怎么优雅的研究 RGSS3 (二) 为游戏结束画面添加简单的选项
上一期研究了场景中显示窗口的基本原理,本期就动手亲自写一写简单的窗口。
向 Gameover 场景里添加自制的窗口是个不错的选择, 因为 Scene_Gameover 是少数不含窗口的场景之一。
在 RGSS3 的默认脚本中,游戏因为某种原因(战斗失败、HP变为0、强制游戏结束)结束后,会直接跳到 Gameover 场景。
而在 Gameover 场景中按下空格键就会回到游戏标题画面。
这不科学嘛,虽然在标题画面中也可以读取游戏进度,但是显然在游戏结束画面直接读取进度更为方便。
所以我们现在就为游戏结束画面添加一个窗口,给出三个选项:回到标题画面、载入进度、关闭游戏。
虽然在上一期中已经了解了窗口类的工作原理,但是具体细节仍然不太清晰,突然要我们自己写一个还是不知道该从何入手。
#encoding:utf-8 #============================================================================== # ■ Window_OverLoad #------------------------------------------------------------------------------ # 游戏结束后可以读档的窗口。 #============================================================================== class Window_OverLoad < Window_Command先把注释写好肯定错不了,我们要写的结束后读档的窗口显然是 Window_Command 的子类。
我们的窗口类有三个选项而且还能读档,这和标题画面中选择“开始游戏/继续游戏”的窗口的功能非常接近。
所以直接把 Window_TitleCommand 的代码复制一份粘贴到 Window_OverLoad 好了。不会有问题的!
但是在标题画面的窗口中,第一个选项是开始新游戏,在 Window_OverLoad 中应该改成回到标题画面。
于是我们把生成指令列表的方法 make_command_list 中的第一句话 add_command(Vocab::new_game, :new_game) 改为 add_command(Vocab::to_title, :to_title) 。
new_game 与 to_title 都是在 Vocab 模块中定义的一些表示游戏用语的字符串常量。
#-------------------------------------------------------------------------- # ● 初始化对象 #-------------------------------------------------------------------------- def initialize super(0, 0) update_placement select_symbol(:continue) if continue_enabled self.openness = 0 open end #-------------------------------------------------------------------------- # ● 获取窗口的宽度 #-------------------------------------------------------------------------- def window_width return 160 end #-------------------------------------------------------------------------- # ● 更新窗口的位置 #-------------------------------------------------------------------------- def update_placement self.x = (Graphics.width - width) / 2 self.y = (Graphics.height * 1.6 - height) / 2 end #-------------------------------------------------------------------------- # ● 生成指令列表 #-------------------------------------------------------------------------- def make_command_list add_command(Vocab::to_title, :to_title) add_command(Vocab::continue, :continue, continue_enabled) add_command(Vocab::shutdown, :shutdown) end #-------------------------------------------------------------------------- # ● 获取“继续游戏”选项是否有效 #-------------------------------------------------------------------------- def continue_enabled DataManager.save_file_exists? end end在窗口初始化时先计算了窗口所在的位置,将窗口设定在游戏画面*偏下的位置。
接下来判断了一下是否有存档,如果没有存档记录的话就禁用“继续游戏”选项。
self.openness = 0 将窗口设置为了没打开状态,然后调用 open 展示了一个窗口打开动画。
接下来向 Scene_Gameover 类中添加 create_command_window 方法的定义,并在 start 方法的最后调用它。
#-------------------------------------------------------------------------- # ● 生成指令窗口 #-------------------------------------------------------------------------- def create_command_window @command_window = Window_OverLoad.new @command_window.set_handler(:to_title, method(:command_to_title)) @command_window.set_handler(:continue, method(:command_continue)) @command_window.set_handler(:shutdown, method(:command_shutdown)) end在里将游戏结束场景中的三个方法 command_to_title、command_continue、command_shutdown 与 Window_OverLoad 的实例 @command_window 关联在了一起。
虽然现在我们还没有添加这三个方法的具体内容。
def command_to_title end def command_continue end def command_shutdown end
现在进入游戏的结束画面,发现多了一个跟游戏标题画面里的窗口很像的窗口,里面有三个选项。
现在不管在什么选项上按下确定键都只会回到标题画面。
为什么会这样呢?
#-------------------------------------------------------------------------- # ● 更新画面 #-------------------------------------------------------------------------- def update super goto_title if Input.trigger?(:C) end发现 Scene_Gameover 的 update 方法中有这样一句话 goto_title if Input.trigger?(:C) 。
goto_title 也是 Scene_Gameover 中的方法。调用它切换到标题画面。
这样一句话就是说在更新场景时,如果侦测到按下了确定键,就调用 goto_title 回到标题画面。
#-------------------------------------------------------------------------- # ● 切换到标题画面 #-------------------------------------------------------------------------- def goto_title fadeout_all SceneManager.goto(Scene_Title) endSceneManager 是场景切换的管理器,调用其 goto 方法可以直接切换某个场景(无过渡)。
现在我们将其删去。然后向 command_to_title 方法中添加 goto_title 的调用。
类似的,向 command_continue 方法中添加一句 SceneManager.goto(Scene_Load) ,向 command_shutdown 方法中添加一句 SceneManager.exit。
def command_to_title goto_title end def command_continue SceneManager.goto(Scene_Load) end def command_shutdown SceneManager.exit end这下三个选项的基本功能就做好了,不过还是有一些瑕疵在里面。
当我们选择继续游戏选项后,进入载入游戏画面,然后我们按下取消键,游戏就自己关掉了- -
这是因为我们是用 goto 方法进入的新场景,SceneManager 切换场景的方法有两个:
#-------------------------------------------------------------------------- # ● 直接切换某个场景(无过渡) #-------------------------------------------------------------------------- def self.goto(scene_class) @scene = scene_class.new end #-------------------------------------------------------------------------- # ● 切换 #-------------------------------------------------------------------------- def self.call(scene_class) @stack.push(@scene) @scene = scene_class.new endgoto 方法直接切换场景,而 call 方法将现在的场景压入栈中,然后再切换场景,这是为回到上一个场景的 return 方法做准备。
#-------------------------------------------------------------------------- # ● 返回到上一个场景 #-------------------------------------------------------------------------- def self.return @scene = @stack.pop end当在载入游戏的场景中按下取消键时,Scene_Load 的父类 Scene_File 更新画面时的 update_savefile_selection 方法检测到了取消键,于是执行 on_savefile_cancel 方法:
#-------------------------------------------------------------------------- # ● 更新画面 #-------------------------------------------------------------------------- def update super @savefile_windows.each {|window| window.update } update_savefile_selection end
#-------------------------------------------------------------------------- # ● 更新存档文件选择 #-------------------------------------------------------------------------- def update_savefile_selection return on_savefile_ok if Input.trigger?(:C) return on_savefile_cancel if Input.trigger?(:B) update_cursor end
#-------------------------------------------------------------------------- # ● 存档文件“取消” #-------------------------------------------------------------------------- def on_savefile_cancel Sound.play_cancel return_scene end
return_scene 是游戏中所有 Scene 类(场景类)的父类 Scene_Base 中的方法,它调用了 SceneManager 的 return 方法。
#-------------------------------------------------------------------------- # ● 返回前一个场景 #-------------------------------------------------------------------------- def return_scene SceneManager.return end现在我们知道问题出在哪了,将 command_continue 中的 SceneManager.goto(Scene_Load) 改为 SceneManager.call(Scene_Load)。
这样在载入游戏场景中按下取消键就会返回游戏结束场景。
嗯,这样就好多了,可是还是有些别扭,选中选项时总是感觉有些僵硬。
与标题画面做了对比后发现,我们的窗口少了关闭时的动画,难怪感觉有些不对。
#-------------------------------------------------------------------------- # ● 关闭指令窗口 #-------------------------------------------------------------------------- def close_command_window @command_window.close update until @command_window.close? end没错,正是 Scene_Title 中的 close_command_window 方法使标题画面中的窗口有了关闭动画。
在 Scene_Title 中的每个选项方法,在执行其功能之前,都会先调用 close_command_window 显示一个关闭窗口的动画。
我们也将 close_command_window 方法的定义和调用添加到 Scene_Gameover 中。
def command_to_title close_command_window goto_title end def command_continue close_command_window SceneManager.call(Scene_Load) end def command_shutdown close_command_window SceneManager.exit end这样我们的窗口也变得酷炫了起来。
虽然很想说这样就完美了,不过呢,还是漏了一点东西。
在 Scene_Base 中有一个 fadeout_all 方法,淡出各种音效以及图像。
#-------------------------------------------------------------------------- # ● 淡出各种音效以及图像 #-------------------------------------------------------------------------- def fadeout_all(time = 1000) RPG::BGM.fade(time) RPG::BGS.fade(time) RPG::ME.fade(time) Graphics.fadeout(time * Graphics.frame_rate / 1000) RPG::BGM.stop RPG::BGS.stop RPG::ME.stop end调用这个方法可以让当前的所有声音与画面在1秒内渐渐消失。
在离开 Scene_Gameover 场景的时候调用一下这个方法可以让场景的切换不那么突兀。
def command_to_title close_command_window fadeout_all goto_title end def command_continue close_command_window fadeout_all SceneManager.call(Scene_Load) end def command_shutdown close_command_window fadeout_all SceneManager.exit end
这样我们的窗口终于完美啦,赶紧 Gameover 体验一下吧。