Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- =begin
- Animated Image Class
- Made by: Sixth
- Usage:
- You can show an animated image with this:
- AnimatedImage.new(data,viewport,folder)
- The viewport is the viewport of the image. It can be nil (so you can omit it).
- The folder is the folder where the image-sheet is.
- If you omit it, a default one will be used. It should be obvious what is the
- default value. :P
- And the data is the actual data of the image. It must be a hash with this
- layout:
- {
- :img => "image name",
- :opa => value,
- :z => value,
- :cols => number,
- :rows => number,
- :frames => [index1, index2, ...],
- :wait => frames,
- }
- :img = The file name of the image-sheet.
- :opa = The opacity of the image.
- :z = The Z level of the image.
- :cols = The number of columns on your image-sheet. Horizontal sheets only!
- :rows = The number of rows on your image-sheet. Vertical sheets only!
- :frames = The animation order. Each picture on your image-sheet is numbered.
- This number is the index of the picture on the sheet.
- 0 being the first one (top one for vertical, leftmost one for
- horizontal sheets), 1 being the second, and so on.
- You can re-use these frame indexes as many times as you want!
- You can also add as many frames as you want!
- Once the full animation is played (all frames were displayed) it will
- start from the beginning!
- :wait = The number of frames (in time) to wait between changing the displayed
- image frame. In other words, this will determine the speed of the
- animation.
- And this is it.
- When you make an instance of AnimatedImage, you will, of course, need to
- update it or else it won't be animated.
- I used this class in many of my scripts.
- Feel free to use it if you want for any project.
- Kindly credit me if you do use it, okay? :P
- =end
- # Image-sheet information (copy/pasted from one of my scripts):
- # The image-sheet must follow some rules or else the animation will look
- # weird or flat out bad.
- # These rules are:
- # - The animation frames must be lined up vertically or horizontally
- # on the sprite-sheet.
- # - These frames are indexed, and these indexes are used in the animation
- # settings in the script.
- # The first image frame's index is 0 (top one for horizontal sheets and
- # left-most one for vertical sheets), the second is 1, and so on!
- # - All frames on the sprite-sheet must use the same dimensions!
- # If the 1st frame is 32x32 (width x height), all the others must use the
- # same dimensions!
- # - A sprite-sheet can have unlimited number of frames!
- # * A little visual representation showing the index numbers of the image
- # frames on a sprite-sheet:
- # - Correct sprite-sheet: - Incorrect sprite-sheet:
- # * Same frame dimensions! * Different frame dimensions!
- # ----- ----------------- ----- -------------------
- # | 0 | | 0 | 1 | 2 | 3 | | 0 | | 0 | 1 | 2 | 3 |
- # ----- ----------------- ----- -------------------
- # | 1 | Horizontal | 1 | Horizontal
- # ----- Sheet | | Sheet
- # | 2 | -----
- # ----- Vertical | 2 | Vertical
- # | 3 | Sheet | | Sheet
- # ----- -----
- class AnimatedImage
- def initialize(data,view=nil,fold="Graphics/Pictures/")
- @data = data # The image and animation data.
- @view = view # The viewport used. Not necessary.
- @folder = fold # The folder where the images is read from.
- @counter = @pattern = 0 # Animation counters.
- @anim = {} # Real animation container (database animations).
- init_sprite(view) # Initializing the image.
- end
- def init_sprite(view=nil)
- @img = Sprite.new(view) # Making the sprite. Only once.
- setup_bitmap # Setting up the bitmap (the image itself).
- end
- # This method will setup the bitmap of this sprite.
- # Will account for the type of the image-sheet used (horizontal or vertical).
- def setup_bitmap
- @img.bitmap = Cache.custom_imgs(@data[:img],@folder).clone # Note the clone!
- @img.opacity = @data[:opa]
- @img.z = @data[:z]
- if @data[:cols] # If the image sheet is horizontal (more columns) we move the rect's X position.
- @img.src_rect.width = @img.bitmap.width/@data[:cols]
- @img.ox = @img.src_rect.width/2 # Centering horizontally.
- @img.oy = @img.bitmap.height/2 # Centering vertically.
- @img.src_rect.x = @data[:frames][@pattern] * @img.src_rect.width
- else # If the image sheet is vertical (more rows) we move the rect's Y position.
- @img.src_rect.height = @img.bitmap.height/@data[:rows] # Getting the height of one image frame from the sheet.
- @img.oy = @img.src_rect.height/2 # Centering vertically.
- @img.ox = @img.bitmap.width/2 # Centering horizontally.
- @img.src_rect.y = @data[:frames][@pattern] * @img.src_rect.height # Setting the initial frame.
- end
- end
- # Some shortcut methods. Not mandatory.
- def x; return @img.x; end
- def x=(val); @img.x = val; end
- def y; return @img.y; end
- def y=(val); @img.y = val; end
- def ox; return @img.ox; end
- def oy; return @img.oy; end
- def img; return @img; end
- # Method for changing the image/animation data on the fly if needed.
- # Only IF needed, you should NOT use this unless you really need it!
- # Disposing and loading bitmaps a lot of times in a short interval might
- # impact performance!
- # Not mandatory.
- #
- # Arguments:
- #
- # data = The image data.
- # folder = Optional! I won't explain this one any more. :P
- def change_image(data,folder=nil)
- @folder = folder if folder
- @data = data
- @counter = @pattern = 0
- @img.bitmap.dispose if @img.bitmap && !@img.bitmap.disposed?
- setup_bitmap
- end
- # Shortcut method for starting a flash effect on the image. Not mandatory.
- #
- # Arguments:
- #
- # col = A color object. Sample: Color.new(R,G,B,A)
- # dur = The duration of the flash effect.
- def start_flash(col,dur)
- @img.flash(col,dur)
- end
- # A method to display database animations on the displayed image.
- # It can be set to follow a target as well (the target can be any other object
- # which got an X and Y instance variable).
- # If it is set to follow without a target set, it will follow this image!
- #
- # Arguments:
- #
- # type = A unique identifier of the animation.
- # If you use the same identifier as another, already playing
- # animation, it won't play your new animation!
- # At any given time, only one animation can be played with the same
- # type identifier!
- # This can be anything from numbers to strings and symbols or arrays
- # of data!
- # anim_id = Should be obvious, this is the database ID of the animation.
- # target = This is the target of the animation. Optional argument!
- # If omitted, the animation will be played on this image.
- # If set to something, the animation will be played on this object!
- # follow = This will make the animation follow the target. Optional argument!
- #
- def set_anim(type,anim_id,target=nil,follow=false)
- return if @anim[type] && !@anim[type].disposed?
- @anim[type] = QuickAnim.new(@view)
- @anim[type].x = target ? target.x : @img.x
- @anim[type].y = target ? target.y : @img.y
- @anim[type].z = @img.z
- if follow
- if target
- @anim[type].set_target(target)
- else
- @anim[type].set_target(@img)
- end
- end
- @anim[type].start_animation($data_animations[anim_id])
- end
- # The update method, updating everthing it should.
- def update
- @img.update # Updating the image (for flash effects and others).
- update_sprite_frames # Updating the image animation (from the image-sheet).
- update_animations # Updating the database animations (if any).
- end
- # The image-sheet animation.
- # It advances the counter by one, and if the required number of frames have
- # been passed (the :wait setting from the data), it advances to the next
- # image frame.
- # Depending on the type of the image-sheet (horizontal or vertical), it moves
- # the rect of the sprite on the X or Y axis (src_rect.x or src_rect.y)!
- # This is what you asked in the topic actually, an effective way of animating
- # something using an image-sheet.
- def update_sprite_frames
- @counter += 1
- if @counter % @data[:wait] == 0
- @pattern += 1
- @pattern = 0 if @pattern >= @data[:frames].size
- if @data[:cols]
- @img.src_rect.x = @data[:frames][@pattern] * @img.src_rect.width
- else
- @img.src_rect.y = @data[:frames][@pattern] * @img.src_rect.height
- end
- end
- end
- # This will update the database animations if there is any displayed.
- # This is entirely optional, not really something you should use unless you
- # really need to. I used this in my shooter engine and was too lazy to remove.
- def update_animations
- @anim.each do |ky,an|
- next if an.nil?
- if an.animation?
- an.update
- else
- an.dispose
- @anim[ky] = nil
- end
- end
- end
- # Check for disposal.
- # Can be used to check if the image has been disposed or not, obviously.
- # You don't need to use this many times (if ever).
- def disposed?
- return @img.disposed?
- end
- # The dispose method.
- # Disposes the image and any database animations that might be playing.
- def dispose
- @anim.each_value {|an| an.dispose if !an.nil? && !an.disposed?}
- @img.bitmap.dispose
- @img.dispose
- end
- end
- # The class below is a quick class for playing animations.
- # Not much different from the Sprite_Base class, just added some methods for
- # following a target and to show the animation on a specified position.
- # I won't explain this class, because it is not the subject of your topic. :P
- # This is just a little extra which was already included in my code, so I
- # didn't want to remove it. Use it if you want, don't if you don't want.
- class QuickAnim < Sprite_Base
- def initialize(viewport=nil,pos=nil)
- super(viewport)
- if pos
- self.x = pos[0]
- self.y = pos[1]
- end
- @use_sprite = true
- @ani_duration = 0
- end
- def set_target(target,set_pos=true)
- @target = target
- return unless set_pos
- self.x = target.x
- self.y = target.y
- end
- def update
- super
- if !self.disposed? && @target && !@target.disposed?
- update_follow_target
- end
- end
- def update_follow_target
- xx = @target.x - self.x
- yy = @target.y - self.y
- self.x = @target.x
- self.y = @target.y
- move_animation2(xx,yy)
- end
- def move_animation2(dx, dy)
- if @animation && @animation.position != 3
- @ani_ox += dx
- @ani_oy += dy
- @ani_sprites.each do |sprite|
- sprite.x += dx
- sprite.y += dy
- end
- end
- end
- def animation_process_timing(timing)
- super
- return unless @target && !@target.disposed?
- case timing.flash_scope
- when 1
- @target.flash(timing.flash_color, timing.flash_duration * @ani_rate)
- when 3
- @target.flash(nil, timing.flash_duration * @ani_rate)
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement