加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 RyanBern 于 2019-8-25 10:44 编辑
不知道大家在战斗中触发事件时有没有这样的体会:整个游戏会出现明显卡顿。按 F2 查看 FPS 时发现帧率只有 10 左右甚至个位数。
例如使用 Steam 版的最新 RMXP 创建新工程,在没有额外添加任何脚本的情况下就会出现下面这个图的情况。
这个图中我只是用了一个显示文章的命令,游戏的帧率直接跌到个位数。如果是显示战斗动画这种肉眼可见的事件那么体感会更加明显。在事件执行完成之后,游戏的 FPS 立即恢复了正常的水平。而在地图上执行各种事件我们并没有发现什么异常。
问题就出现在 Scene_Battle 刷新机制上。打开脚本编辑器后找到 Scene_Battle 1 可以看到定义 update 方法的部分:
def update # If battle event is running if $game_system.battle_interpreter.running? # Update interpreter $game_system.battle_interpreter.update # If a battler which is forcing actions doesn't exist if $game_temp.forcing_battler == nil # If battle event has finished running unless $game_system.battle_interpreter.running? # Rerun battle event set up if battle continues unless judge setup_battle_event end end # If not after battle phase if @phase != 5 # Refresh status window @status_window.refresh end end end
def update
# If battle event is running
if $game_system.battle_interpreter.running?
# Update interpreter
$game_system.battle_interpreter.update
# If a battler which is forcing actions doesn't exist
if $game_temp.forcing_battler == nil
# If battle event has finished running
unless $game_system.battle_interpreter.running?
# Rerun battle event set up if battle continues
unless judge
setup_battle_event
end
end
# If not after battle phase
if @phase != 5
# Refresh status window
@status_window.refresh
end
end
end
刷新机制表明如果战斗事件不为空就优先刷新事件解释器。但问题就出现在这个过程的最后一步。
if @phase != 5 @status_window.refresh end
if @phase != 5
@status_window.refresh
end
这句话的意思是说如果战斗的阶段不在第五阶段,那么就需要对 @status_window 的内容进行重新描绘。战斗的第五阶段实际上是显示战利品,获得 EXP 的阶段,除了这个阶段以外,只要事件解释器运行,每次 update 都会重新刷新一次状态窗口。这个 @status_window 就是显示角色 HP、SP、当前状态的那个窗口。
写过 RMXP 脚本的人都知道,refresh 操作一般是对 bitmap 进行各种绘制,里面调用的方法执行起来通常是比较慢的。反复调用 refresh 操作应该极力避免。这也就不难理解为什么在战斗中执行事件会导致帧率下降了。
为了测试是否真的是这个地方的锅,可以直接将这一段注释掉,结果发现帧率直接恢复正常。
那么为啥默认系统要放一个 @status_window.refresh 在这呢?当然是因为状态窗口有时候在执行事件指令之后是需要刷新的,例如:增减 HP/SP,更改角色姓名,更改角色状态。不过即使在这些场合需要刷新,也不需要每帧都进行检查。最简单的修复办法就是在刷新之前增加一个判定标志,当只有执行特定事件的一瞬间才去刷新状态窗口。我们先在 Game_Temp 中增加一个刷新战斗状态窗口的标志。
class Game_Temp attr_accessor :battle_status_need_refresh def initialize # ... @battle_status_need_refresh = false end end
class Game_Temp
attr_accessor :battle_status_need_refresh
def initialize
# ...
@battle_status_need_refresh = false
end
end
然后再需要刷新窗口的时候打开这个标志。以增减 HP 为例,它的事件指令编号是 311。
class Interpreter def command_311 # Get operate value value = operate_value(@parameters[1], @parameters[2], @parameters[3]) # Process with iterator iterate_actor(@parameters[0]) do |actor| # If HP are not 0 if actor.hp > 0 # Change HP (if death is not permitted, make HP 1) if @parameters[4] == false and actor.hp + value <= 0 actor.hp = 1 else actor.hp += value end end end # Determine game over $game_temp.gameover = $game_party.all_dead? # 刷新状态窗口 if $game_temp.in_battle $game_temp.battle_status_need_refresh = true end # Continue return true end end
class Interpreter
def command_311
# Get operate value
value = operate_value(@parameters[1], @parameters[2], @parameters[3])
# Process with iterator
iterate_actor(@parameters[0]) do |actor|
# If HP are not 0
if actor.hp > 0
# Change HP (if death is not permitted, make HP 1)
if @parameters[4] == false and actor.hp + value <= 0
actor.hp = 1
else
actor.hp += value
end
end
end
# Determine game over
$game_temp.gameover = $game_party.all_dead?
# 刷新状态窗口
if $game_temp.in_battle
$game_temp.battle_status_need_refresh = true
end
# Continue
return true
end
end
在这个指令增加一个开启刷新标志的命令。最后就是修改 Scene_Battle 1 的刷新判定了。
if @phase != 5 && $game_temp.battle_status_need_refresh @status_window.refresh $game_temp.battle_status_need_refresh = false end
if @phase != 5 && $game_temp.battle_status_need_refresh
@status_window.refresh
$game_temp.battle_status_need_refresh = false
end
大功告成。 |