找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8696|回复: 2

[转载] Ren'Py引擎从入门到放弃(15)——GUI定制化之主菜单

[复制链接]
发表于 2021-2-6 23:37:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
Ren'Py引擎从入门到放弃(15)——GUI定制化之主菜单

世上无难事,只要肯放弃。

这是入门介绍的第十五篇,主要内容是GUI定制化,这次内容是稍微复杂一点的主菜单(Main Menu)。

由于cexo同学的原案中没有主菜单部分,所以这次的方案是元素是我自己弄的(丑了点,凑合看)……

第一个问题:上次说的是定制“导航界面”,怎么改成主菜单了?

答:导航界面,也就是navigation screen。项目默认生成的主菜单(main_menu)和游戏内菜单(game_menu)中使用了 use 语句包含了导航界面,估计这样做是为了复用界面资源。cexo的设计原案中游戏内菜单的功能做了大幅精简,只有Return(返回游戏)、Title(回到游戏标题)和Exit(退出游戏),所以抛弃原本的导航界面重新做一个(大概)比较方便。此外,Ren'Py的界面复用常用 use/transclude 组合实现,这种套娃设计对入门不太友好,等后续深入到“创作者定义的界面语言语句”部分再用比较合适。

因此,这次我们定制化主菜单就抛弃导航界面,直接从 main_menu 下手。

方案目标大体是这样的(图标没有对齐,字体丑等问题后续会处理):
方案目标大体是这样的.jpg

第二个问题:需要使用导入和修改哪些资源?

:用到的图片资源只有两项:背景图片和按钮图片。

按钮图片建议不带文字,用脚本“写”上去。这样做的好处是方便后续修改,以及更好的支持多语言版本。

主菜单界面默认在screen.rpy文件中,自定义的main_menu也还是放在这个文件中吧。


第三个问题:怎么搞?

答:是时候展示一下真正(其实也没什么高级)的技术了。

先查一下原来默认的main_menu定义,看看有什么可以直接复制/粘贴过来的……
[RenPy] 纯文本查看 复制代码
screen main_menu():

    ## 此语句可确保替换掉任何其他菜单界面。
    tag menu

    style_prefix "main_menu"

    add gui.main_menu_background

    ## 此空框可使标题菜单变暗。
    frame:
        pass

    ## “use”语句将其他的界面包含进此界面。标题界面的实际内容在导航界面中。
    use navigation

    if gui.show_name:

        vbox:
            text "[config.name!t]":
                style "main_menu_title"

            text "[config.version]":
                style "main_menu_version"

第一个tag是必需的,用来清界面,防止各种菜单重叠。

样式相关内容可以去掉。

add语句定义了背景图片,改成自己导入的背景图片或者把自己导入的图替换原来的。(gui.main_menu_background定义在 gui.rpy 文件中,对应 gui/main_menu.png)

frame这个灰色半透明的框……暂时去掉,后续(可能)会用另一个更好看点的可视组件代替。

use语句是该界面的核心,其定义了一堆按钮和对应的行为(action)。此次定制化会直接在 main_menu 中定义按钮,忽略navigation界面的内容。

最后的if语句是展示项目名称和版本号的,与按钮的功能无关,请根据需要自己决定是否保留。

最初的框架就是这样:
[RenPy] 纯文本查看 复制代码
screen main_menu():

    tag menu

    add gui.main_menu_background

运行一下可以发现,除了背景图之外啥都没有了(当然,也没有报错)……

接着开始添加按钮。主菜单总共6个按钮:
[RenPy] 纯文本查看 复制代码
    vbox:
        xalign 1.0
        yalign 0.5
        
        imagebutton:
            idle "gui/button/main_menu_button.png"
            action Start()
        imagebutton:
            idle "gui/button/main_menu_button.png"
            action ShowMenu("load")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            action ShowMenu("preferences")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            action ShowMenu("about")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            action ShowMenu("help")
        if renpy.variant("pc"):

            ## “退出”按钮在 iOS 上被禁止设置,在安卓和网页上也不是必需的。
            imagebutton:
                idle "gui/button/main_menu_button.png"
                action Quit(confirm=not main_menu)

此时按钮上没有文字说明,需要自己定义。为了避开原来定义的样式与我们自定义的发生冲突,最好重新写样式,并应用到文本上,封装成可视组件:
[RenPy] 纯文本查看 复制代码
# 文字本体样式
style main_menu_button_text_fill:
    align (0.5, 0.5)
    size 30
    # font ""
    color "#fedaaa"
    outlines [(1, "#fab5a4", 0, 0)]

# 文字投影样式
style main_menu_button_text_shadow:
    align (0.5, 0.5)
    size 30
    # font ""
    color "#c0c0c0"
    outlines [(2, "#c0c0c0", 3, 3)]

image new_game_button_text:
    contains:
        Text("开坑", style = "main_menu_button_text_shadow")
    contains:
        Text("开坑", style = "main_menu_button_text_fill")
    
image load_game_button_text:
    contains:
        Text("填坑", style = "main_menu_button_text_shadow")
    contains:
        Text("填坑", style = "main_menu_button_text_fill")

image preference_button_text:
    contains:
        Text("设置", style = "main_menu_button_text_shadow")
    contains:
        Text("设置", style = "main_menu_button_text_fill")

image about_button_text:
    contains:
        Text("关于", style = "main_menu_button_text_shadow")
    contains:
        Text("关于", style = "main_menu_button_text_fill")

image help_button_text:
    contains:
        Text("帮助", style = "main_menu_button_text_shadow")
    contains:
        Text("帮助", style = "main_menu_button_text_fill")

image quit_button_text:
    contains:
        Text("放弃", style = "main_menu_button_text_shadow")
    contains:
        Text("放弃", style = "main_menu_button_text_fill")

这样就可以把文本加到按钮上了:
[RenPy] 纯文本查看 复制代码
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "new_game_button_text"
            action Start()
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "load_game_button_text"
            action ShowMenu("load")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "preference_button_text"
            action ShowMenu("preferences")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "about_button_text"
            action ShowMenu("about")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "help_button_text"
            action ShowMenu("help")
        if renpy.variant("pc"):

            ## “退出”按钮在 iOS 上被禁止设置,在安卓和网页上也不是必需的。
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "quit_button_text"
                action Quit(confirm=not main_menu)

初版效果如图(后来发现投影的方向反了,应该把偏移值设置为负数):

偏移值设置为负数

偏移值设置为负数


看起来好像比设计原案好,把书叠在一起反而好看一些……(而且省去了给图片做投影的步骤)

接下来做一个菜单按钮的进入动画,我们希望刚开始显示菜单时画面上没有按钮,所有按钮依次从画面右侧平移出来。实现的核心是 start 事件响应,做一个transform即可:
[RenPy] 纯文本查看 复制代码
# 入参delay用作不同按钮的动画间隔时间,缓动函数选用了结尾平滑的quint
transform main_menu_button_in(delay):
    # 图片宽度273,所以默认偏移量稍微多两个像素
    xoffset 275
    on start:
        time delay
        easein_quint 2.0 xoffset 0

应用到所有按钮上,时间间隔为0.3秒:
[RenPy] 纯文本查看 复制代码
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "new_game_button_text"
            at main_menu_button_in(1.8)
            action Start()
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "load_game_button_text"
            at main_menu_button_in(1.5)
            action ShowMenu("load")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "preference_button_text"
            at main_menu_button_in(1.2)
            action ShowMenu("preferences")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "about_button_text"
            at main_menu_button_in(0.9)
            action ShowMenu("about")
        imagebutton:
            idle "gui/button/main_menu_button.png"
            foreground "help_button_text"
            at main_menu_button_in(0.6)
            action ShowMenu("help")
        if renpy.variant("pc"):

            ## “退出”按钮在 iOS 上被禁止设置,在安卓和网页上也不是必需的。
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "quit_button_text"
                at main_menu_button_in(0.3)
                action Quit(confirm=not main_menu)

主菜单按钮进入动画1
主菜单按钮进入动画1.gif

看着还行……如果要对文字做动画,也可以放在这个transform中,这里我就偷懒一下不写了……

接着是给按钮添加hover和idle事件的动画,也就是上一篇内容的重点。我们希望鼠标移动到对应按钮上时,书的图片可以向左移动一些距离,类似这本书要被抽出来的样子;而鼠标离开后,书的图片向右移动到原位。此时会出现一个新问题:如果直接添加hover和idle的事件处理,由于idle的优先级比start高,进入主菜单就会中断start事件处理器并执行idle事件处理。显示效果就是,所有按钮一开始就一齐移动到最终位置。解决方案也简单,所有imagebutton上再套个父组件,这里选取frame组件(frame没有hover和idle事件处理器)。frame组件负责处理画面初始的移动动画,imagebutton组件负责鼠标事件的动画,新增一个应用到 imagebutton 的 transform:
[RenPy] 纯文本查看 复制代码
transform main_menu_button_hover:
    on hover:
        ease 0.5 xoffset -35
    on idle:
        ease 0.5 xoffset 0

修改后的布局:
[RenPy] 纯文本查看 复制代码
        frame:
            # 无背景
            background None
            # 不扩展
            padding (0, 0, 0, 0)
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "new_game_button_text"
                at main_menu_button_hover
                action Start()
            at main_menu_button_in(1.8)

        frame:
            background None
            padding (0, 0, 0, 0)
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "load_game_button_text"
                at main_menu_button_hover
                action ShowMenu("load")
            at main_menu_button_in(1.5)
            
        frame:
            background None
            padding (0, 0, 0, 0)
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "preference_button_text"
                at main_menu_button_hover
                action ShowMenu("preferences")
            at main_menu_button_in(1.2)

        frame:
            background None
            padding (0, 0, 0, 0)
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "about_button_text"
                at main_menu_button_hover
                action ShowMenu("about")
            at main_menu_button_in(0.9)

        frame:
            background None
            padding (0, 0, 0, 0)
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "help_button_text"
                at main_menu_button_hover
                action ShowMenu("help")
            at main_menu_button_in(0.6)
        if renpy.variant("pc"):

            ## “退出”按钮在 iOS 上被禁止设置,在安卓和网页上也不是必需的。
            frame:
                background None
                padding (0, 0, 0, 0)
                imagebutton:
                    idle "gui/button/main_menu_button.png"
                    foreground "quit_button_text"
                    at main_menu_button_hover
                    action Quit(confirm=not main_menu)
                at main_menu_button_in(0.3)

此处代码有一些冗余,把frame的样式单独提取出来能省几行,我这里就不做了……

最后再注入一点灵魂(音效),模仿书被抽出来时候的摩擦声。在所有imagebutton里添加hover_sound,样例只写一个按钮:
[RenPy] 纯文本查看 复制代码
        frame:
            # 无背景
            background None
            # 不扩展
            padding (0, 0, 0, 0)
            imagebutton:
                idle "gui/button/main_menu_button.png"
                foreground "new_game_button_text"
                at main_menu_button_hover
                # 按钮获取焦点播放音效
                hover_sound "audio/book_selected.wav"
                action Start()
            at main_menu_button_in(1.8)
最终效果:
主菜单最终效果.gif

多余的问题:好像文字效果跟设计案有差别啊?

答:支线(2)那篇文章里有提到过,文字叠加图片的实现方法,链接如下:

被诅咒的章鱼:Ren'Py引擎从入门到放弃(支线2·续)——只有文字也要搞NV

因为这个不是本篇的重点,就略过了……

预告部分:下一篇会再谈一下Live2D的情况,会很短……






发表于 2021-2-9 21:30:39 | 显示全部楼层
按照步骤做的时候遇到了问题,因为我之前自己写过一个画廊系统,就把画廊系统也做了进去,但是发现做完之后按钮全部到了屏幕的最左侧,通过修改padding值,将前面几个按钮放在了最右侧,但是最后一个退出按钮不管修改不过来,这是怎么回事呢?
回复 支持 抱歉

使用道具 举报

发表于 2021-2-22 11:08:23 | 显示全部楼层
比企谷士道 发表于 2021-2-9 21:30
按照步骤做的时候遇到了问题,因为我之前自己写过一个画廊系统,就把画廊系统也做了进去,但是发现做完之后 ...

可能有样式重名或者继承关系有冲突。只能根据代码排查……
回复 支持 抱歉

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|RenPy中文空间 ( 苏ICP备17067825号|苏公网安备 32092302000068号 )

GMT+8, 2024-3-28 22:28 , Processed in 0.050540 second(s), 13 queries , File On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表