加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 SailCat 于 2021-3-22 04:53 编辑
def animation(animation, hit) dispose_animation @_animation = animation return if @_animation == nil @_animation_hit = hit @_animation_duration = @_animation.frame_max animation_name = @_animation.animation_name animation_hue = @_animation.animation_hue bitmap = RPG::Cache.animation(animation_name, animation_hue) if @@_reference_count.include?(bitmap) @@_reference_count[bitmap] += 1 else @@_reference_count[bitmap] = 1 end @_animation_sprites = [] if @_animation.position != 3 or not @@_animations.include?(animation) for i in 0..15 sprite = ::Sprite.new(self.viewport) sprite.bitmap = bitmap sprite.visible = false @_animation_sprites.push(sprite) end unless @@_animations.include?(animation) @@_animations.push(animation) end end update_animation end
def animation(animation, hit)
dispose_animation
@_animation = animation
return if @_animation == nil
@_animation_hit = hit
@_animation_duration = @_animation.frame_max
animation_name = @_animation.animation_name
animation_hue = @_animation.animation_hue
bitmap = RPG::Cache.animation(animation_name, animation_hue)
if @@_reference_count.include?(bitmap)
@@_reference_count[bitmap] += 1
else
@@_reference_count[bitmap] = 1
end
@_animation_sprites = []
if @_animation.position != 3 or not @@_animations.include?(animation)
for i in 0..15
sprite = ::Sprite.new(self.viewport)
sprite.bitmap = bitmap
sprite.visible = false
@_animation_sprites.push(sprite)
end
unless @@_animations.include?(animation)
@@_animations.push(animation)
end
end
update_animation
end
请注意这一句: if @_animation.position != 3 or not @@_animations.include?(animation)
我查了一下什么叫不等于3:也就是动画的“位置”不等于“画面”(即非全屏动画)
这个if后面是两个否定,你改成肯定并unless就好理解了:除非动画是全屏动画,并且缓存里已经有了这个动画(那么跳过),否则就要实际生成动画图块,并将动画加载到缓存里。
看起来,这个判定是为了当你有8个敌人然后你放了个全体大招的时候,不至于要生成8*16=128个动画元件(因为进行全屏动画所有元件的位置是一样的,这样做完全没有意义),只需要16个元件,然后本体分别闪烁就行了。
但是经过反复实验,放全体大招的时候根本不会触发这个判断,会生成128个动画元件,以毫无意义的方式进行重叠播放(也不能说毫无意义,你要是加法或减法,就能看出来原位叠加了),并且最后咣咣咣释放掉。
这是为啥呢?
战斗时更新精灵的地方在Spriteset_Battle的108-111行:
# 刷新战斗者的活动块 for sprite in @enemy_sprites + @actor_sprites sprite.update end
# 刷新战斗者的活动块
for sprite in @enemy_sprites + @actor_sprites
sprite.update
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帧播放的,真是不好说这是进步还是退步了…… |