查看: 4249|回复: 8

[讨论] RGSS1 的「又一」坑人 BUG

[复制链接]
梦石
0
星屑
9557
在线时间
5074 小时
注册时间
2013-6-21
回帖
3459

开拓者贵宾剧作品鉴家

发表于 2019-8-25 10:41:32 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 RyanBern 于 2019-8-25 10:44 编辑

不知道大家在战斗中触发事件时有没有这样的体会:整个游戏会出现明显卡顿。按 F2 查看 FPS 时发现帧率只有 10 左右甚至个位数。
例如使用 Steam 版的最新 RMXP 创建新工程,在没有额外添加任何脚本的情况下就会出现下面这个图的情况。

1.PNG

这个图中我只是用了一个显示文章的命令,游戏的帧率直接跌到个位数。如果是显示战斗动画这种肉眼可见的事件那么体感会更加明显。在事件执行完成之后,游戏的 FPS 立即恢复了正常的水平。而在地图上执行各种事件我们并没有发现什么异常。

问题就出现在 Scene_Battle 刷新机制上。打开脚本编辑器后找到 Scene_Battle 1 可以看到定义 update 方法的部分:
[pre lang="Ruby"]
  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
[/pre]
刷新机制表明如果战斗事件不为空就优先刷新事件解释器。但问题就出现在这个过程的最后一步。
[pre lang="Ruby"]if @phase != 5
  @status_window.refresh
end[/pre]
这句话的意思是说如果战斗的阶段不在第五阶段,那么就需要对 @status_window 的内容进行重新描绘。战斗的第五阶段实际上是显示战利品,获得 EXP 的阶段,除了这个阶段以外,只要事件解释器运行,每次 update 都会重新刷新一次状态窗口。这个 @status_window 就是显示角色 HP、SP、当前状态的那个窗口。

写过 RMXP 脚本的人都知道,refresh 操作一般是对 bitmap 进行各种绘制,里面调用的方法执行起来通常是比较慢的。反复调用 refresh 操作应该极力避免。这也就不难理解为什么在战斗中执行事件会导致帧率下降了。
为了测试是否真的是这个地方的锅,可以直接将这一段注释掉,结果发现帧率直接恢复正常。

2.PNG

那么为啥默认系统要放一个 @status_window.refresh 在这呢?当然是因为状态窗口有时候在执行事件指令之后是需要刷新的,例如:增减 HP/SP,更改角色姓名,更改角色状态。不过即使在这些场合需要刷新,也不需要每帧都进行检查。最简单的修复办法就是在刷新之前增加一个判定标志,当只有执行特定事件的一瞬间才去刷新状态窗口。我们先在 Game_Temp 中增加一个刷新战斗状态窗口的标志。
[pre lang="Ruby"]class Game_Temp
  attr_accessor :battle_status_need_refresh
  def initialize
    # ...
    @battle_status_need_refresh = false
  end
end[/pre]
然后再需要刷新窗口的时候打开这个标志。以增减 HP 为例,它的事件指令编号是 311。
[pre lang="Ruby"]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
[/pre]
在这个指令增加一个开启刷新标志的命令。最后就是修改 Scene_Battle 1 的刷新判定了。
[pre lang="Ruby"]if @phase != 5 && $game_temp.battle_status_need_refresh
  @status_window.refresh
  $game_temp.battle_status_need_refresh = false
end[/pre]
大功告成。

评分

参与人数 9赞 +9 收起 理由
e900003 + 1 精品文章
89444640 + 1 精品文章
W.Q.C. + 1 精品文章
kirh_036 + 1 醋虾
真·可乐 + 1 精品文章
miantouchi + 1 精品文章
kklt + 1 精品文章
百里_飞柳 + 1 我很赞同
灯笼菜刀王 + 1 精品文章

查看全部评分

梦石
1
星屑
24088
在线时间
3339 小时
注册时间
2011-7-8
回帖
3862

开拓者

发表于 2019-8-25 15:52:20 | 显示全部楼层
23333机智的我早就注释掉了

点评

如果不用那几个命令确实注释掉更简单粗暴。  发表于 2019-8-25 18:34
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复

使用道具 举报

双子人

梦石
0
星屑
3205
在线时间
3619 小时
注册时间
2009-4-4
回帖
3901

开拓者

发表于 2019-8-25 19:24:18 | 显示全部楼层
本帖最后由 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?里面去了

点评

很好奇两个passable是怎样合并的?看了半天表示很晕。(=_=)  发表于 2020-1-27 04:21

评分

参与人数 2赞 +2 收起 理由
灯笼菜刀王 + 1 我很赞同
guoxiaomi + 1 我很赞同

查看全部评分

回复

使用道具 举报

梦石
0
星屑
703
在线时间
313 小时
注册时间
2013-6-1
回帖
125
发表于 2019-8-26 20:18:32 | 显示全部楼层
本帖最后由 e900003 于 2019-8-26 21:36 编辑

我目前測試  套用此設定之後 用公共事件設定造成傷害的設定
不會在造成傷害時候刷新HP跟MP
只能等下一回合之後才會刷新一次
有什麼解決辦法可以解決這個沒有自動刷新HP跟MP的問題

更新: 找到方案了,謝謝
回复

使用道具 举报

梦石
0
星屑
4638
在线时间
488 小时
注册时间
2017-7-7
回帖
134

R考场第七期纪念奖

发表于 2019-8-26 21:41:34 | 显示全部楼层
e900003 发表于 2019-8-26 20:18
我目前測試  套用此設定之後 用公共事件設定造成傷害的設定
不會在造成傷害時候刷新HP跟MP
只能等下一回合 ...


公共事件里用事件脚本手动$game_temp.battle_status_need_refresh = true一下就好了
-
咳,不好意思没看到已经解决了
回复

使用道具 举报

老黄鸡

梦石
4
星屑
45695
在线时间
7948 小时
注册时间
2009-7-6
回帖
13337

MZ评测员RM创作大赛01组委会开拓者贵宾

发表于 2019-8-26 22:31:19 | 显示全部楼层
这,简直强到不可思议,我一直以为是fps统计方式有问题

点评

这鸡假装没注意到。实际上已经自己修好了。  发表于 2019-8-26 23:38
RGDirect - DirectX驱动的RGSS,点我了解.
(排满,暂停)RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部