From f07b44d82683b025400b995812d12c52961cb2f5 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sun, 5 Nov 2023 16:15:41 +0000 Subject: [PATCH] Minor lag improvements to overworld animations --- Data/Scripts/001_Technical/006_RPG_Sprite.rb | 260 +--------------- .../005_Sprites/008_Sprite_AnimationSprite.rb | 284 ++++++++++++++++-- .../007_BitmapSprite.rb | 2 +- Data/Scripts/009_Scenes/002_EventScene.rb | 1 + 4 files changed, 271 insertions(+), 276 deletions(-) diff --git a/Data/Scripts/001_Technical/006_RPG_Sprite.rb b/Data/Scripts/001_Technical/006_RPG_Sprite.rb index 047b9345..7a960d09 100644 --- a/Data/Scripts/001_Technical/006_RPG_Sprite.rb +++ b/Data/Scripts/001_Technical/006_RPG_Sprite.rb @@ -1,262 +1,6 @@ #=============================================================================== -# -#=============================================================================== -class SpriteAnimation - @@_animations = [] - @@_reference_count = {} - - def initialize(sprite) - @sprite = sprite - end - - def x(*arg); @sprite.x(*arg); end - def y(*arg); @sprite.y(*arg); end - def ox(*arg); @sprite.ox(*arg); end - def oy(*arg); @sprite.oy(*arg); end - def viewport(*arg); @sprite.viewport(*arg); end - def flash(*arg); @sprite.flash(*arg); end - def src_rect(*arg); @sprite.src_rect(*arg); end - def opacity(*arg); @sprite.opacity(*arg); end - def tone(*arg); @sprite.tone(*arg); end - - def self.clear - @@_animations.clear - end - - def dispose - dispose_animation - dispose_loop_animation - end - - def animation(animation, hit, height = 3) - dispose_animation - @_animation = animation - return if @_animation.nil? - @_animation_hit = hit - @_animation_height = height - @_animation_duration = @_animation.frame_max - @_animation_index = -1 - fr = 20 - if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/] - fr = $~[1].to_i - end - @_animation_time_per_frame = 1.0 / fr - @_animation_timer_start = System.uptime - animation_name = @_animation.animation_name - animation_hue = @_animation.animation_hue - bitmap = pbGetAnimation(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 || !@@_animations.include?(animation) - 16.times do - sprite = ::Sprite.new(self.viewport) - sprite.bitmap = bitmap - sprite.visible = false - @_animation_sprites.push(sprite) - end - @@_animations.push(animation) unless @@_animations.include?(animation) - end - update_animation - end - - def loop_animation(animation) - return if animation == @_loop_animation - dispose_loop_animation - @_loop_animation = animation - return if @_loop_animation.nil? - @_loop_animation_duration = @_animation.frame_max - @_loop_animation_index = -1 - fr = 20 - if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/] - fr = $~[1].to_i - end - @_loop_animation_time_per_frame = 1.0 / fr - @_loop_animation_timer_start = System.uptime - animation_name = @_loop_animation.animation_name - animation_hue = @_loop_animation.animation_hue - bitmap = pbGetAnimation(animation_name, animation_hue) - if @@_reference_count.include?(bitmap) - @@_reference_count[bitmap] += 1 - else - @@_reference_count[bitmap] = 1 - end - @_loop_animation_sprites = [] - 16.times do - sprite = ::Sprite.new(self.viewport) - sprite.bitmap = bitmap - sprite.visible = false - @_loop_animation_sprites.push(sprite) - end - update_loop_animation - end - - def dispose_animation - return if @_animation_sprites.nil? - sprite = @_animation_sprites[0] - if sprite - @@_reference_count[sprite.bitmap] -= 1 - sprite.bitmap.dispose if @@_reference_count[sprite.bitmap] == 0 - end - @_animation_sprites.each { |s| s.dispose } - @_animation_sprites = nil - @_animation = nil - @_animation_duration = 0 - end - - def dispose_loop_animation - return if @_loop_animation_sprites.nil? - sprite = @_loop_animation_sprites[0] - if sprite - @@_reference_count[sprite.bitmap] -= 1 - sprite.bitmap.dispose if @@_reference_count[sprite.bitmap] == 0 - end - @_loop_animation_sprites.each { |s| s.dispose } - @_loop_animation_sprites = nil - @_loop_animation = nil - end - - def active? - return @_loop_animation_sprites || @_animation_sprites - end - - def effect? - return @_animation_duration > 0 - end - - def update - update_animation if @_animation - update_loop_animation if @_loop_animation - end - - def update_animation - new_index = ((System.uptime - @_animation_timer_start) / @_animation_time_per_frame).to_i - if new_index >= @_animation_duration - dispose_animation - return - end - quick_update = (@_animation_index == new_index) - @_animation_index = new_index - frame_index = @_animation_index - cell_data = @_animation.frames[frame_index].cell_data - position = @_animation.position - animation_set_sprites(@_animation_sprites, cell_data, position, quick_update) - return if quick_update - @_animation.timings.each do |timing| - next if timing.frame != frame_index - animation_process_timing(timing, @_animation_hit) - end - end - - def update_loop_animation - new_index = ((System.uptime - @_loop_animation_timer_start) / @_loop_animation_time_per_frame).to_i - new_index %= @_loop_animation_duration - quick_update = (@_loop_animation_index == new_index) - @_loop_animation_index = new_index - frame_index = @_loop_animation_index - cell_data = @_loop_animation.frames[frame_index].cell_data - position = @_loop_animation.position - animation_set_sprites(@_loop_animation_sprites, cell_data, position, quick_update) - return if quick_update - @_loop_animation.timings.each do |timing| - next if timing.frame != frame_index - animation_process_timing(timing, true) - end - end - - def animation_set_sprites(sprites, cell_data, position, quick_update = false) - sprite_x = 320 - sprite_y = 240 - if position == 3 # Screen - if self.viewport - sprite_x = self.viewport.rect.width / 2 - sprite_y = self.viewport.rect.height - 160 - end - else - sprite_x = self.x - self.ox + (self.src_rect.width / 2) - sprite_y = self.y - self.oy - if self.src_rect.height > 1 - sprite_y += self.src_rect.height / 2 if position == 1 # Middle - sprite_y += self.src_rect.height if position == 2 # Bottom - end - end - 16.times do |i| - sprite = sprites[i] - pattern = cell_data[i, 0] - if sprite.nil? || pattern.nil? || pattern == -1 - sprite.visible = false if sprite - next - end - sprite.x = sprite_x + cell_data[i, 1] - sprite.y = sprite_y + cell_data[i, 2] - next if quick_update - sprite.visible = true - sprite.src_rect.set((pattern % 5) * 192, (pattern / 5) * 192, 192, 192) - case @_animation_height - when 0 then sprite.z = 1 - when 1 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3 / 2) + 1 - when 2 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3) + 1 - else sprite.z = 2000 - end - sprite.ox = 96 - sprite.oy = 96 - sprite.zoom_x = cell_data[i, 3] / 100.0 - sprite.zoom_y = cell_data[i, 3] / 100.0 - sprite.angle = cell_data[i, 4] - sprite.mirror = (cell_data[i, 5] == 1) - sprite.tone = self.tone - sprite.opacity = cell_data[i, 6] * self.opacity / 255.0 - sprite.blend_type = cell_data[i, 7] - end - end - - def animation_process_timing(timing, hit) - if timing.condition == 0 || - (timing.condition == 1 && hit == true) || - (timing.condition == 2 && hit == false) - if timing.se.name != "" - se = timing.se - pbSEPlay(se) - end - case timing.flash_scope - when 1 - self.flash(timing.flash_color, timing.flash_duration * 2) - when 2 - self.viewport.flash(timing.flash_color, timing.flash_duration * 2) if self.viewport - when 3 - self.flash(nil, timing.flash_duration * 2) - end - end - end - - def x=(x) - sx = x - self.x - return if sx == 0 - if @_animation_sprites - 16.times { |i| @_animation_sprites[i].x += sx } - end - if @_loop_animation_sprites - 16.times { |i| @_loop_animation_sprites[i].x += sx } - end - end - - def y=(y) - sy = y - self.y - return if sy == 0 - if @_animation_sprites - 16.times { |i| @_animation_sprites[i].y += sy } - end - if @_loop_animation_sprites - 16.times { |i| @_loop_animation_sprites[i].y += sy } - end - end -end - -#=============================================================================== -# +# Additions to class Sprite that allows class AnimationContainerSprite to attach +# overworld animations to itself. #=============================================================================== module RPG class Sprite < ::Sprite diff --git a/Data/Scripts/005_Sprites/008_Sprite_AnimationSprite.rb b/Data/Scripts/005_Sprites/008_Sprite_AnimationSprite.rb index 0c63008a..05eadab8 100644 --- a/Data/Scripts/005_Sprites/008_Sprite_AnimationSprite.rb +++ b/Data/Scripts/005_Sprites/008_Sprite_AnimationSprite.rb @@ -1,15 +1,270 @@ #=============================================================================== -# A sprite whose sole purpose is to display an animation. This sprite can be -# displayed anywhere on the map and is disposed automatically when its animation -# is finished. Used for grass rustling and so forth. +# #=============================================================================== -class AnimationSprite < RPG::Sprite +class SpriteAnimation + @@_animations = [] + @@_reference_count = {} + + def initialize(sprite) + @sprite = sprite + end + + def x(*arg); @sprite.x(*arg); end + def y(*arg); @sprite.y(*arg); end + def ox(*arg); @sprite.ox(*arg); end + def oy(*arg); @sprite.oy(*arg); end + def viewport(*arg); @sprite.viewport(*arg); end + def flash(*arg); @sprite.flash(*arg); end + def src_rect(*arg); @sprite.src_rect(*arg); end + def opacity(*arg); @sprite.opacity(*arg); end + def tone(*arg); @sprite.tone(*arg); end + + def self.clear + @@_animations.clear + end + + def dispose + dispose_animation + dispose_loop_animation + end + + def animation(animation, hit, height = 3) + dispose_animation + @_animation = animation + return if @_animation.nil? + @_animation_hit = hit + @_animation_height = height + @_animation_duration = @_animation.frame_max + @_animation_index = -1 + fr = 20 + if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/] + fr = $~[1].to_i + end + @_animation_time_per_frame = 1.0 / fr + @_animation_timer_start = System.uptime + animation_name = @_animation.animation_name + animation_hue = @_animation.animation_hue + bitmap = pbGetAnimation(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 || !@@_animations.include?(animation) + 16.times do + sprite = ::Sprite.new(self.viewport) + sprite.bitmap = bitmap + sprite.visible = false + @_animation_sprites.push(sprite) + end + @@_animations.push(animation) unless @@_animations.include?(animation) + end + update_animation + end + + def loop_animation(animation) + return if animation == @_loop_animation + dispose_loop_animation + @_loop_animation = animation + return if @_loop_animation.nil? + @_loop_animation_duration = @_animation.frame_max + @_loop_animation_index = -1 + fr = 20 + if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/] + fr = $~[1].to_i + end + @_loop_animation_time_per_frame = 1.0 / fr + @_loop_animation_timer_start = System.uptime + animation_name = @_loop_animation.animation_name + animation_hue = @_loop_animation.animation_hue + bitmap = pbGetAnimation(animation_name, animation_hue) + if @@_reference_count.include?(bitmap) + @@_reference_count[bitmap] += 1 + else + @@_reference_count[bitmap] = 1 + end + @_loop_animation_sprites = [] + 16.times do + sprite = ::Sprite.new(self.viewport) + sprite.bitmap = bitmap + sprite.visible = false + @_loop_animation_sprites.push(sprite) + end + update_loop_animation + end + + def dispose_animation + return if @_animation_sprites.nil? + sprite = @_animation_sprites[0] + if sprite + @@_reference_count[sprite.bitmap] -= 1 + sprite.bitmap.dispose if @@_reference_count[sprite.bitmap] == 0 + end + @_animation_sprites.each { |s| s.dispose } + @_animation_sprites = nil + @_animation = nil + @_animation_duration = 0 + end + + def dispose_loop_animation + return if @_loop_animation_sprites.nil? + sprite = @_loop_animation_sprites[0] + if sprite + @@_reference_count[sprite.bitmap] -= 1 + sprite.bitmap.dispose if @@_reference_count[sprite.bitmap] == 0 + end + @_loop_animation_sprites.each { |s| s.dispose } + @_loop_animation_sprites = nil + @_loop_animation = nil + end + + def active? + return @_loop_animation_sprites || @_animation_sprites + end + + def effect? + return @_animation_duration > 0 + end + + def update + update_animation if @_animation + update_loop_animation if @_loop_animation + end + + def update_animation + new_index = ((System.uptime - @_animation_timer_start) / @_animation_time_per_frame).to_i + if new_index >= @_animation_duration + dispose_animation + return + end + quick_update = (@_animation_index == new_index) + @_animation_index = new_index + frame_index = @_animation_index + cell_data = @_animation.frames[frame_index].cell_data + position = @_animation.position + animation_set_sprites(@_animation_sprites, cell_data, position, quick_update) + return if quick_update + @_animation.timings.each do |timing| + next if timing.frame != frame_index + animation_process_timing(timing, @_animation_hit) + end + end + + def update_loop_animation + new_index = ((System.uptime - @_loop_animation_timer_start) / @_loop_animation_time_per_frame).to_i + new_index %= @_loop_animation_duration + quick_update = (@_loop_animation_index == new_index) + @_loop_animation_index = new_index + frame_index = @_loop_animation_index + cell_data = @_loop_animation.frames[frame_index].cell_data + position = @_loop_animation.position + animation_set_sprites(@_loop_animation_sprites, cell_data, position, quick_update) + return if quick_update + @_loop_animation.timings.each do |timing| + next if timing.frame != frame_index + animation_process_timing(timing, true) + end + end + + def animation_set_sprites(sprites, cell_data, position, quick_update = false) + sprite_x = 320 + sprite_y = 240 + if position == 3 # Screen + if self.viewport + sprite_x = self.viewport.rect.width / 2 + sprite_y = self.viewport.rect.height - 160 + end + else + sprite_x = self.x - self.ox + (self.src_rect.width / 2) + sprite_y = self.y - self.oy + if self.src_rect.height > 1 + sprite_y += self.src_rect.height / 2 if position == 1 # Middle + sprite_y += self.src_rect.height if position == 2 # Bottom + end + end + 16.times do |i| + sprite = sprites[i] + pattern = cell_data[i, 0] + if sprite.nil? || pattern.nil? || pattern == -1 + sprite.visible = false if sprite + next + end + sprite.x = sprite_x + cell_data[i, 1] + sprite.y = sprite_y + cell_data[i, 2] + next if quick_update + sprite.visible = true + sprite.src_rect.set((pattern % 5) * 192, (pattern / 5) * 192, 192, 192) + case @_animation_height + when 0 then sprite.z = 1 + when 1 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3 / 2) + 1 + when 2 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3) + 1 + else sprite.z = 2000 + end + sprite.ox = 96 + sprite.oy = 96 + sprite.zoom_x = cell_data[i, 3] / 100.0 + sprite.zoom_y = cell_data[i, 3] / 100.0 + sprite.angle = cell_data[i, 4] + sprite.mirror = (cell_data[i, 5] == 1) + sprite.tone = self.tone + sprite.opacity = cell_data[i, 6] * self.opacity / 255.0 + sprite.blend_type = cell_data[i, 7] + end + end + + def animation_process_timing(timing, hit) + if timing.condition == 0 || + (timing.condition == 1 && hit == true) || + (timing.condition == 2 && hit == false) + if timing.se.name != "" + se = timing.se + pbSEPlay(se) + end + case timing.flash_scope + when 1 + self.flash(timing.flash_color, timing.flash_duration * 2) + when 2 + self.viewport.flash(timing.flash_color, timing.flash_duration * 2) if self.viewport + when 3 + self.flash(nil, timing.flash_duration * 2) + end + end + end + + def x=(x) + sx = x - self.x + return if sx == 0 + if @_animation_sprites + 16.times { |i| @_animation_sprites[i].x += sx } + end + if @_loop_animation_sprites + 16.times { |i| @_loop_animation_sprites[i].x += sx } + end + end + + def y=(y) + sy = y - self.y + return if sy == 0 + if @_animation_sprites + 16.times { |i| @_animation_sprites[i].y += sy } + end + if @_loop_animation_sprites + 16.times { |i| @_loop_animation_sprites[i].y += sy } + end + end +end + +#=============================================================================== +# A sprite whose sole purpose is to display an animation (a SpriteAnimation). +# This sprite can be displayed anywhere on the map and is disposed automatically +# when its animation is finished. Used for grass rustling and so forth. +#=============================================================================== +class AnimationContainerSprite < RPG::Sprite def initialize(animID, map, tileX, tileY, viewport = nil, tinting = false, height = 3) super(viewport) @tileX = tileX @tileY = tileY - self.bitmap = Bitmap.new(1, 1) - self.bitmap.clear @map = map setCoords pbDayNightTint(self) if tinting @@ -23,17 +278,11 @@ class AnimationSprite < RPG::Sprite self.y += Game_Map::TILE_HEIGHT end - def dispose - self.bitmap.dispose - super - end - def update - if !self.disposed? - setCoords - super - self.dispose if !self.effect? - end + return if disposed? + setCoords + super + dispose if !effect? end end @@ -53,7 +302,7 @@ class Spriteset_Map end def addUserAnimation(animID, x, y, tinting = false, height = 3) - sprite = AnimationSprite.new(animID, self.map, x, y, @@viewport1, tinting, height) + sprite = AnimationContainerSprite.new(animID, self.map, x, y, @@viewport1, tinting, height) addUserSprite(sprite) return sprite end @@ -77,5 +326,6 @@ class Spriteset_Map @@viewport3.tone.set(0, 0, 0, 0) _animationSprite_update @usersprites.each { |sprite| sprite.update if !sprite.disposed? } + @usersprites.delete_if { |sprite| sprite.disposed? } end end diff --git a/Data/Scripts/007_Objects and windows/007_BitmapSprite.rb b/Data/Scripts/007_Objects and windows/007_BitmapSprite.rb index 6ce24838..c19283a8 100644 --- a/Data/Scripts/007_Objects and windows/007_BitmapSprite.rb +++ b/Data/Scripts/007_Objects and windows/007_BitmapSprite.rb @@ -59,7 +59,7 @@ class AnimatedSprite < Sprite self.frame = 0 end - # Shorter version of AnimationSprite. All frames are placed on a single row + # Shorter version of AnimatedSprite. All frames are placed on a single row # of the bitmap, so that the width and height need not be defined beforehand. # frameskip is in 1/20ths of a second, and is the time between frame changes. def initializeShort(animname, framecount, frameskip) diff --git a/Data/Scripts/009_Scenes/002_EventScene.rb b/Data/Scripts/009_Scenes/002_EventScene.rb index 07f1c594..aacd9694 100644 --- a/Data/Scripts/009_Scenes/002_EventScene.rb +++ b/Data/Scripts/009_Scenes/002_EventScene.rb @@ -162,6 +162,7 @@ class EventScene next if !sprite || sprite.disposed? || !sprite.is_a?(Sprite) sprite.update end + @usersprites.delete_if { |sprite| sprite.disposed? } @onUpdate.trigger(self) if Input.trigger?(Input::BACK) @onBTrigger.trigger(self)