加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 eve592370698 于 2013-1-21 21:48 编辑
这是我的师父癫狂侠客说出来的话。如今他正在忙于工作,看到@疯狂异形 给出这么多探索之旅,我也想把我和他一起探索脚本的一些心得体会发给大家。我们决定发布这个脚本探索之旅主要目的是为了让大家通过优化精简自己的脚本,让RMXP的RGSS1吸收VX的RGSS2以及VX ACE的RGSS3里面一些优点,让脚本更容易理解,顺利理清自己的思路,为以后制作脚本力争用最少量简单的代码尽可能实现庞大复杂的功能。
为啥我们上来开始探索Scene这个类呢?虽然这个类位置比较靠后,但是和游戏的运行却最为紧密!而且针对XP来说,也有很多嘈点。想必看脚本的时候,很多类里面上来给出的第一个方法是
def initialize
这个是加载的该方法的初始初始化状态。但是一到Scene里面,却成了
def main
很多Scene里面竟然没有initialize这个方法,这里头不禁有人会不明白了。经过一番探索,其实答案就在Main这个标签中(注意这里头修改过了!)
begin # 准备过渡 # 设置系统默认字体 Font.default_name = (["黑体"]) Graphics.freeze # 生成场景对像 (↓生成游戏开始) $scene = Scene_Start.new # $scene 为有效的情况下调用 main 过程 while $scene != nil $scene.main end # 淡入淡出 Graphics.transition(20) rescue Errno::ENOENT # 补充 Errno::ENOENT 以外错误 # 无法打开文件的情况下、显示信息后结束 filename = $!.message.sub("No such file or directory - ", "") print("找不到文件 #{filename}。 ") end
begin
# 准备过渡
# 设置系统默认字体
Font.default_name = (["黑体"])
Graphics.freeze
# 生成场景对像 (↓生成游戏开始)
$scene = Scene_Start.new
# $scene 为有效的情况下调用 main 过程
while $scene != nil
$scene.main
end
# 淡入淡出
Graphics.transition(20)
rescue Errno::ENOENT
# 补充 Errno::ENOENT 以外错误
# 无法打开文件的情况下、显示信息后结束
filename = $!.message.sub("No such file or directory - ", "")
print("找不到文件 #{filename}。 ")
end
也就是说当您打开这个游戏的时候,首先读取的就是Scene_Start这个类,随后呢,按照执行的先后顺序下一个执行的就是while $scene != nil $scene.main end
while $scene != nil
$scene.main
end
说白了,整个游戏过程无外乎就是Scene这一套类的main这个方法的执行过程。以上的内容,在RMXP帮助文件的场景类里面会有详细的描述,但是下面呢?这帮助文件就有点不够意思了。打开一个Scene类,就举个例子吧,例如RM默认的Scene_Skilldef main # 获取角色 [url=home.php?mod=space&uid=95897]@actor[/url] = $game_party.actors[@actor_index] # 生成帮助窗口、状态窗口、特技窗口 @help_window = Window_Help.new @status_window = Window_SkillStatus.new(@actor) @skill_window = Window_Skill.new(@actor) # 关联帮助窗口 @skill_window.help_window = @help_window # 生成目标窗口 (设置为不可见?不活动) @target_window = Window_Target.new @target_window.visible = false @target_window.active = false # 执行过渡 Graphics.transition # 主循环 loop do # 刷新游戏画面 Graphics.update # 刷新输入信息 Input.update # 刷新画面 update # 如果画面切换的话就中断循环 if $scene != self break end end # 准备过渡 Graphics.freeze # 释放窗口 @help_window.dispose @status_window.dispose @skill_window.dispose @target_window.dispose end
def main
# 获取角色
[url=home.php?mod=space&uid=95897]@actor[/url] = $game_party.actors[@actor_index]
# 生成帮助窗口、状态窗口、特技窗口
@help_window = Window_Help.new
@status_window = Window_SkillStatus.new(@actor)
@skill_window = Window_Skill.new(@actor)
# 关联帮助窗口
@skill_window.help_window = @help_window
# 生成目标窗口 (设置为不可见?不活动)
@target_window = Window_Target.new
@target_window.visible = false
@target_window.active = false
# 执行过渡
Graphics.transition
# 主循环
loop do
# 刷新游戏画面
Graphics.update
# 刷新输入信息
Input.update
# 刷新画面
update
# 如果画面切换的话就中断循环
if $scene != self
break
end
end
# 准备过渡
Graphics.freeze
# 释放窗口
@help_window.dispose
@status_window.dispose
@skill_window.dispose
@target_window.dispose
end
我们可以看到一开始是各种变量赋值,下面呢,除了少数Scene之外,基本上就进入# 执行过渡 Graphics.transition # 主循环 loop do # 刷新游戏画面 Graphics.update # 刷新输入信息 Input.update # 刷新画面 update # 如果画面切换的话就中断循环 if $scene != self break end end # 准备过渡 Graphics.freeze
# 执行过渡
Graphics.transition
# 主循环
loop do
# 刷新游戏画面
Graphics.update
# 刷新输入信息
Input.update
# 刷新画面
update
# 如果画面切换的话就中断循环
if $scene != self
break
end
end
# 准备过渡
Graphics.freeze
接下来就是各种dispose了。
接下来,不禁要对比一下VX(包括VX ACE)了,看看它们的Scene,首先加入了一个Scene_Base,以VX为例,def main start # 開始処理 perform_transition # トランジション実行 post_start # 開始後処理 Input.update # 入力情報を更新 loop do Graphics.update # ゲーム画面を更新 Input.update # 入力情報を更新 update # フレーム更新 break if $scene != self # 画面が切り替わったらループを中断 end Graphics.update pre_terminate # 終了前処理 Graphics.freeze # トランジション準備 terminate # 終了処理 end
def main
start # 開始処理
perform_transition # トランジション実行
post_start # 開始後処理
Input.update # 入力情報を更新
loop do
Graphics.update # ゲーム画面を更新
Input.update # 入力情報を更新
update # フレーム更新
break if $scene != self # 画面が切り替わったらループを中断
end
Graphics.update
pre_terminate # 終了前処理
Graphics.freeze # トランジション準備
terminate # 終了処理
end
下面的呢?其实都是继承了Scene_Base这个类的main,而子类说白了就是分别对这里的各个方法进行具体而详细的定义,考虑到这里重点是在探究RMXP,所以不赘述,这么做的好处的确是精简了不少代码,咱们不妨从XP尝试一下精简合并。经过一些摸索,我们终于发现除了Scene_Battle等少数类以外,都是按照Graphics.transition完了循环,然后Graphics.freeze。
为了便于理解,我也建立一个Scene_Base这个类并定义几个重要方法def main #↓首先是加载 main_setup #↓为了便于扩展,这里填补空白 main_add # 执行过渡 Graphics.transition #更新 main_update # 更新完毕装备过渡 Graphics.freeze #↓最后是释放 main_dispose end
def main
#↓首先是加载
main_setup
#↓为了便于扩展,这里填补空白
main_add
# 执行过渡
Graphics.transition
#更新
main_update
# 更新完毕装备过渡
Graphics.freeze
#↓最后是释放
main_dispose
end
当然名字可能有点不太准确,但是从业余脚本爱好者来看,适合自己理解即可,看下面一段代码# 主循环 loop do # 刷新游戏画面 Graphics.update # 刷新输入信息 Input.update # 刷新画面 update # 如果画面切换的话就中断循环 if $scene != self break end end
# 主循环
loop do
# 刷新游戏画面
Graphics.update
# 刷新输入信息
Input.update
# 刷新画面
update
# 如果画面切换的话就中断循环
if $scene != self
break
end
end
将此方法定义到main_update这个方法里面,找到凡是符合这个规律的Scene类,继承了Base之后main都可以拆分成两个main_setup和main_dispose。
估计有人会问为什么不把Graphics.freeze和Graphics.transition定义到main_update里面,另外那么像Scene_Battle怎么处理呢?
其实,为了进一步精简代码,我要在Scene_Base类上面再加一个父类Scene,把main_update定义到最顶端的父类Scene里面,这样一来让Scene_Battle直接继承下来,不是很好吗?例如Scene_Title优化之后class Scene_Title < Scene_Base #-------------------------------------------------------------------------- # ● 主处理【受到继承影响】 def main_setup # 战斗测试的情况下 # 生成标题图形 [url=home.php?mod=space&uid=114926]@sprite[/url] = Sprite.new @sprite.bitmap = RPG::Cache.title($data_system.title_name) # 生成命令窗口 s1 = DKRM::NEWGAME_STR s2 = DKRM::LOADGAME_STR s3 = DKRM::EXITGAME_STR @command_window = Window_Command.new(192, [s1, s2, s3]) @command_window.back_opacity = 160 @command_window.x = 320 - @command_window.width / 2 @command_window.y = 288 # 判定继续的有效性 # 存档文件一个也不存在的时候也调查 # 有効为 @continue_enabled 为 true、无效为 false @continue_enabled = false for i in 0..DKRM::FILESAVE_MAX if FileTest.exist?("Save/Save#{i+1}.rxdata") @continue_enabled = true end end # 继续为有效的情况下、光标停止在继续上 # 无效的情况下、继续的文字显示为灰色 if @continue_enabled @command_window.index = 1 else @command_window.disable_item(1) end # 演奏标题 BGM $game_system.bgm_play($data_system.title_bgm) # 停止演奏 ME、BGS Audio.me_stop Audio.bgs_stop end #-------------------------------------------------------------------------- def main_dispose # 释放命令窗口 @command_window.dispose # 释放标题图形 @sprite.bitmap.dispose @sprite.dispose end end
class Scene_Title < Scene_Base
#--------------------------------------------------------------------------
# ● 主处理【受到继承影响】
def main_setup
# 战斗测试的情况下
# 生成标题图形
[url=home.php?mod=space&uid=114926]@sprite[/url] = Sprite.new
@sprite.bitmap = RPG::Cache.title($data_system.title_name)
# 生成命令窗口
s1 = DKRM::NEWGAME_STR
s2 = DKRM::LOADGAME_STR
s3 = DKRM::EXITGAME_STR
@command_window = Window_Command.new(192, [s1, s2, s3])
@command_window.back_opacity = 160
@command_window.x = 320 - @command_window.width / 2
@command_window.y = 288
# 判定继续的有效性
# 存档文件一个也不存在的时候也调查
# 有効为 @continue_enabled 为 true、无效为 false
@continue_enabled = false
for i in 0..DKRM::FILESAVE_MAX
if FileTest.exist?("Save/Save#{i+1}.rxdata")
@continue_enabled = true
end
end
# 继续为有效的情况下、光标停止在继续上
# 无效的情况下、继续的文字显示为灰色
if @continue_enabled
@command_window.index = 1
else
@command_window.disable_item(1)
end
# 演奏标题 BGM
$game_system.bgm_play($data_system.title_bgm)
# 停止演奏 ME、BGS
Audio.me_stop
Audio.bgs_stop
end
#--------------------------------------------------------------------------
def main_dispose
# 释放命令窗口
@command_window.dispose
# 释放标题图形
@sprite.bitmap.dispose
@sprite.dispose
end
end
本探索暂时到这里在Scene_Base上再建立一个父类Scene除了精简代码,难道还有别的企图不成?我会在下一帖子里面开贴分享,如有不用意见尽管回帖提出。
|