Minor lag improvements to overworld animations

This commit is contained in:
Maruno17
2023-11-05 16:15:41 +00:00
parent 156a6fca74
commit f07b44d826
4 changed files with 271 additions and 276 deletions

View File

@@ -1,262 +1,6 @@
#=============================================================================== #===============================================================================
# # Additions to class Sprite that allows class AnimationContainerSprite to attach
#=============================================================================== # overworld animations to itself.
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
#===============================================================================
#
#=============================================================================== #===============================================================================
module RPG module RPG
class Sprite < ::Sprite class Sprite < ::Sprite

View File

@@ -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) def initialize(animID, map, tileX, tileY, viewport = nil, tinting = false, height = 3)
super(viewport) super(viewport)
@tileX = tileX @tileX = tileX
@tileY = tileY @tileY = tileY
self.bitmap = Bitmap.new(1, 1)
self.bitmap.clear
@map = map @map = map
setCoords setCoords
pbDayNightTint(self) if tinting pbDayNightTint(self) if tinting
@@ -23,17 +278,11 @@ class AnimationSprite < RPG::Sprite
self.y += Game_Map::TILE_HEIGHT self.y += Game_Map::TILE_HEIGHT
end end
def dispose
self.bitmap.dispose
super
end
def update def update
if !self.disposed? return if disposed?
setCoords setCoords
super super
self.dispose if !self.effect? dispose if !effect?
end
end end
end end
@@ -53,7 +302,7 @@ class Spriteset_Map
end end
def addUserAnimation(animID, x, y, tinting = false, height = 3) 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) addUserSprite(sprite)
return sprite return sprite
end end
@@ -77,5 +326,6 @@ class Spriteset_Map
@@viewport3.tone.set(0, 0, 0, 0) @@viewport3.tone.set(0, 0, 0, 0)
_animationSprite_update _animationSprite_update
@usersprites.each { |sprite| sprite.update if !sprite.disposed? } @usersprites.each { |sprite| sprite.update if !sprite.disposed? }
@usersprites.delete_if { |sprite| sprite.disposed? }
end end
end end

View File

@@ -59,7 +59,7 @@ class AnimatedSprite < Sprite
self.frame = 0 self.frame = 0
end 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. # 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. # frameskip is in 1/20ths of a second, and is the time between frame changes.
def initializeShort(animname, framecount, frameskip) def initializeShort(animname, framecount, frameskip)

View File

@@ -162,6 +162,7 @@ class EventScene
next if !sprite || sprite.disposed? || !sprite.is_a?(Sprite) next if !sprite || sprite.disposed? || !sprite.is_a?(Sprite)
sprite.update sprite.update
end end
@usersprites.delete_if { |sprite| sprite.disposed? }
@onUpdate.trigger(self) @onUpdate.trigger(self)
if Input.trigger?(Input::BACK) if Input.trigger?(Input::BACK)
@onBTrigger.trigger(self) @onBTrigger.trigger(self)