Advertisement
Iavra

[Ace] Animate Everything - Script

Jun 1st, 2015
598
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 18.37 KB | None | 0 0
  1. #==============================================================================
  2. # Iavra Animate Everything 1.04
  3. # -----------------------------------------------------------------------------
  4. # Description:
  5. # Allows animation of every numeric attribute on any object.
  6. # -----------------------------------------------------------------------------
  7. # Prerequisites:
  8. # (optional) "Iavra Weak Reference" - only if Weak References are used.
  9. # -----------------------------------------------------------------------------
  10. # How to Use:
  11. # Place this script below every class that you want to support animating.
  12. #
  13. # To register a class, add it to the CLASSES hash and define a generic getter
  14. # and setter for it. The configuration lists common patterns for this part.
  15. #
  16. # Afterwards, call the following method on an object of said class:
  17. #
  18. # IAVRA::ANIMATE.start(<object>, {:attr => 100}, 120, :linear, 60, false) { p self }
  19. #
  20. # This will first wait 60 frames before animating the attribute "attr" on
  21. # <object> from its current value to 100 over a duration of 120 frames using
  22. # linear easing. Since the last parameter is false, the animation will cancel
  23. # existing ones. After the animation is finished, the given block will be
  24. # executed in the object's context and prints it to the console.
  25. #
  26. # Animations can also be start from the object itself by calling:
  27. #
  28. # <object>.iavra_animate_start({:attr => 100}, 120, :linear, 60, false) { p self }
  29. # -----------------------------------------------------------------------------
  30. # Terms of Use:
  31. # Free to use for both commercial and non-commercial games. Please give credit.
  32. # -----------------------------------------------------------------------------
  33. # Credits:
  34. # Iavra
  35. # -----------------------------------------------------------------------------
  36. # Changelog:
  37. # - 0.01: First version.
  38. # - 0.02: Added support for different accessing methods, restructured the code.
  39. # - 0.03: Changed the update method to fix rounding error on animation end.
  40. #         Also fixed a bug that caused the update method to skip frames for
  41. #         every animated attribute after the first.
  42. # - 0.04: Different attributes on the same object can now be animated, paused,
  43. #         resumed and stopped independently from each other.
  44. # - 0.05: Changed the easing functions from lambdas to methods to increase
  45. #         performance. Added Bounce/Back/Elastic easing.
  46. # - 0.06: Moved the start, pause, resume and stop methods to IAVRA::ANIMATE to
  47. #         lessen the amount of clutter on the extended classes.
  48. # - 0.07: Exported the easing functions to their own script, so it's easily
  49. #         possible to switch them out, if needed. I left the default :linear in
  50. #         here, so the script can still work on its own.
  51. # - 0.08: Removed pause and resume functions, since they would mess up the
  52. #         animation if the attributes are changed by other means.
  53. # - 0.09: Added support for on complete callbacks. Be careful only to use them
  54. #         on objects that are not included in the savefiles.
  55. # - 0.10: An optional offset can now be specified that will cause the animation
  56. #         to start delayed.
  57. # - 0.11: Animations will no longer overwrite existing ones, but are pushed in
  58. #         a queue and processed in order. "stop" will still remove all stored
  59. #         animations, while the new method "skip" will only remove the current
  60. #         one and proceed with the remaining, if any.
  61. # - 0.12: On complete callbacks are now executed using instance_eval, so self
  62. #         will be set to the animated object.
  63. # - 0.13: Default easing function and chaining behaviour can now be configured.
  64. #         Also added a new parameter to IAVRA::ANIMATE.start, that specifies if
  65. #         the animation should be queued or overwrite older ones.
  66. # - 1.00: Release version.
  67. # - 1.01: Added the "step" method, that was previously removed. It returns the
  68. #         current frame of the active animation for an attribute. Returns 0 for
  69. #         delayed animations and nil if the attribute isn't animating.
  70. # - 1.02: Moved the update_animation method to occur before the normal update,
  71. #         since the old version sometimes resulted in strange behaviour.
  72. # - 1.03: Added dependency to "Iavra Weak Reference". Objects are now updated
  73. #         from outside and don't need their own update method anymore. They
  74. #         still have their own animation data, though, since checking equality
  75. #         with WeakRefs can be a nightmare.
  76. # - 1.04: Added a new configuration option to toggle between Weak and Strong
  77. #         references. "Iavra Weak Reference" is only needed if Weak References
  78. #         are used.
  79. #==============================================================================
  80.  
  81. ($imported ||= {})[:iavra_animate_everything] = true
  82.  
  83. #==============================================================================
  84. # ▼ IAVRA::ANIMATE
  85. #==============================================================================
  86.  
  87. module IAVRA
  88.     module ANIMATE
  89.        
  90.         #==========================================================================
  91.         # ■ ■ ■ ■ ■ CONFIGURATION ■ ■ ■ ■ ■
  92.         #==========================================================================
  93.        
  94.         #==========================================================================
  95.         # The keys are classes, which should implement animating. The values are
  96.         # arrays containing a generic getter and a generic setter. Usually one of
  97.         # 2 patterns is needed:
  98.         #
  99.         # - Direct variable access:
  100.         #
  101.         # Game_Picture => [
  102.         #       lambda {|a|    instance_variable_get(:"@#{a}")},
  103.         #       lambda {|a, v| instance_variable_set(:"@#{a}", v)}
  104.         # ]
  105.         #
  106.         # - Getter and setter, either implicit via attr_accessor or explicit:
  107.         #
  108.         # Sprite_Base => [
  109.         #       lambda {|a|    send(:"#{a}")},
  110.         #       lambda {|a, v| send(:"#{a}=", v)}
  111.         # ]
  112.         #==========================================================================
  113.        
  114.         CLASSES = {
  115.             Game_Picture => [
  116.                 lambda {|a|    instance_variable_get(:"@#{a}")},
  117.                 lambda {|a, v| instance_variable_set(:"@#{a}", v)}
  118.             ],
  119.             Game_Character => [
  120.                 lambda {|a|    instance_variable_get(:"@#{a}")},
  121.                 lambda {|a, v| instance_variable_set(:"@#{a}", v)}
  122.             ],
  123.             Sprite_Base => [
  124.                 lambda {|a|    send(:"#{a}")},
  125.                 lambda {|a, v| send(:"#{a}=", v)}
  126.             ]
  127.         }
  128.        
  129.         #==========================================================================
  130.         # If set to true, animations will chain by default.
  131.         #==========================================================================
  132.        
  133.         DEFAULT_CHAINING = false
  134.        
  135.         #==========================================================================
  136.         # The default easing function to be used, if the parameter is omitted.
  137.         #==========================================================================
  138.        
  139.         DEFAULT_EASING = :linear
  140.        
  141.         #==========================================================================
  142.         # If set to true, the script will keep weak references to the animated
  143.         # objects instead of referencing to the objects themselves. An object that
  144.         # is only referenced by Weak References may be garbage collected at any
  145.         # time.
  146.         #
  147.         # Using this option adds a dependency to "Iavra Weak References".
  148.         #
  149.         # If you only intend to animate disposable objects (Sprites, Windows) and
  150.         # dispose them correctly, you won't need this.
  151.         #==========================================================================
  152.        
  153.         WEAK_REFERENCES = false
  154.        
  155.         #==========================================================================
  156.         # ■ ■ ■ ■ ■ CONFIGURATION ■ ■ ■ ■ ■
  157.         #==========================================================================
  158.        
  159.         fail "'Iavra Weak Reference' not found" if WEAK_REFERENCES && $imported[:iavra_weakref].nil?
  160.        
  161.         #==========================================================================
  162.         # Keeping a list of references to animating objects.
  163.         #==========================================================================
  164.        
  165.         @refs = {}
  166.        
  167.         #==========================================================================
  168.         # Starts an animation on the target object.
  169.         #
  170.         # Takes the following parameters:
  171.         #
  172.         # target:                           Object to animate.
  173.         # attrs:                            Attributes to animate and their target values.
  174.         # duration (default 1):             Animation duration, in frames.
  175.         # easing   (default configurable):  Easing function to use.
  176.         # offset   (default 0):             Delay, before starting the animation.
  177.         # chain    (default configurable):  If the animation should be queued.
  178.         # proc:    (default nil)            On complete callback.
  179.         #
  180.         # Stores the following data as an instance variable:
  181.         #
  182.         # v(alue):   The target value.
  183.         # t(ime):    Animation step, starting at 0. Gets increased every frame.
  184.         # d(uration: Total animation duration, in frames.
  185.         # e(asing):  Symbol identifying the easing function to be used.
  186.         # o(ffset):  Delay, before the animation starts (since :d was already taken).
  187.         # p(roc):    An optional block to be called once the animation is finished.
  188.         #            Inside the block, self will be set to the animated object.
  189.         #
  190.         # WARNING: Procs can NOT be serialized. If you pass a callback to an object
  191.         # that is included in the savefile and the animation is still running when
  192.         # the game is saved, it will crash.
  193.         #
  194.         # The method will fail, if:
  195.         # - The target's class or one of its superclasses isn't listed in CLASSES.
  196.         # - A duration less than 1 is specified.
  197.         # - The specified easing function can't be found.
  198.         #==========================================================================
  199.        
  200.         def self.start(target, attrs, duration = 1, easing = DEFAULT_EASING,
  201.                            offset = 0, chain = DEFAULT_CHAINING, &proc)
  202.             fail "target doesn't support animating" unless CLASSES.keys.map{|k| target.is_a?(k)}.any?
  203.             fail "duration must be higher than 0" if duration < 1
  204.             fail "easing '#{easing}' not found" unless EASING.respond_to?(easing)
  205.             dur = duration.to_i.to_f
  206.             attrs.each do |k, v|
  207.                 data = {:v => v, :t => 0.0, :d => dur, :e => easing, :o => offset, :p => proc}
  208.                 (target.iavra_animate_data[k] ||= []).clear unless chain
  209.                 (target.iavra_animate_data[k] ||= []) << data
  210.             end
  211.             @refs[(WEAK_REFERENCES ? IAVRA::WeakRef.new(target) : target)] = true
  212.         end
  213.        
  214.         #==========================================================================
  215.         # Stops the animation for either all or selected attributes on the target.
  216.         #==========================================================================
  217.        
  218.         def self.stop(target, *attrs)
  219.             if attrs.empty?
  220.                 target.iavra_animate_data.clear
  221.             else
  222.                 attrs.each{|a| target.iavra_animate_data.delete(a)}
  223.             end
  224.         end
  225.        
  226.         #==========================================================================
  227.         # Skips the current animation for the selected attributes.
  228.         #==========================================================================
  229.        
  230.         def self.skip(target, *attrs)
  231.             attrs.each{|a| (target.iavra_animate_data[a] || []).shift}
  232.         end
  233.        
  234.         #==========================================================================
  235.         # Returns the frame of the current animation for the selected attribute or
  236.         # nil, if the attribute isn't animating. If the animation is delayed, this
  237.         # will return 0.
  238.         #==========================================================================
  239.        
  240.         def self.step(target, attr)
  241.             target.iavra_animate_data[attr][0][:t].to_i rescue nil
  242.         end
  243.        
  244.         #==========================================================================
  245.         # Returns the current animation status. An object is considered animating,
  246.         # if it has any currently active, non-delayed animations.
  247.         #==========================================================================
  248.        
  249.         def self.animating?(target)
  250.             target.iavra_animate_data.values.reject{|v| v.empty?}.map{|v| v[0][:o] <= 0}.any?
  251.         end
  252.        
  253.         #==========================================================================
  254.         # Called every frame. First, clears all references to objects that have
  255.         # been garbage collected, disposed or that have no active animations. Then
  256.         # updates the animations of those remaining.
  257.         #==========================================================================
  258.        
  259.         def self.update
  260.             @refs.reject!{|ref, v| clear_ref?(ref)}
  261.             @refs.keys.each{|ref| update_ref(ref)}
  262.         end
  263.        
  264.         #==========================================================================
  265.         # Returns true if:
  266.         # - The reference can't access the object anymore, or
  267.         # - The referenced object is disposable and has been disposed, or
  268.         # - There are no active animations left on the object.
  269.         #==========================================================================
  270.        
  271.         def self.clear_ref?(ref)
  272.             obj = get_object(ref)
  273.             obj.nil? || (obj.respond_to?(:disposed?) && obj.disposed?) ||obj.iavra_animate_data.empty?
  274.         end
  275.        
  276.         #========================================================================
  277.         # Iterates over the animation data of an object and does the following:
  278.         #
  279.         # - Cleans up empty animation queues. This happens after an animation is
  280.         #   finished or a call to skip removed the last animation.
  281.         #
  282.         # - Takes the first animation in the queue.
  283.         #
  284.         # - If an animation delay was specified and is still active, decreases it
  285.         #   by 1 and does nothing.
  286.         #
  287.         # - If the animation just started, stores the current attribute value.
  288.         #   This will be used to determine the current values during the animation.
  289.         #
  290.         # - Increases the animation times by 1.
  291.         #
  292.         # - If this is the last step of the animation, sets the attribute to its
  293.         #   target value, calls the on complete callback, if any, and removes the
  294.         #   animation from the queue.
  295.         #
  296.         # - Otherwise invoke the easing method to determine the current value.
  297.         #
  298.         # - Deletes the data hash, if the animation is finished.
  299.         #========================================================================
  300.        
  301.         def self.update_ref(ref)
  302.             obj = get_object(ref)
  303.             obj.iavra_animate_data.reject!{|k, v| v.empty?}
  304.             obj.iavra_animate_data.each do |a, data_array|
  305.                 next if ((data = data_array[0])[:o] -= 1) >= 0
  306.                 data[:b] = obj.iavra_animate_get_attribute(a).to_f unless data[:b]
  307.                 if((data[:t] += 1) >= data[:d])
  308.                     obj.iavra_animate_set_attribute(a, data[:v])
  309.                     obj.instance_eval(&data[:p]) if data[:p]
  310.                     data_array.shift
  311.                 else
  312.                     args = [data[:e], data[:b], data[:v] - data[:b], data[:t], data[:d]]
  313.                     obj.iavra_animate_set_attribute(a, EASING.send(*args))
  314.                 end
  315.             end
  316.         end
  317.        
  318.         #==========================================================================
  319.         # Returns the referenced object.
  320.         #==========================================================================
  321.        
  322.         def self.get_object(ref)
  323.             WEAK_REFERENCES ? ref.object : ref
  324.         end
  325.        
  326.         #==========================================================================
  327.         # ▼ IAVRA::ANIMATE::METHODS
  328.         # -------------------------------------------------------------------------
  329.         # Since the script is supposed to work on virtually any class, we define
  330.         # our methods in a module that gets included in all declared classes.
  331.         #==========================================================================
  332.        
  333.         module METHODS
  334.            
  335.             #========================================================================
  336.             # We define a generic getter and setter for supported classes based on
  337.             # the classes declared in the configuration.
  338.             #========================================================================
  339.            
  340.             def self.included(cls)
  341.                 proc_get, proc_set = *IAVRA::ANIMATE::CLASSES[cls]
  342.                 cls.send(:define_method, :iavra_animate_get_attribute, proc_get)
  343.                 cls.send(:define_method, :iavra_animate_set_attribute, proc_set)
  344.             end
  345.            
  346.             #========================================================================
  347.             # Gets the animation data. Initializes it, if it doesn't already exist.
  348.             #========================================================================
  349.            
  350.             def iavra_animate_data
  351.                 @iavra_animate_data ||= {}
  352.             end
  353.            
  354.             #========================================================================
  355.             # Redirects to the module methods. Some of those are extended to allow
  356.             # chaining.
  357.             #========================================================================
  358.            
  359.             def iavra_animate_start(*args, &proc); IAVRA::ANIMATE.start(self, *args, &proc); self; end
  360.             def iavra_animate_stop(*args); IAVRA::ANIMATE.stop(self, *args); self; end
  361.             def iavra_animate_skip(*args); IAVRA::ANIMATE.skip(self, *args); self; end
  362.             def iavra_animate_step(*args); IAVRA::ANIMATE.step(self, *args); end
  363.             def iavra_animate_animating?(*args); IAVRA::ANIMATE.animating?(self, *args); end
  364.  
  365.         end
  366.        
  367.         #==========================================================================
  368.         # ▼ IAVRA::ANIMATE::EASING
  369.         # -------------------------------------------------------------------------
  370.         # Easing functions to be used in animations. :linear is no easing. Each
  371.         # method needs to take 4 parameters, all of which are floats:
  372.         #
  373.         # b(ase):     Base value of the attribute.
  374.         # c(hange):   Difference to the target value.
  375.         # t(ime):     Elapsed animation time.
  376.         # d(uration): Total animation time.
  377.         #==========================================================================
  378.        
  379.         module EASING
  380.            
  381.             #========================================================================
  382.             # Linear
  383.             #========================================================================
  384.            
  385.             def self.linear(b, c, t, d)
  386.                 c * t / d + b
  387.             end
  388.            
  389.         end
  390.        
  391.     end
  392. end
  393.  
  394. #==============================================================================
  395. # We let each supported class include our method module.
  396. #==============================================================================
  397.  
  398. IAVRA::ANIMATE::CLASSES.each{|cls, p| cls.send(:include, IAVRA::ANIMATE::METHODS)}
  399.  
  400. #==============================================================================
  401. # ▼ Scene_Base
  402. #==============================================================================
  403.  
  404. class Scene_Base
  405.    
  406.     alias :iavra_animate_update_basic :update_basic
  407.    
  408.     #============================================================================
  409.     # Update animations on every frame.
  410.     #============================================================================
  411.    
  412.     def update_basic
  413.         IAVRA::ANIMATE.update
  414.         iavra_animate_update_basic
  415.     end
  416.    
  417. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement