设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 4290|回复: 10
打印 上一主题 下一主题

[讨论] RGSS1(2、3也同样)中一个并不会触发的奇怪bug

[复制链接]

Lv5.捕梦者 (版主)

遠航の猫咪

梦石
3
星屑
23186
在线时间
2387 小时
注册时间
2005-10-15
帖子
1166

开拓者

跳转到指定楼层
1
发表于 2021-3-22 04:04:20 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式

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

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

x
本帖最后由 SailCat 于 2021-3-22 04:53 编辑

RUBY 代码复制
  1. def animation(animation, hit)
  2.       dispose_animation
  3.       @_animation = animation
  4.       return if @_animation == nil
  5.       @_animation_hit = hit
  6.       @_animation_duration = @_animation.frame_max
  7.       animation_name = @_animation.animation_name
  8.       animation_hue = @_animation.animation_hue
  9.       bitmap = RPG::Cache.animation(animation_name, animation_hue)
  10.       if @@_reference_count.include?(bitmap)
  11.         @@_reference_count[bitmap] += 1
  12.       else
  13.         @@_reference_count[bitmap] = 1
  14.       end
  15.       @_animation_sprites = []
  16.       if @_animation.position != 3 or not @@_animations.include?(animation)
  17.         for i in 0..15
  18.           sprite = ::Sprite.new(self.viewport)
  19.           sprite.bitmap = bitmap
  20.           sprite.visible = false
  21.           @_animation_sprites.push(sprite)
  22.         end
  23.         unless @@_animations.include?(animation)
  24.           @@_animations.push(animation)
  25.         end
  26.       end
  27.       update_animation
  28.     end


请注意这一句:  if @_animation.position != 3 or not @@_animations.include?(animation)

我查了一下什么叫不等于3:也就是动画的“位置”不等于“画面”(即非全屏动画)
这个if后面是两个否定,你改成肯定并unless就好理解了:除非动画是全屏动画,并且缓存里已经有了这个动画(那么跳过),否则就要实际生成动画图块,并将动画加载到缓存里。

看起来,这个判定是为了当你有8个敌人然后你放了个全体大招的时候,不至于要生成8*16=128个动画元件(因为进行全屏动画所有元件的位置是一样的,这样做完全没有意义),只需要16个元件,然后本体分别闪烁就行了。
但是经过反复实验,放全体大招的时候根本不会触发这个判断,会生成128个动画元件,以毫无意义的方式进行重叠播放(也不能说毫无意义,你要是加法或减法,就能看出来原位叠加了),并且最后咣咣咣释放掉。
这是为啥呢?
战斗时更新精灵的地方在Spriteset_Battle的108-111行:
RUBY 代码复制
  1. # 刷新战斗者的活动块
  2.     for sprite in @enemy_sprites + @actor_sprites
  3.       sprite.update
  4.     end


看出问题了吗?它是每个战斗者依次更新的。
而每个战斗者精灵在执行自己的update的时候,第一句都是super(Sprite_Battler第36行),也就是去执行RPG::Sprite的update。这个操作会干吗呢?会将@@_animations(也就是全屏动画缓存)予以清空。
所以,战斗者A预约调用全屏动画1(animation2_id设置为1),清空缓存,执行动画。然后战斗者B预约调用全屏动画1,清空缓存,执行动画(这时缓存被清空了,于是无法通过那个检测了,会照样生成16个重复的动画元件)。

然后我为啥说这个是不会触发的奇怪bug呢?这里的bug之处,在于@@_reference_count(也就是对动画位图的引用)是在检查之前更新+1的,但是若是检查不通过,不会生成16个动画元件精灵,也就不会产生对动画位图的引用,到最后释放的时候这个计数-1就执行不到了,然后动画精灵解放的时候,缓存位图就dispose不掉,然后大家都知道,这个错误叫内存泄露。
但是,按照目前的更新逻辑(我以战斗为例了,但地图上也是一样的),每个战斗者自己update时都会清缓存,到下一个战斗者时,根本就不会出现“检查不通过”的情况,也就不会出现@@_reference_count的计数器错误。——结果就是,除了会卡一些之外,它的执行逻辑是完全自恰的。

也就是说,这个看上去可以防止全屏动画叠加播放的判断,根本就是形同虚设,白给了。

看看大家打算怎么修这个bug?
保持不动(因为实际不会触发)——但是齐时战斗系统就不好说会不会触发了
还是去掉这个根本无用的判断
还是保留这个判断,但是让它真的能起防止重复播放的作用,并且不会出现计数错误

后记:XP的动画其实也真没有到特别卡的地步,我试着做了个天气扩展插件,允许天上下刀子——后来做着做着发现RPG::Weather继承的不是原生Sprite,而是RPG::Sprite,也就是说天气元素(雨滴,雪花,刀子)都是允许带效果的精灵——然后我试了40个天气元素循环播放状态动画并同时下落,在这种极端情况下,帧率还能连续10秒钟维持在34左右。
又后记:VA也是一模一样的问题(不会触发的bug,形同虚设的判定),顺便XP的动画是按1秒20帧播放的,VA……居然是按1秒15帧播放的,真是不好说这是进步还是退步了……

评分

参与人数 1+1 收起 理由
srwjrevenger + 1 精品文章

查看全部评分

SailCat (小猫子·要开心一点) 共上站 24 次,发表过 11 篇文章 上 次 在: [2006年01月28日11:41:18 星期六] 从 [162.105.120.91] 到本站一游。

Lv5.捕梦者 (版主)

遠航の猫咪

梦石
3
星屑
23186
在线时间
2387 小时
注册时间
2005-10-15
帖子
1166

开拓者

10
 楼主| 发表于 2021-3-28 10:02:04 | 只看该作者
本帖最后由 SailCat 于 2021-3-28 10:04 编辑

https://rpg.blue/thread-484741-1-1.html
该bug问题已经在SEP Core 1.8中被完美修复。见插件bug说明的l)-n)项。

三个bug是交织在一起的,所以先修正了计数错误(从而将重复绘制错误暴露出来)然后通过将@@_animations.clear改为一帧执行一次(植入Spriteset.update)而不是一帧执行多次,来修正重复绘制的错误。
SailCat (小猫子·要开心一点) 共上站 24 次,发表过 11 篇文章 上 次 在: [2006年01月28日11:41:18 星期六] 从 [162.105.120.91] 到本站一游。
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
7981
在线时间
1183 小时
注册时间
2007-7-29
帖子
2055
9
发表于 2021-3-22 23:11:32 | 只看该作者
以前改一个技能多动画的时候也是发现同款bug,只是当时不知道是bug,以为全屏动画就是那么设计的,现在仔细看来还是太草率了……
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
1
星屑
10079
在线时间
4432 小时
注册时间
2005-10-22
帖子
6958

开拓者贵宾

8
发表于 2021-3-22 16:22:32 | 只看该作者
于是大家终于发现这个BUG了,那么我也等着伸手好了。(大雾)
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
6483
在线时间
119 小时
注册时间
2020-1-8
帖子
234
7
发表于 2021-3-22 12:30:30 | 只看该作者
怎么分辨是否重叠啊,我是没看出来……
12人测试,感觉FPS少掉 2-3
  1. module RPG
  2.   class Sprite < ::Sprite
  3.     def dispose_animation
  4.       if @_animation_sprites != nil
  5.         sprite = @_animation_sprites[0]
  6.         if sprite != nil
  7.           @@_reference_count[sprite.bitmap] -= 1
  8.           if @@_reference_count[sprite.bitmap] == 0
  9.             sprite.bitmap.dispose
  10.           end
  11.         end
  12.         for sprite in @_animation_sprites
  13.           sprite.dispose
  14.         end
  15.         @_animation_sprites = nil
  16.       end
  17.       #……………………………………………………………………………………
  18.       if @_animation != nil
  19.         @@_animations.delete(@_animation) if @_animation.position == 3
  20.         @_animation = nil
  21.       end
  22.       #……………………………………………………………………………………
  23.     end
  24.    
  25.     def update
  26.       super
  27.       if @_whiten_duration > 0
  28.         @_whiten_duration -= 1
  29.         self.color.alpha = 128 - (16 - @_whiten_duration) * 10
  30.       end
  31.       if @_appear_duration > 0
  32.         @_appear_duration -= 1
  33.         self.opacity = (16 - @_appear_duration) * 16
  34.       end
  35.       if @_escape_duration > 0
  36.         @_escape_duration -= 1
  37.         self.opacity = 256 - (32 - @_escape_duration) * 10
  38.       end
  39.       if @_collapse_duration > 0
  40.         @_collapse_duration -= 1
  41.         self.opacity = 256 - (48 - @_collapse_duration) * 6
  42.       end
  43.       if @_damage_duration > 0
  44.         @_damage_duration -= 1
  45.         case @_damage_duration
  46.         when 38..39
  47.           @_damage_sprite.y -= 4
  48.         when 36..37
  49.           @_damage_sprite.y -= 2
  50.         when 34..35
  51.           @_damage_sprite.y += 2
  52.         when 28..33
  53.           @_damage_sprite.y += 4
  54.         end
  55.         @_damage_sprite.opacity = 256 - (12 - @_damage_duration) * 32
  56.         if @_damage_duration == 0
  57.           dispose_damage
  58.         end
  59.       end
  60.       if @_animation != nil and (Graphics.frame_count % 2 == 0)
  61.         @_animation_duration -= 1
  62.         update_animation  
  63.       end
  64.       if @_loop_animation != nil and (Graphics.frame_count % 2 == 0)
  65.         update_loop_animation
  66.         @_loop_animation_index += 1
  67.         @_loop_animation_index %= @_loop_animation.frame_max
  68.       end
  69.       if @_blink
  70.         @_blink_count = (@_blink_count + 1) % 32
  71.         if @_blink_count < 16
  72.           alpha = (16 - @_blink_count) * 6
  73.         else
  74.           alpha = (@_blink_count - 16) * 6
  75.         end
  76.         self.color.set(255, 255, 255, alpha)
  77.       end
  78.       #@@_animations.clear
  79.       @@_animations.delete_if {|i| i.position != 3}
  80.     end
  81.   end
  82. end
复制代码

回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
14619
在线时间
2152 小时
注册时间
2016-9-20
帖子
861
6
发表于 2021-3-22 12:25:24 | 只看该作者
本帖最后由 ppspssss 于 2024-8-8 19:37 编辑

,我之前使用这个动画时候也是卡的不行, 基本播放动画从40帧掉到只有30帧, 然后修改了@@_reference_count[bitmap]就變回滿40幀了, 不知有什么副作用,
2024/8/8 追加
if @@_reference_count.include?(bitmap)
        @@_reference_count[bitmap] += 1
      else
        @@_reference_count[bitmap] = 2#b 原是1  改了这个就不会有BUG
      end
我发的贴子大多未经整理是草稿抱歉
回复 支持 反对

使用道具 举报

Lv5.捕梦者

梦石
0
星屑
39016
在线时间
5717 小时
注册时间
2006-11-10
帖子
6619
5
发表于 2021-3-22 10:33:35 | 只看该作者
本帖最后由 灯笼菜刀王 于 2021-3-22 10:38 编辑

我前些时候也发现了同款BUG(应该)



如图, 让主角播放循环动画, 本来应该是一直持续播放的, 此时, 给另一事件播放个同bitmap的动画, 然后呢, 等这个动画结束的时候, 循环动画也一起消失了.....

初步判断是@@_reference_count的判定没起作用, bitmap被释放了~  感觉应该也是这个BUG的原因

坐等解决方法(伸手)
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
6165
在线时间
794 小时
注册时间
2019-1-20
帖子
204
4
发表于 2021-3-22 10:20:27 | 只看该作者
居然允许天上下刀子雨?你这个魔鬼(滑稽)

提高解答机会的方法:
看一下对应版本的帮助文件 看天气预报说今天不下雨
改变问题为更有可能的或常见的 如:天气自动变化下雨→天气系统 果然不准呀~
使用论坛的搜索功能查找相关问题 好丧啊... ...想看女装
清楚说明实际上你想解决的问题  想看坛友的女装  
脚本自己有改过的地方要标明  不要遮脸的
脚本有问题但不是默认的要全部贴出来 大胆点,尽情发
三包原则:包有BUG,包甩锅,包咕咕
回复 支持 反对

使用道具 举报

Lv5.捕梦者

梦石
0
星屑
35186
在线时间
4169 小时
注册时间
2007-12-15
帖子
10067
3
发表于 2021-3-22 10:06:17 | 只看该作者
本帖最后由 89444640 于 2021-3-22 10:15 编辑

对,就是这个闹得我当年卡的要死,
我这里用的攻击对象同时执行攻击动作是对象全体 动画设置是对象方动画为画面,等于当时用全动画脚本时候,同一个时间加上敌我待机动作,一旦我执行全屏攻击最多同时在播放8敌人+4己方+8对象方画面的动画,这还不算中毒什么的循环状态,
造成我当年战斗时候一旦战斗进行多了,就会卡死跳出。难道是因为这种全屏占用的内存一直没清除?我动画文件是又多又大,而且当初也没调用4G内存的微软官方不定,全屏攻击同时叠加N个不卡死才怪。
话说,用guoxiaomi写的全屏动画,直接ps做640*320的去播放,一旦目标是对象方,画面,也会叠加8次?

XP不能调用显卡,2D序列帧只要我是非像素的光效,一旦体积上来就完蛋。所以我也只好出迷宫什么的手动清一下内存。
回复 支持 反对

使用道具 举报

Lv6.析梦学徒

老鹰

梦石
40
星屑
34730
在线时间
6740 小时
注册时间
2012-5-26
帖子
3259

极短24评委极短23参与极短22参与极短21评委老司机慢点开短篇十吟唱者组别冠军开拓者剧作品鉴家

2
发表于 2021-3-22 09:18:19 | 只看该作者
关于这个,va里的yea的battle core插件就新增了一个修改
为技能备注栏增加了<one anim>的备注
如果有这个,就不再是所有目标调用use_item(里面包含显示动画和执行伤害),而是在迭代前显示一个动画,然后每个目标只执行伤害

点评

VA没有闪烁是否个体击中的判定。XP是没法这么玩的……  发表于 2021-3-22 18:00
回复 支持 反对

使用道具 举报

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

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-22 10:16

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表