Project1
标题: RGSS1 的「又一」坑人 BUG [打印本页]
作者: RyanBern 时间: 2019-8-25 10:41
标题: RGSS1 的「又一」坑人 BUG
本帖最后由 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
大功告成。
作者: guoxiaomi 时间: 2019-8-25 15:52
23333机智的我早就注释掉了
作者: hys111111 时间: 2019-8-25 19:24
本帖最后由 hys111111 于 2019-8-25 19:28 编辑
类似的,
做ARPG事件多的时候,地图很卡,因为Game_Character下的def passable?(x,y,d)会先调用Game_Map下的def passable?(x,y,d,self_event = nil),
然而这两个类下的passable?都会执行for event in $game_map.events.values循环,很不舒服。直接不要Game_Map下的passable?了(整合到Game_Character下了,循环执行两次变为一次)。
到后面直接连check_event_trigger_there也整合到passable?里面去了
作者: e900003 时间: 2019-8-26 20:18
本帖最后由 e900003 于 2019-8-26 21:36 编辑
我目前測試 套用此設定之後 用公共事件設定造成傷害的設定
不會在造成傷害時候刷新HP跟MP
只能等下一回合之後才會刷新一次
有什麼解決辦法可以解決這個沒有自動刷新HP跟MP的問題
更新: 找到方案了,謝謝
作者: Six_Fish 时间: 2019-8-26 21:41
公共事件里用事件脚本手动$game_temp.battle_status_need_refresh = true一下就好了
-
咳,不好意思没看到已经解决了
作者: fux2 时间: 2019-8-26 22:31
这,简直强到不可思议,我一直以为是fps统计方式有问题
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |