马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 blackpineapple 于 2022-7-5 14:24 编辑
效果演示
代码:
本教程主要讲如何实现通讯录部分,短信演出部分请看另外一篇。通讯录部分是由通讯录类,负责控制主角的联系人。联系人类,储存联系人相关的信息。通讯录的现实部分,这三部分构成的。本教程的最后附加了再script里需要添加的代码。
通讯录类:
通讯录类主要负责增加/删除联系人,以及获得该联系人当前的信息脚本的label名字。
[RenPy] 纯文本查看 复制代码
## Contact类:这个类负责通讯录的后端逻辑。
init -1 python:
class Contact(object):
def __init__(self, main_character, npcs=[]):
## 主角的名字,因为主角在发短信的屏幕和别人的显示不同,这里记录下主角的名字。
self.mc = main_character
## 用字典储存联系人,键是人名字的字符串,值是NPC对象。
self.contacts = dict()
## 是否在nvl mode启用这个phone的屏幕。
## 如果不在游戏里使用nvl,可以直接改自带的nvl screen
self.enable_phone_mode = True
## 初始化主角的通讯录,添加NPC到通讯录中。
for npc in npcs:
self.add(npc)
## 添加一个联系人到通讯录。参数是一个NPC对象。
def add(self, npc):
self.contacts[npc.name] = npc
## 从通讯录删掉一个联系人。参数是一个字符串,npc的名字。
def remove(self, name):
del self.contacts[name]
## 通过NPC名字的字符串获得NPC对应的头像,用于聊天对话显示。
def get_icon(self, name):
if name == self.mc:
return self.mc.img
return self.contacts[name].img
## 获得和联系人短信脚本的label的名字,是一个字符串。
def get_message(self, name):
return self.contacts[name].get_message()
联系人类
主要用来储存联系人的相关信息。
[RenPy] 纯文本查看 复制代码
init -1 python:
class NPC(object):
def __init__(self, name, bio="", texting_default="texting_default",
friendship=0):
## NPC的名字
self.name = name
## NPC的图标头像,可以修改下面这个去符合你自己的需求。
self.img = name + "_icon.png"
## NPC的签名,在通讯录中显示的一句话。
self.bio = bio
## 主角和NPC的友好度。通讯录会按照友好度排序显示。
self.friendship = friendship
## 点击联系人,有3种信息显示。
## 主角给联系人发信息的演出,联系人并不会提示有新信息。
## 主角收到了联系人发的信息,会有信息提示。
## 缺省信息演出,如果系统中并没有前两种信息,但是玩家点了联系人,就会演出一个
## 缺省的信息对话。
self.texting_send = []
self.texting_recieved = []
self.texting_default = texting_default
## 判断是否有新信息。
def has_new_message(self):
return len(self.texting_send) > 0
## 联系人列表的排列顺序,如果有新消息就排列在前面,除此之外按照友好度排列。
## 假设没有友好度会达到10000
def sort_score(self):
score = 10000 if self.has_new_message() else 0
return self.friendship + score
## 获得和联系人的信息的label的名字。
def get_message(self):
if self.texting_send:
return self.texting_send[0]
if self.texting_recieved:
return self.texting_recieved[0]
return self.texting_default
## 删掉已经演出过的短信剧本。
def pop_message(self):
if self.texting_send:
self.texting_send.pop(0)
if self.texting_recieved:
self.texting_recieved.pop(0)
主界面代码:
包含一个手机按钮,可以呼出通讯录界面。
[RenPy] 纯文本查看 复制代码
screen main:
zorder 1
modal True
hbox:
add "naruto.png"
imagebutton:
ycenter 0.1
xalign 0.7
idle "phone.png"
hover im.MatrixColor("phone.png", im.matrix.brightness(0.1))
focus_mask True
action [Hide('main'), Jump('contact')]
通讯录界面
[RenPy] 纯文本查看 复制代码
screen contact:
zorder 1
modal True
default contacts = contact.contacts.values()
## 按照友好度排列联系人。
python:
contacts = sorted(contacts, key=lambda x: x.sort_score(), reverse=True)
button:
xysize (1280, 720)
action [Hide('contact'), Return()]
frame at phone_appear:
background "phone_background.png"
foreground "phone_foreground.png"
xalign 0.3
ysize 600
xsize 350
vpgrid:
yoffset 120
xalign 0.5
cols 1
draggable True
mousewheel True
ysize 500
for idx, npc in enumerate(contacts):
button:
action [Hide('contact'), Jump(
contact.get_message(npc.name))]
hover_sound "audio/click.mp3"
vbox:
spacing 10
hbox:
spacing 10
add npc.img
vbox:
hbox:
spacing 10
text npc.name:
color "#f59a61"
hover_color "#61aef5"
size 15
if npc.has_new_message():
text "(New)":
color "#f41161"
hover_color "#eb6d99"
size 15
text npc.bio:
color "#000"
size 15
if idx != len(contacts) - 1:
add Solid("#f59a61", xsize=300, ysize=3)
transform phone_appear:
xcenter 0.3
yalign 0.5
on show:
yoffset 720
easein_back 1.0 yoffset -50
script
[RenPy] 纯文本查看 复制代码
## 很重要,没有下面的4行,NVL会没有办法清理掉。
init python:
config.empty_window = nvl_show_core
config.window_hide_transition = dissolve
config.window_show_transition = dissolve
define n_nvl = Character("naruto", kind=nvl,callback=Phone_SendSound)
define e_nvl = Character("iruka", kind=nvl, callback=Phone_ReceiveSound)
default NARUTO = NPC('naruto')
default IRUKA = NPC('iruka', "今天也要好好学习。", friendship=5)
default NAVI = NPC('navi', "通讯记录刷新中", friendship=1)
default KAKASHI = NPC('kakashi', "周刊征稿,请联系我。", friendship=2)
default C_1 = NPC('c1', "自我介绍")
default C_2 = NPC('c2', "关于我的关键字")
default C_3 = NPC('c3', "随便写写")
default C_4 = NPC('c4', "这个是我的网站")
default C_5 = NPC('c5', "小猫咪能有什么坏心眼")
## 初始化通讯录
default contact = Contact(NARUTO, [IRUKA, NAVI, KAKASHI, C_1, C_2, C_3, C_4, C_5])
#Skip the main menu 跳过主菜单
label main_menu:
return
label start:
## 增加一条IRUKA的信息,label的名字是script_1
python:
IRUKA.texting_send.append('script_1')
scene bg with dissolve
pause 1.0
jump main
return
## 有手机按钮的界面
label main:
show screen main
pause
jump main
return
## 通讯录界面
label contact:
show screen contact
pause
jump contact
return
label script_1:
## 因为运行到了这个地方,删掉这条信息。否则会重复演出此条信息。
$ IRUKA.pop_message()
n_nvl "这是一个关于手机短信的演示视频。"
n_nvl "实在不知道写点什么文案比较好。"
e_nvl "哦"
n_nvl "下面测试一个图片发送的效果。"
e_nvl "{image=picture.png}"
n_nvl "而且还可以发表情。"
e_nvl "{image=emoji/slightly_happy.png}"
n_nvl "也可以发一段非常长的发言。不如这一条。但是我真的不会写小作文,不如就复制粘贴达到一百字好了,但是这样真的非常敷衍诶。或者可以去找一个小作文生成器来帮忙,能不能找个文案帮帮忙?"
e_nvl "请不要在意文案的具体内容。"
## NVl的选择枝的写法。
menu(nvl=True):
"这是选项1":
n_nvl "选择了选项1"
e_nvl "是的"
"这是选项2":
n_nvl "选择了选项2"
e_nvl "是的"
"这是选项3":
n_nvl "选择了选项3"
e_nvl "是的"
n_nvl "这是之后一行了。"
## 清理掉nvl的演出。
nvl clear
window hide
jump contact
return
短信演出
本代码是二改自renpy官方论坛lemmasoft的帖子
https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=62837%20
手机短信的演出其实就是基于NVL 模式的改写。NVL model的详细教程,请参考官方文档(https://doc.renpy.cn/zh-CN/nvl_mode.html)。
打开你自己的工程或者新建一个工程,找到screens 这个文件,搜索nvl会找到下面的代码。
[RenPy] 纯文本查看 复制代码
## NVL 模式屏幕 ####################################################################
##
## 此屏幕用于 NVL 模式的对话和菜单。
##
## [url=https://www.renpy.org/doc/html/screen_special.html#nvl]https://www.renpy.org/doc/html/screen_special.html#nvl[/url]
screen nvl(dialogue, items=None):
window:
style "nvl_window"
has vbox:
spacing gui.nvl_spacing
## 在“vpgrid”或“vbox”中显示对话框。
if gui.nvl_height:
vpgrid:
cols 1
yinitial 1.0
use nvl_dialogue(dialogue)
else:
use nvl_dialogue(dialogue)
## 如果给定,则显示“menu”。 如果“config.narrator_menu”设置为“True”,
## 则“menu”可能显示不正确,如前述。
for i in items:
textbutton i.caption:
action i.action
style "nvl_button"
add SideImage() xalign 0.0 yalign 1.0
screen nvl_dialogue(dialogue):
for d in dialogue:
window:
id d.window_id
fixed:
yfit gui.nvl_height is None
if d.who is not None:
text d.who:
id d.who_id
text d.what:
id d.what_id
这个代码就是Ren'Py 自带的NVL模式的实现,如果想做什么类似于NVL的效果,就可以基于这个屏幕去修改。请对比这个界面的写法和修改后的写法。
对于我们这个聊天的显示要做如下修改
[RenPy] 纯文本查看 复制代码
screen nvl(dialogue, items=None):
if contact.enable_phone_mode:
use phone_dialogue(dialogue, items)
增加一个判断,如果是手机模式,就用手机的界面。contact是教程1中通讯录的对象。
手机短信的主要屏幕和效果
[RenPy] 纯文本查看 复制代码
## 用回调函数来增加收/发信息的音效。
init -1 python:
def Phone_ReceiveSound(event, interact=True, **kwargs):
if event == "show_done":
renpy.sound.play("audio/ReceiveText.ogg")
def Phone_SendSound(event, interact=True, **kwargs):
if event == "show_done":
renpy.sound.play("audio/SendText.ogg")
## 消息出现的动态效果。因为可能是收也可能是发
## 用direction来决定出现的方向。
transform message_appear(direction):
alpha 0.0
xoffset 50 * direction
parallel:
ease 0.5 alpha 1.0
parallel:
easein_back 0.5 xoffset 0
screen phone_dialogue(dialogue, items=None):
frame:
background "phone_background.png"
foreground "phone_foreground.png"
ysize 600
xsize 350
xcenter 0.3
yalign 0.5
viewport:
yfill True
xfill True
ysize 550
yoffset 80
draggable True
mousewheel True
yinitial 1.0
vbox:
spacing 10
xfill True
null height 20
use nvl_phonetext(dialogue, items)
null height 20
## 负责显示选项的部分
for i in items:
button:
action i.action
xalign 0.15
xysize (265,52)
background "choice_bg.png"
hover_background "choice_bg_hover.png"
hover_sound "audio/click.mp3"
text i.caption:
align (0.5,0.5)
text_align 0.5
size 15
color "#000"
screen nvl_phonetext(dialogue, items=None):
style_prefix None
## dialogue 是对话,items是负责选项的部分。
for d in dialogue:
## 如果是旁白,这样显示。
if d.who == None:
text d.what:
xpos -230
xsize 250
text_align 0.5
color "#000"
italic True
size 15
slow_cps False
id d.what_id
if d.current:
at transform:
alpha 0.0
yoffset -50
parallel:
ease 0.5 alpha 1.0
easein_back 0.5 yoffset 0
else:
hbox:
xpos 18
spacing 10
## 判断现在说话的人是不是主角,因为主角的显示方式和其他人不同。
## 比如主角头像的方向和其他说话人不同。
if d.who == contact.mc.name:
$ message_frame = "send_base.png"
$ direction = 1
## 因为主角是先显示对话框再显示头像,所以这里用下面这个参数。
box_reverse True
else:
$ message_frame = "text_base.png"
$ direction = -1
$ message_icon = d.who + "_icon.png"
## 有选择枝的时候,items不为空,但是current为True,会重新加载
## 最后一句对话。为了避免重新加载,需要判断是否有选择枝。
add message_icon:
if d.current and not items:
at transform:
zoom 0.0
ease_back 0.5 zoom 1.0
frame:
yalign 1.0
padding (10,10)
background Frame(message_frame, 12,12,12,12)
xsize 210
if d.current and not items:
at message_appear(direction)
text d.what:
pos (0,0)
xsize 190
size 15
slow_cps False
color "#000"
id d.what_id
|