加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 喵呜喵5 于 2022-4-19 00:08 编辑
庆祝我的博客搬家,把我七年前写了一半的教程写完了……
访问我的博客获得更好的阅读体验 https://script.miaowm5.com/post/93
引言
前一段时间玩了海底囚人的 Mogeko Castle ,虽然电波对不上玩起来感觉有点微妙,但是这个游戏使用的菜单还是有点意思的。因此,打算写一个简单的教程介绍一下如何使用RMVA制作出这样的菜单。请注意,下面的教程要求你有一定的脚本基础,整个教程我更多的是说明我写这个脚本时的思路而不是为什么可以这么写,因此……嘛。
首先先放上游戏菜单的截图:
另外,随着游戏进程的推进或者游戏中加入新角色时,菜单中的立绘和人物信息还会发生改变,例如下面这样:
大概搞懂了需求以后,下面就开始开心的写代码吧。
调整已有逻辑
首先,先在 Window_MenuCommand 中删除菜单不需要的选项。
这里保留了 add_original_commands 以增强和其他菜单添加选项脚本的兼容性。
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 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 中,把不需要的右侧队友状态窗口删除。
class Scene_Menu def create_status_window end end
class Scene_Menu
def create_status_window
end
end
注意到原本的菜单中这两个窗口并不是仅仅贴着屏幕边缘而是和其有一小段距离的,在 start 的最后将这两个窗口的位置稍微移动一些。
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
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
class Window_M5ActorStatus20150301 < Window_Base def initialize super(200,200,160,100) end end
class Window_M5ActorStatus20150301 < Window_Base
def initialize
super(200,200,160,100)
end
end
将上述窗口加到 Scene_Menu 中
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
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。
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
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 的代码
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
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 传递进去。
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_index do |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
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_index do |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 terminate
- def 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
- end
- end
复制代码
显示正常了,接下来就改写代码,让图片能够根据变量1的值动态的显示不同的立绘吧。
- @m5_20220418_actor_sprite.bitmap = Cache.picture("menu_actor/#{$game_variables[1]}")
复制代码
大功告成!
最终成品
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_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/#{$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
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_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/#{$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
|