Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Trickster's Animated Sprite class

Okay In a recent CMS i made i would like to have the sprite animated.
Trick gave me this script;
Code:
#============================================================================== 
# ** Sprite_ActorCharGraphic (BETA)                                By Trickster
#-----------------------------------------------------------------------------
#  A Sprite Class that represents an actor character graphic. Also Handles a few
#  Graphical methods and animation. The Z coordinate is, by default,
#  in between the window and its contents for easy integration in a window.
#============================================================================== 
class Sprite_ActorCharGraphic < Sprite
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :speed
  attr_reader :frame
  attr_reader :pose
     # Pose Names
   POSES = ['down','left','right','up']
   # Number of Frames Per Pose
   FRAMES = 4
  #-------------------------------------------------------------------------
  # * Name:      Object Initialization
  #   Info:      Creates a New Instance of this Class
  #   Author:    Trickster
  #   Call Info: Three or Seven Arguments
  #              Game_Actor actor, Actor's Sprite to Display
  #              Integer X and Y, Position to Display
  #              Integer Speed, Speed of animation (Def 1)
  #              Integer Frame, Starting frame (Def. nil)
  #              String/Integer Pose, Pose Type/Pose Index (Def. nil)
  #              Viewport viewport, Viewport used (Def. nil)
  #-------------------------------------------------------------------------
  def initialize(actor, x, y, speed = 1, frame = nil, pose = nil, viewport = nil)
    super(viewport)
    @actor = actor
    self.x = x
    self.y = y
    self.z = 101
    self.speed = speed
    self.bitmap = RPG::Cache.character(actor.character_name, actor.character_hue)
    @name, @hue, @animate = @actor.character_name, @actor.character_hue, false
    pose = POSES.index(pose) if pose.is_a?(String)
    self.pose, self.frame = pose, frame
    @count = 0
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Graphic
  #   Info:      Sets Graphic to (Frame, Pose)
  #   Author:    Trickster
  #   Call Info: Two Arguments 
  #              Integer Frame, Frame
  #              String/Integer Pose, Pose Type/Pose Index 
  #-------------------------------------------------------------------------
  def set_graphic(pose,frame)
    pose = POSES.index(pose) if pose.is_a?(String)
    return if @pose == pose and @frame == frame
    self.src_rect.x = self.bitmap.width / FRAMES * frame
    self.src_rect.y = self.bitmap.height / POSES.size * pose
    self.src_rect.width = self.bitmap.width / FRAMES
    self.src_rect.height = self.bitmap.height / POSES.size
    @pose, @frame = pose, frame
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Pose
  #   Info:      Sets The Pose
  #   Author:    Trickster
  #   Call Info: One Argument, String/Integer Pose Pose Type/Pose Index
  #-------------------------------------------------------------------------
  def pose=(pose)
    pose = POSES.index(pose) if pose.is_a?(String)
    return if pose == nil or pose == @pose
    self.src_rect.y = self.bitmap.height / POSES.size * pose
    self.src_rect.height = self.bitmap.height / POSES.size
    @pose = pose
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Frame
  #   Info:      Sets the Frame
  #   Author:    Trickster
  #   Call Info: One Argument, Integer Frame, Frame to set
  #-------------------------------------------------------------------------
  def frame=(frame)
    return if frame == nil or frame == @frame
    self.src_rect.x = self.bitmap.width / FRAMES * frame
    self.src_rect.width = self.bitmap.width / FRAMES
    @frame = frame
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Animate
  #   Info:      Set Animation flag
  #   Author:    Trickster
  #   Call Info: One Argument, Boolean bool, True (On) False (Off)
  #-------------------------------------------------------------------------
  def animate=(bool)
    @animate = bool
  end
  #-------------------------------------------------------------------------
  # * Name:      Frame Update
  #   Info:      Update Animation if enabled, Updates Graphic
  #   Author:    Trickster
  #   Call Info: No Arguments
  #-------------------------------------------------------------------------
  def update
    super
    update_graphic
    return if not @animate or [@pose, @frame].include?(nil)
    @count += 1
    return if @count % @speed != 0
    self.frame = (self.frame + 1) % FRAMES
  end
  #-------------------------------------------------------------------------
  # * Name:      Update Graphic (Private)
  #   Info:      Private Method, Updates Actor Graphic
  #   Author:    Trickster
  #   Call Info: No Arguements, can not be called outside this class
  #-------------------------------------------------------------------------
  private
  def update_graphic
    if @name != @actor.character_name or @hue != @actor.character_hue
      self.bitmap = RPG::Cache.character(actor.character_name, actor.character_hue)
      @name, @hue = @actor.character_name, @actor.character_hue
    end
  end
end

I have tried to mae the sprite show by using;
Sprite_ActorCharGraphic($game_actors[1], 10, 10, 4, 0, 'down')

I get this error when opening the CMS or with trying the code in other scenes.
http://img139.imageshack.us/img139/3965/erroruk9.png[/IMG]

BTW, Sorry for the bother on Mirc Trickster :)
 
You have to call this way:
Code:
[B]@sprite = [/B]Sprite_ActorCharGraphic[B].new[/B]($game_actors[1], 10, 10, 4, 0, 'down')
don't forget do dispose this sprite when closing your scene (unless if you are using SDK::Scene_Base)
Code:
@sprite.dispose
 
Here use this version

Code:
#============================================================================== 
# ** Sprite_ActorCharGraphic (BETA)                                By Trickster
#-----------------------------------------------------------------------------
#  A Sprite Class that represents an actor character graphic. Also Handles a few
#  Graphical methods and animation. The Z coordinate is, by default,
#  in between the window and its contents for easy integration in a window.
#============================================================================== 
class Sprite_ActorCharGraphic < Sprite
  #-------------------------------------------------------------------------
  # * Constants
  #-------------------------------------------------------------------------
  # Pose Names
  POSES = ['down','left','right','up']
  # Number of Frames Per Pose
  FRAMES = 4
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :speed
  attr_reader :frame
  attr_reader :pose
  #-------------------------------------------------------------------------
  # * Name:      Object Initialization
  #   Info:      Creates a New Instance of this Class
  #   Author:    Trickster
  #   Call Info: Three or Seven Arguments
  #              Game_Actor actor, Actor's Sprite to Display
  #              Integer X and Y, Position to Display
  #              Integer Speed, Speed of animation (Def 1)
  #              Integer Frame, Starting frame (Def. nil)
  #              String/Integer Pose, Pose Type/Pose Index (Def. nil)
  #              Viewport viewport, Viewport used (Def. nil)
  #-------------------------------------------------------------------------
  def initialize(actor, x, y, speed = 1, frame = nil, pose = nil, viewport = nil)
    super(viewport)
    @actor = actor
    self.x = x
    self.y = y
    self.z = 101
    self.speed = speed
    self.bitmap = RPG::Cache.character(actor.character_name, actor.character_hue)
    @name, @hue, @animate = @actor.character_name, @actor.character_hue, false
    pose = POSES.index(pose) if pose.is_a?(String)
    self.pose, self.frame = pose, frame
    @count = 0
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Graphic
  #   Info:      Sets Graphic to (Frame, Pose)
  #   Author:    Trickster
  #   Call Info: Two Arguments 
  #              Integer Frame, Frame
  #              String/Integer Pose, Pose Type/Pose Index 
  #-------------------------------------------------------------------------
  def set_graphic(pose,frame)
    pose = POSES.index(pose) if pose.is_a?(String)
    return if @pose == pose and @frame == frame
    self.src_rect.x = self.bitmap.width / FRAMES * frame
    self.src_rect.y = self.bitmap.height / POSES.size * pose
    self.src_rect.width = self.bitmap.width / FRAMES
    self.src_rect.height = self.bitmap.height / POSES.size
    @pose, @frame = pose, frame
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Pose
  #   Info:      Sets The Pose
  #   Author:    Trickster
  #   Call Info: One Argument, String/Integer Pose Pose Type/Pose Index
  #-------------------------------------------------------------------------
  def pose=(pose)
    pose = POSES.index(pose) if pose.is_a?(String)
    return if pose == nil or pose == @pose
    self.src_rect.y = self.bitmap.height / POSES.size * pose
    self.src_rect.height = self.bitmap.height / POSES.size
    @pose = pose
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Frame
  #   Info:      Sets the Frame
  #   Author:    Trickster
  #   Call Info: One Argument, Integer Frame, Frame to set
  #-------------------------------------------------------------------------
  def frame=(frame)
    return if frame == nil or frame == @frame
    self.src_rect.x = self.bitmap.width / FRAMES * frame
    self.src_rect.width = self.bitmap.width / FRAMES
    @frame = frame
  end
  #-------------------------------------------------------------------------
  # * Name:      Set Animate
  #   Info:      Set Animation flag
  #   Author:    Trickster
  #   Call Info: One Argument, Boolean bool, True (On) False (Off)
  #-------------------------------------------------------------------------
  def animate=(bool)
    @animate = bool
  end
  #-------------------------------------------------------------------------
  # * Name:      Frame Update
  #   Info:      Update Animation if enabled, Updates Graphic
  #   Author:    Trickster
  #   Call Info: No Arguments
  #-------------------------------------------------------------------------
  def update
    super
    update_graphic
    return if not @animate or [@pose, @frame].include?(nil)
    @count += 1
    return if @count % @speed != 0
    self.frame = (self.frame + 1) % FRAMES
  end
  #-------------------------------------------------------------------------
  # * Name:      Update Graphic (Private)
  #   Info:      Private Method, Updates Actor Graphic
  #   Author:    Trickster
  #   Call Info: No Arguements, can not be called outside this class
  #-------------------------------------------------------------------------
  private
  def update_graphic
    if @name != @actor.character_name or @hue != @actor.character_hue
      self.bitmap = RPG::Cache.character(actor.character_name, actor.character_hue)
      @name, @hue = @actor.character_name, @actor.character_hue
    end
  end
end


Now as I told you read my method headers they shouldn't be that hard to figure out what to do if you read them

Also if you are going to use this in a window that moves, changes visibility, scrolls or whatever. Then get my window_sprites script and after you created your sprite object just do

Code:
@window_sprites << <Sprite>

where <Sprite> is a sprite (or any class that is a child of the Sprite class)

Also after adding the sprite to the window_sprites array there is no need to update or dispose the sprite the script automatically takes care of this for you.
 
@Trickster
I've writed this small script (based on your gradient bars) to replace Window_Base#draw_actor_graphic using this class. I hope you don't mind it.
Code:
class Window_Base
  #-------------------------------------------------------------------------
  alias_method :tibuda_animchars_winbase_initialize, :initialize
  def initialize(*args)
    # Setup Sprites Hash
    @char_sprites = {}
    # The Usual
    tibuda_animchars_winbase_initialize(*args)
  end
  #-------------------------------------------------------------------------
  def draw_actor_graphic(actor, x, y, animated = true)
    bitmap = RPG::Cache.character(actor.character_name, actor.character_hue)
    cw = bitmap.width / 4
    ch = bitmap.height / 4
    src_rect = Rect.new(0, 0, cw, ch)
    if @char_sprites[actor].nil?
      # Setup the coords
      draw_x, draw_y = self.x + x - self.ox - cw / 2 + 16, self.y + y - self.oy + 16 - ch
      # Create Sprite
      sprite = Sprite_ActorCharGraphic.new(actor, draw_x, draw_y, 8, 0, 'down', self.viewport)
      sprite.animate = animated
      # Get Z
      z = self.z
      # Set Visibility
      sprite.visible = (sprite.x.between?(self.x + 16, self.x + self.width - 16) &&
        sprite.y.between?(self.y + 16, self.y + self.height - 16))
      # Set Z
      sprite.z = z
      # Set Reference
      @char_sprites[actor] = sprite
      # Add Sprite to Window Sprites
      @window_sprites << sprite
    end
  end
  #-------------------------------------------------------------------------
end
@Prefix
Feel free to use this script, and give Trickster ALL the credits
 
It will automacally replace the characters in the menu for animated ones...
And any script using the method draw_actor_graphic will be animated too...
I'm working on a edit to animate the load and save scenes (too bad that in these scenes enterbrain didnt used the method)...
EDIT: this will animate Window_SaveFile (all scripters are hunting me by now, but these method are really hard to alias)
Code:
class Window_SaveFile
  #--------------------------------------------------------------------------
  if @tibuda_animchars_savefile.nil?
    alias_method :tibuda_animchars_winsave_selected=, :selected=
    @tibuda_animchars_savefile = true
  end
  #--------------------------------------------------------------------------
  def initialize(file_index, filename)
    super(0, 64 + file_index % 4 * 104, 640, 104)
    self.contents = Bitmap.new(width - 32, height - 32)
    @file_index = file_index
    @filename = "Save#{@file_index + 1}.rxdata"
    @time_stamp = Time.at(0)
    @file_exist = FileTest.exist?(@filename)
    if @file_exist
      file = File.open(@filename, "r")
      @time_stamp         = file.mtime
      @characters         = Marshal.load(file)
      @frame_count        = Marshal.load(file)
      @game_system        = Marshal.load(file)
      @game_switches      = Marshal.load(file)
      @game_variables     = Marshal.load(file)
      @game_self_switches = Marshal.load(file)
      @game_screen        = Marshal.load(file)
      @game_actors        = Marshal.load(file)
      @game_party         = Marshal.load(file)
#      @game_troop         = Marshal.load(file)
#      @game_map           = Marshal.load(file)
#      @game_player        = Marshal.load(file)
      @total_sec = @frame_count / Graphics.frame_rate
      file.close
    end
    refresh
    @selected = false
  end
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    # Draw file number
    self.contents.font.color = normal_color
    name = "File#{@file_index + 1}"
    self.contents.draw_text(4, 0, 600, 32, name)
    @name_width = contents.text_size(name).width
    # If save file exists
    if @file_exist
      # Draw character
      for i in 0...@game_party.actors.size
        x = 300 - @game_party.actors.size * 32 + i * 64
        draw_actor_graphic(@game_party.actors[i], x, 68)
      end
      # Draw play time
      hour = @total_sec / 60 / 60
      min = @total_sec / 60 % 60
      sec = @total_sec % 60
      time_string = sprintf("%02d:%02d:%02d", hour, min, sec)
      self.contents.font.color = normal_color
      self.contents.draw_text(4, 8, 600, 32, time_string, 2)
      # Draw timestamp
      self.contents.font.color = normal_color
      time_string = @time_stamp.strftime("%Y/%m/%d %H:%M")
      self.contents.draw_text(4, 40, 600, 32, time_string, 2)
    end
  end
  #--------------------------------------------------------------------------
  def selected=(selected)
    self.tibuda_animchars_winsave_selected = selected
    for sprite in @char_sprites.values
      sprite.animate = selected
      sprite.frame = 0 unless selected
    end
  end
  #--------------------------------------------------------------------------
end
 
Should be more like this tibuda

Code:
[CODE]class Window_Base
  #-------------------------------------------------------------------------
  alias_method :tibuda_animchars_winbase_initialize, :initialize
  def initialize(*args)
    # Setup Sprites Hash
    @char_sprites = {}
    # The Usual
    tibuda_animchars_winbase_initialize(*args)
  end
  #-------------------------------------------------------------------------
  def draw_actor_graphic(actor, x, y, animated = true)
    if @char_sprites[actor].nil?
      # Setup the coords
      draw_x, draw_y = self.x + x - self.ox - cw / 2 + 16, self.y + y - self.oy + 16 - ch
      # Create Sprite
      sprite = Sprite_ActorCharGraphic.new(actor, draw_x, draw_y, 8, 0, 'down', self.viewport)
      sprite.animate = animated
      sprite.tag(self)
      # Set Reference
      @char_sprites[actor] = sprite
      # Add Sprite to Window Sprites
      @window_sprites << sprite
    end
  end
  #-------------------------------------------------------------------------
end

This removed unnecessary code and used the tag method of the Sprite class (see new version of window sprites)

but yeah good job
 
But we need to load the bitmap to know the size, and make the right coords...
Code:
 draw_x, draw_y = self.x + x - self.ox - [B]cw[/B] / 2 + 16, self.y + y - self.oy + 16 - [B]ch[/B]
See the bold variables?
and about the tag method, that's really good, I haven't seen it before
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top