地图画面,菜单画面这类游戏中通常称作「画面」的概念、在程序中则称为场景(Scene)。各场景的转换由 SceneManager 模块管理。
首先先来确认脚本 Main 的内容吧。扣掉注释的话 Main 的内容只有一行。
rgss_main { SceneManager.run }
实际上在内建的脚本中,与模块和类的定义无关的只有这个部分。某种程度上可以把这当成脚本真正开始执行的地方。
rgss_main是在 RGSS3 新增的内建函数。这个函数基本上只会执行 { } 括住的部分一遍,不过如果在过程中按下 F12 重置时,该函数会从头开始重新处理。如果无视重置处理,在这行就只会调用 SceneManager 模块的 run 方法。
尽管 SceneManager 模块一直在脚本列表的最上方,但是我们到目前完全没有谈到相关的内容。SceneManager 即是管理场景切换的模块。
首先、先来看看刚刚确认刚才在一开始调用出来的 run 方法。
def self.run DataManager.init Audio.setup_midi if use_midi? @scene = first_scene_class.new @scene.main while @scene end
内容只有四行,我们就一行一行看吧。
DataManager.init
这里调用了 DataManager 模块的 init 方法数据库的读取和游戏对象的初始化就是在这里面进行的。
Audio.setup_midi if use_midi?
数据库的[系统]标签页里面的[启动时初始化 MIDI]的选项如果打了勾,就会进行 MIDI 的初始化。
@scene = first_scene_class.new
这句调用了同样是 SceneManager 模块的 first_scene_class 方法,生成了当做返回的类的实例,并将其代入实例变量 @scene 中。相关内容会在下一节详细解释。
@scene.main while @scene
这里所使用的 while 是修饰符的形式。和 if 或 unless 同样,while 也有这样的用法。 如果采用基础篇学到的循环的语法再写一遍就会变成这个样子。
while @scene @scene.main end
以内容来看,只要实例变量 @scene 不为 nil ,就会持续调用 @scene 的 main 方法。虽然看起来或许很像无限循环,但它的构造是在 main 方法的内部链接到 SceneManager 里面,@scene 所指向的对象是由外部变更,因此不成问题。
再回到第三行。
@scene = first_scene_class.new
我们来看看这里调用的 first_scene_class 方法定义的内容吧。
def self.first_scene_class $BTEST ? Scene_Battle : Scene_Title end? 加上 : 这样的符号是运算符形式的分支条件。如果 $BTEST 变量的值为真则返回 Scene_Battle 为假则返回 Scene_Title 。所谓的 Scene_Battle 或 Scene_Title 是类的名称,在 Ruby 里面可以像这样把类当成方法的返回值。
全局变量 $BTEST 是由 RGSS 自动设置的变量,表示是否开启了战斗测试。也就是说如果开启了战斗测试,那么游戏的开始画面就会是战斗画面,如果没开启那就会是标题画面。
SceneManager 调用出 main 方法是在场景域的最上方的 Scene_Base 类所定义的。来确认看看吧。
def main start post_start update until scene_changing? pre_terminate terminate end
这里依次调用了以下五个方法:
方法 | 内容 |
---|---|
start | 开始处理 |
post_start | 开始后处理 |
update | 更新帧 |
pre_terminate | 结束前处理 |
terminate | 结束处理 |
开始处理和开始后处理、结束处理和结束前处理的主要差别在于,该画面的图形是否已经实际显示出来。由于通过子类重新定义来新增一些处理比较好控制这些时间点,所以又像下方这样细分:
update until scene_changing?
位于正中间的这行,表示的是在场景切换(画面切换))之前的这段时间,会持续调用 update 方法。在各场景中如果有需要每一帧都处理的话,可以重新定义这个 update 方法。
下表为各场景类对应的画面。类的名字与脚本页的名称是一一对应的。
类 | 内容 | 父类 |
---|---|---|
Scene_Title | 标题画面 | Scene_Base |
Scene_Map | 地图画面 | Scene_Base |
Scene_MenuBase | 菜单画面系的基本处理 | Scene_Base |
Scene_Menu | 菜单画面 | Scene_MenuBase |
Scene_ItemBase | 物品画面和技能画面的共通处理 | Scene_MenuBase |
Scene_Item | 物品画面 | Scene_ItemBase |
Scene_Skill | 技能画面 | Scene_ItemBase |
Scene_Equip | 装备画面 | Scene_MenuBase |
Scene_Status | 状态画面 | Scene_MenuBase |
Scene_File | 存档画面和读取画面的共通处理 | Scene_MenuBase |
Scene_Save | 存档画面 | Scene_File |
Scene_Load | 读取画面 | Scene_File |
Scene_End | 游戏结束画面 | Scene_MenuBase |
Scene_Shop | 商店画面 | Scene_MenuBase |
Scene_Name | 输入名字画面 | Scene_MenuBase |
Scene_Debug | 调试画面 | Scene_MenuBase |
Scene_Battle | 战斗画面 | Scene_Base |
Scene_Gameover | 游戏结束画面 | Scene_Base |
负责菜单画面类的基本处理的 Scene_MenuBase 类被许多别的类所继承。在这个类中,包含了把地图画面模糊化后的图像当做背景显示的处理。
游戏中的场景切换的方法有 goto、call、return 三种。
像是游戏结束这种切换过去就不会再回原场景的画面,会使用最简单的 goto。
SceneManager.goto(Scene_Gameover)
call 则是像菜单画面这种,需要回到调用呼出菜单的原场景时使用的。
SceneManager.call(Scene_Menu)
return 则是,当我们要从用 call 调用呼出的场景回到原场景时会使用的。
SceneManager.return
实际上场景切换如何使用。在接下来的实践篇中会解说。
补充、直到 VX 之前的版本,是通过将场景对象赋值到 $scene 这个全局变量的形式进行场景切换,不过随着导入了更完整的 SceneManager 模块后,该方法就被废弃了。以前使用到现在的使用者请注意这一点。