庆祝我的博客搬家,把我七年前写了一半的教程写完了……
访问我的博客获得更好的阅读体验
https://script.miaowm5.com/post/93
引言
前一段时间玩了海底囚人的 Mogeko Castle ,虽然电波对不上玩起来感觉有点微妙,但是这个游戏使用的菜单还是有点意思的。因此,打算写一个简单的教程介绍一下如何使用RMVA制作出这样的菜单。请注意,下面的教程要求你有一定的脚本基础,整个教程我更多的是说明我写这个脚本时的思路而不是为什么可以这么写,因此……嘛。
首先先放上游戏菜单的截图:
另外,随着游戏进程的推进或者游戏中加入新角色时,菜单中的立绘和人物信息还会发生改变,例如下面这样:
大概搞懂了需求以后,下面就开始开心的写代码吧。
调整已有逻辑
首先,先在 Window_MenuCommand 中删除菜单不需要的选项。
这里保留了 add_original_commands 以增强和其他菜单添加选项脚本的兼容性。
RUBY 代码
- class Window_MenuCommand
- def make_command_list
- add_command(Vocab::item, :item)
- add_original_commands
- add_save_command
- add_game_end_command
- end
- end
复制代码
接着,进入到 Scene_Menu 中,把不需要的右侧队友状态窗口删除。
RUBY 代码
- class Scene_Menu
- def create_status_window
- end
- end
复制代码
注意到原本的菜单中这两个窗口并不是仅仅贴着屏幕边缘而是和其有一小段距离的,在 start 的最后将这两个窗口的位置稍微移动一些。
RUBY 代码
- class Scene_Menu
- alias m5_20150301_start start
- def start
- m5_20150301_start
- @command_window.x += 6
- @command_window.y += 6
- @gold_window.x += 6
- @gold_window.y -= 6
- end
- end
复制代码
队伍成员窗口
下面开始制作显示当前队伍成员的窗口,新建一个 Window_Base 的子类,起一个不容易冲突的名字 Window_M5ActorStatus20150301。最开始先要快速测试窗口是否正常显示,因此先把随便把位置定在 200,200,大小设置为 160*100
RUBY 代码
- class Window_M5ActorStatus20150301 < Window_Base
- def initialize
- super(200,200,160,100)
- end
- end
复制代码
将上述窗口加到 Scene_Menu 中
RUBY 代码
- class Scene_Menu
- alias m5_20150301_start start
- def start
- m5_20150301_start
- @command_window.x += 6
- @command_window.y += 6
- @gold_window.x += 6
- @gold_window.y -= 6
- @m5_20220418_actor_window = Window_M5ActorStatus20150301.new
- end
- end
复制代码
总体来看似乎没有什么大问题,接下去就开始为窗口内部描绘内容了。先从描绘队伍中第一个角色开始。重新修改 Window_M5ActorStatus20150301 添加描绘行走图和名字的代码。
同时,根据游戏内实际的表现,开始细调内容的位置和窗口的尺寸位置。最终的窗口大小为 160*70,位置为 6,286。
RUBY 代码
- class Window_M5ActorStatus20150301 < Window_Base
- def initialize
- x = 6
- y = 286
- width = 160
- height = 70
- actor = $game_party.leader
- super(x,y,width,height)
- refresh(actor)
- end
- def refresh(actor)
- contents.clear
- draw_actor_graphic(actor, 20, 40)
- draw_text(0, 0, contents_width, line_height, actor.name, 2)
- end
- end
复制代码
第一个角色调通后,下面该开始根据队伍中的实际数据显示角色了。重新改写 Window_M5ActorStatus20150301 的代码
RUBY 代码
- class Window_M5ActorStatus20150301 < Window_Base
- def initialize(actor, index)
- x = 6
- y = 286 - index * (70 + 5)
- width = 160
- height = 70
- super(x,y,width,height)
- refresh(actor)
- end
- def refresh(actor)
- contents.clear
- draw_actor_graphic(actor, 20, 40)
- draw_text(0, 0, contents_width, line_height, actor.name, 2)
- end
- end
复制代码
Window_M5ActorStatus20150301 里,窗口的 y 坐标从固定的286改成第一个窗口286,第二个窗口286-70+5,第三个窗口286-(70+5)*2……依次类推。(70 是窗口的高度,5 是窗口和窗口的间距。)窗口描绘的角色也从固定的 $game_party.leader 修改成了通过参数传递。
接下来,修改 Scene_Menu ,将 Window_M5ActorStatus20150301 所需的 actor 和 index 传递进去。
RUBY 代码
- class Scene_Menu
- alias m5_20150301_start start
- def start
- m5_20150301_start
- @command_window.x += 6
- @command_window.y += 6
- @gold_window.x += 6
- @gold_window.y -= 6
- @m5_20220418_actor_window = $game_party.all_members.slice(0,3)
- .reverse.collect.each_with_indexdo |actor, index|
- Window_M5ActorStatus20150301.new(actor, index)
- end
- end
- instance_methods(false).include?(:terminate) ||
- (def terminate *args; super; end)
- alias m5_20220418_terminate terminate
- def terminate
- m5_20220418_terminate
- @m5_20220418_actor_window.each(&:dispose)
- end
- end
复制代码
……似乎写了一段很吓人的代码,我们一点点分析这次做出的改动。
- @m5_20220418_actor_window = $game_party.all_members.slice(0,3) .reverse.collect.each_with_index do |actor, index| Window_M5ActorStatus20150301.new(actor, index) end复制代码
复制代码@m5_20220418_actor_window 不再是窗口了,现在变成了一个数组。我们先通过 $game_party.all_members 获取到当前队伍中全部的角色,再通过 slice(0,3) 选择前三个角色,之后,使用 reverse 方法反转顺序,最后使用 collect 方法将每个角色作为参数传递给 Window_M5ActorStatus20150301,最终返回的窗口被放入了数组中。通过上面这一串操作,最终成功达成了根据队伍中当前成员情况动态创建窗口的目的。
同时,因为 @m5_20220418_actor_window 不再是窗口而是数组了,数组中的窗口不再会自动释放了,因此,我们需要手动在界面关闭时调用每个窗口的 dispose 方法
- alias m5_20220418_terminate terminatedef terminate m5_20220418_terminate @m5_20220418_actor_window.each(&:dispose)end复制代码
复制代码另外,在默认脚本中 Scene_Menu 并没有定义 terminate 方法,出于 alias 的兼容性考虑,我们还需要显式的定义一下。
- instance_methods(false).include?(:terminate) || (def terminate *args; super; end)复制代码
复制代码大功告成!
立绘展示
完成了角色信息弹窗,接下来就开始写界面右侧立绘展示的代码了。在开始写代码之前我们先规划一下这个功能的设计。对于角色立绘的展示,我们打算换一种方式,直接根据 变量1 的值确定立绘显示的内容。
我们先准备素材,这次的素材选择的是 MtU@ついった 老师画的结月缘,为了方便对坐标,这次直接将素材尺寸处理成屏幕的 544*416 大小,将素材放到 Graphics/Pictures/menu_actor 下面。
接下来,继续改写 Scene_Menu ,加上用于显示立绘的 Sprite 的创建和释放代码。
- class Scene_Menu def start m5_20150301_start @command_window.x += 6 @command_window.y += 6 @gold_window.x += 6 @gold_window.y -= 6 @m5_20220418_actor_window = $game_party.all_members.slice(0,3) .reverse.collect.each_with_index do |actor, index| Window_M5ActorStatus20150301.new(actor, index) end @m5_20220418_actor_sprite = Sprite.new @m5_20220418_actor_sprite.bitmap = Cache.picture('menu_actor/0') end def terminate m5_20220418_terminate @m5_20220418_actor_window.each(&:dispose) @m5_20220418_actor_sprite.dispose endend复制代码
复制代码显示正常了,接下来就改写代码,让图片能够根据变量1的值动态的显示不同的立绘吧。
- @m5_20220418_actor_sprite.bitmap = Cache.picture("menu_actor/#{$game_variables[1]}")复制代码
复制代码大功告成!
最终成品
RUBY 代码
- class Window_MenuCommand
- def make_command_list
- add_command(Vocab::item, :item)
- add_original_commands
- add_save_command
- add_game_end_command
- end
- end
- class Scene_Menu
- alias m5_20150301_start start
- def start
- m5_20150301_start
- @command_window.x += 6
- @command_window.y += 6
- @gold_window.x += 6
- @gold_window.y -= 6
- @m5_20220418_actor_window = $game_party.all_members.slice(0,3)
- .reverse.collect.each_with_indexdo |actor, index|
- Window_M5ActorStatus20150301.new(actor, index)
- end
- @m5_20220418_actor_sprite = Sprite.new
- @m5_20220418_actor_sprite.bitmap = Cache.picture("menu_actor/#{$game_variables[1]}")
- end
- def create_status_window
- end
- instance_methods(false).include?(:terminate) ||
- (def terminate *args; super; end)
- alias m5_20220418_terminate terminate
- def terminate
- m5_20220418_terminate
- @m5_20220418_actor_window.each(&:dispose)
- @m5_20220418_actor_sprite.dispose
- end
- end
- class Window_M5ActorStatus20150301 < Window_Base
- def initialize(actor, index)
- x = 6
- y = 286 - index * (70 + 5)
- width = 160
- height = 70
- super(x,y,width,height)
- refresh(actor)
- end
- def refresh(actor)
- contents.clear
- draw_actor_graphic(actor, 20, 40)
- draw_text(0, 0, contents_width, line_height, actor.name, 2)
- end
- end
复制代码
本帖来自P1论坛作者小怪兽奇奇侠,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:
https://rpg.blue/forum.php?mod=viewthread&tid=489404 若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。