Advertisement
TheSixth

Animated Image Class

Jun 6th, 2016
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 11.43 KB | None | 0 0
  1. =begin
  2.  
  3. Animated Image Class
  4. Made by: Sixth
  5.  
  6. Usage:
  7.  
  8. You can show an animated image with this:
  9.  
  10.   AnimatedImage.new(data,viewport,folder)
  11.  
  12. The viewport is the viewport of the image. It can be nil (so you can omit it).
  13.  
  14. The folder is the folder where the image-sheet is.
  15. If you omit it, a default one will be used. It should be obvious what is the
  16. default value. :P
  17.  
  18. And the data is the actual data of the image. It must be a hash with this
  19. layout:
  20.  
  21.  {
  22.    :img => "image name",
  23.    :opa => value,
  24.    :z => value,
  25.    :cols => number,
  26.    :rows => number,
  27.    :frames => [index1, index2, ...],
  28.    :wait => frames,
  29.  }
  30.  
  31.  :img = The file name of the image-sheet.
  32.  :opa = The opacity of the image.
  33.  :z = The Z level of the image.
  34.  
  35.  :cols = The number of columns on your image-sheet. Horizontal sheets only!
  36.  :rows = The number of rows on your image-sheet. Vertical sheets only!
  37.  :frames = The animation order. Each picture on your image-sheet is numbered.
  38.            This number is the index of the picture on the sheet.
  39.            0 being the first one (top one for vertical, leftmost one for
  40.            horizontal sheets), 1 being the second, and so on.
  41.            You can re-use these frame indexes as many times as you want!
  42.            You can also add as many frames as you want!
  43.            Once the full animation is played (all frames were displayed) it will
  44.            start from the beginning!
  45.  :wait = The number of frames (in time) to wait between changing the displayed
  46.          image frame. In other words, this will determine the speed of the
  47.          animation.
  48.          
  49.  And this is it.
  50.  
  51.  When you make an instance of AnimatedImage, you will, of course, need to
  52.  update it or else it won't be animated.
  53.  
  54.  I used this class in many of my scripts.
  55.  Feel free to use it if you want for any project.
  56.  Kindly credit me if you do use it, okay? :P
  57.  
  58. =end
  59.  
  60. # Image-sheet information (copy/pasted from one of my scripts):
  61.  
  62. #   The image-sheet must follow some rules or else the animation will look
  63. #   weird or flat out bad.
  64. #   These rules are:
  65. #   - The animation frames must be lined up vertically or horizontally
  66. #     on the sprite-sheet.
  67. #   - These frames are indexed, and these indexes are used in the animation
  68. #     settings in the script.
  69. #     The first image frame's index is 0 (top one for horizontal sheets and
  70. #     left-most one for vertical sheets), the second is 1, and so on!
  71. #   - All frames on the sprite-sheet must use the same dimensions!
  72. #     If the 1st frame is 32x32 (width x height), all the others must use the
  73. #     same dimensions!
  74. #   - A sprite-sheet can have unlimited number of frames!
  75. # * A little visual representation showing the index numbers of the image
  76. #   frames on a sprite-sheet:
  77. #   - Correct sprite-sheet:             - Incorrect sprite-sheet:
  78. #     * Same frame dimensions!            * Different frame dimensions!
  79. #     -----   -----------------           -----   -------------------
  80. #     | 0 |   | 0 | 1 | 2 | 3 |           | 0 |   | 0 | 1 |  2  | 3 |
  81. #     -----   -----------------           -----   -------------------
  82. #     | 1 |      Horizontal               | 1 |        Horizontal
  83. #     -----        Sheet                  |   |          Sheet
  84. #     | 2 |                               -----
  85. #     -----  Vertical                     | 2 |  Vertical
  86. #     | 3 |    Sheet                      |   |    Sheet
  87. #     -----                               -----
  88.  
  89. class AnimatedImage
  90.  
  91.   def initialize(data,view=nil,fold="Graphics/Pictures/")
  92.     @data = data            # The image and animation data.
  93.     @view = view            # The viewport used. Not necessary.
  94.     @folder = fold          # The folder where the images is read from.
  95.     @counter = @pattern = 0 # Animation counters.
  96.     @anim = {}              # Real animation container (database animations).
  97.     init_sprite(view)       # Initializing the image.
  98.   end
  99.  
  100.   def init_sprite(view=nil)
  101.     @img = Sprite.new(view) # Making the sprite. Only once.
  102.     setup_bitmap            # Setting up the bitmap (the image itself).
  103.   end
  104.      
  105.   # This method will setup the bitmap of this sprite.
  106.   # Will account for the type of the image-sheet used (horizontal or vertical).
  107.   def setup_bitmap
  108.     @img.bitmap = Cache.custom_imgs(@data[:img],@folder).clone # Note the clone!
  109.     @img.opacity = @data[:opa]
  110.     @img.z = @data[:z]
  111.     if @data[:cols] # If the image sheet is horizontal (more columns) we move the rect's X position.
  112.       @img.src_rect.width = @img.bitmap.width/@data[:cols]
  113.       @img.ox = @img.src_rect.width/2 # Centering horizontally.
  114.       @img.oy = @img.bitmap.height/2  # Centering vertically.
  115.       @img.src_rect.x = @data[:frames][@pattern] * @img.src_rect.width
  116.     else # If the image sheet is vertical (more rows) we move the rect's Y position.
  117.       @img.src_rect.height = @img.bitmap.height/@data[:rows] # Getting the height of one image frame from the sheet.
  118.       @img.oy = @img.src_rect.height/2 # Centering vertically.
  119.       @img.ox = @img.bitmap.width/2    # Centering horizontally.
  120.       @img.src_rect.y = @data[:frames][@pattern] * @img.src_rect.height # Setting the initial frame.
  121.     end
  122.   end
  123.  
  124.   # Some shortcut methods. Not mandatory.
  125.   def x; return @img.x; end
  126.   def x=(val); @img.x = val; end
  127.   def y; return @img.y; end
  128.   def y=(val); @img.y = val; end
  129.   def ox; return @img.ox; end
  130.   def oy; return @img.oy; end
  131.   def img; return @img; end
  132.  
  133.   # Method for changing the image/animation data on the fly if needed.
  134.   # Only IF needed, you should NOT use this unless you really need it!
  135.   # Disposing and loading bitmaps a lot of times in a short interval might
  136.   # impact performance!
  137.   # Not mandatory.
  138.   #
  139.   # Arguments:
  140.   #
  141.   # data = The image data.
  142.   # folder = Optional! I won't explain this one any more. :P
  143.   def change_image(data,folder=nil)
  144.     @folder = folder if folder
  145.     @data = data
  146.     @counter = @pattern = 0
  147.     @img.bitmap.dispose if @img.bitmap && !@img.bitmap.disposed?
  148.     setup_bitmap
  149.   end
  150.  
  151.   # Shortcut method for starting a flash effect on the image. Not mandatory.
  152.   #
  153.   # Arguments:
  154.   #
  155.   # col = A color object. Sample: Color.new(R,G,B,A)
  156.   # dur = The duration of the flash effect.
  157.   def start_flash(col,dur)
  158.     @img.flash(col,dur)
  159.   end
  160.  
  161.   # A method to display database animations on the displayed image.
  162.   # It can be set to follow a target as well (the target can be any other object
  163.   # which got an X and Y instance variable).
  164.   # If it is set to follow without a target set, it will follow this image!
  165.   #
  166.   # Arguments:
  167.   #
  168.   #   type = A unique identifier of the animation.
  169.   #          If you use the same identifier as another, already playing
  170.   #          animation, it won't play your new animation!
  171.   #          At any given time, only one animation can be played with the same
  172.   #          type identifier!
  173.   #          This can be anything from numbers to strings and symbols or arrays
  174.   #          of data!
  175.   # anim_id = Should be obvious, this is the database ID of the animation.
  176.   # target = This is the target of the animation. Optional argument!
  177.   #          If omitted, the animation will be played on this image.
  178.   #          If set to something, the animation will be played on this object!
  179.   # follow = This will make the animation follow the target. Optional argument!
  180.   #          
  181.   def set_anim(type,anim_id,target=nil,follow=false)
  182.     return if @anim[type] && !@anim[type].disposed?
  183.     @anim[type] = QuickAnim.new(@view)
  184.     @anim[type].x = target ? target.x : @img.x
  185.     @anim[type].y = target ? target.y : @img.y
  186.     @anim[type].z = @img.z
  187.     if follow
  188.       if target
  189.         @anim[type].set_target(target)
  190.       else
  191.         @anim[type].set_target(@img)
  192.       end
  193.     end
  194.     @anim[type].start_animation($data_animations[anim_id])
  195.   end
  196.  
  197.   # The update method, updating everthing it should.
  198.   def update
  199.     @img.update          # Updating the image (for flash effects and others).
  200.     update_sprite_frames # Updating the image animation (from the image-sheet).
  201.     update_animations    # Updating the database animations (if any).
  202.   end
  203.  
  204.   # The image-sheet animation.
  205.   # It advances the counter by one, and if the required number of frames have
  206.   # been passed (the :wait setting from the data), it advances to the next
  207.   # image frame.
  208.   # Depending on the type of the image-sheet (horizontal or vertical), it moves
  209.   # the rect of the sprite on the X or Y axis (src_rect.x or src_rect.y)!
  210.   # This is what you asked in the topic actually, an effective way of animating
  211.   # something using an image-sheet.
  212.   def update_sprite_frames
  213.     @counter += 1
  214.     if @counter % @data[:wait] == 0
  215.       @pattern += 1
  216.       @pattern = 0 if @pattern >= @data[:frames].size
  217.       if @data[:cols]
  218.         @img.src_rect.x = @data[:frames][@pattern] * @img.src_rect.width
  219.       else
  220.         @img.src_rect.y = @data[:frames][@pattern] * @img.src_rect.height
  221.       end
  222.     end
  223.   end
  224.  
  225.   # This will update the database animations if there is any displayed.
  226.   # This is entirely optional, not really something you should use unless you
  227.   # really need to. I used this in my shooter engine and was too lazy to remove.
  228.   def update_animations
  229.     @anim.each do |ky,an|
  230.       next if an.nil?
  231.       if an.animation?
  232.         an.update
  233.       else
  234.         an.dispose
  235.         @anim[ky] = nil
  236.       end
  237.     end
  238.   end
  239.  
  240.   # Check for disposal.
  241.   # Can be used to check if the image has been disposed or not, obviously.
  242.   # You don't need to use this many times (if ever).
  243.   def disposed?
  244.     return @img.disposed?
  245.   end
  246.  
  247.   # The dispose method.
  248.   # Disposes the image and any database animations that might be playing.
  249.   def dispose
  250.     @anim.each_value {|an| an.dispose if !an.nil? && !an.disposed?}
  251.     @img.bitmap.dispose
  252.     @img.dispose
  253.   end
  254.  
  255. end
  256.  
  257. # The class below is a quick class for playing animations.
  258. # Not much different from the Sprite_Base class, just added some methods for
  259. # following a target and to show the animation on a specified position.
  260. # I won't explain this class, because it is not the subject of your topic. :P
  261. # This is just a little extra which was already included in my code, so I
  262. # didn't want to remove it. Use it if you want, don't if you don't want.
  263. class QuickAnim < Sprite_Base
  264.  
  265.   def initialize(viewport=nil,pos=nil)
  266.     super(viewport)
  267.     if pos
  268.       self.x = pos[0]
  269.       self.y = pos[1]
  270.     end
  271.     @use_sprite = true
  272.     @ani_duration = 0
  273.   end
  274.  
  275.   def set_target(target,set_pos=true)
  276.     @target = target
  277.     return unless set_pos
  278.     self.x = target.x
  279.     self.y = target.y
  280.   end
  281.  
  282.   def update
  283.     super
  284.     if !self.disposed? && @target && !@target.disposed?
  285.       update_follow_target
  286.     end
  287.   end
  288.  
  289.   def update_follow_target
  290.     xx = @target.x - self.x
  291.     yy = @target.y - self.y
  292.     self.x = @target.x
  293.     self.y = @target.y
  294.     move_animation2(xx,yy)
  295.   end
  296.    
  297.   def move_animation2(dx, dy)
  298.     if @animation && @animation.position != 3
  299.       @ani_ox += dx
  300.       @ani_oy += dy
  301.       @ani_sprites.each do |sprite|
  302.         sprite.x += dx
  303.         sprite.y += dy
  304.       end
  305.     end
  306.   end
  307.  
  308.   def animation_process_timing(timing)
  309.     super
  310.     return unless @target && !@target.disposed?
  311.     case timing.flash_scope
  312.     when 1
  313.       @target.flash(timing.flash_color, timing.flash_duration * @ani_rate)
  314.     when 3
  315.       @target.flash(nil, timing.flash_duration * @ani_rate)
  316.     end
  317.   end
  318.  
  319. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement