Advertisement
TheSixth

Smooth Animation System

Feb 17th, 2017
503
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 21.43 KB | None | 0 0
  1. #===============================================================================
  2. # * [ACE] Smooth Animation System
  3. #===============================================================================
  4. # * Made by: Sixth (www.rpgmakervxace.net, www.forums.rpgmakerweb.com)
  5. # * Version: 1.5
  6. # * Updated: 27/06/2019
  7. # * Requires: Sixth's Smooth Animation Module
  8. #-------------------------------------------------------------------------------
  9. # * < Change Log >
  10. #-------------------------------------------------------------------------------
  11. # * Version 1.0 (07/10/2016)
  12. #   - Initial release.
  13. # * Version 1.1 (13/11/2016)
  14. #   - Added a method to skip to a specified frame in the animation.
  15. #   - Added a method to forcibly update an animated object without proceeding
  16. #     the animation. Might come in handy for initializing resumed animations.
  17. #   - Added a class which can be used to run the animation and store the
  18. #     current values, instead of directly modifying the animated object itself.
  19. #     This makes it possible to save these instanced classes as a reference
  20. #     later on, in case you need to resume an animation from the same time and
  21. #     with the same values. The class is named SmoothNum, and it's only purpose
  22. #     is to animate it's @value property.
  23. # * Version 1.2 (23/12/2016)
  24. #   - Added a method to completely clear all the animations at once.
  25. #     You can choose to finish them or not before clearing them.
  26. #   - All animations will get cleared when starting the title scene from now on.
  27. #     This is to prevent undesired left-over animations for some global objects.
  28. # * Version 1.3 (17/02/2017)
  29. #   - Fixed a typo that crashes the game if the 'rem_time' method was used.
  30. #   - Fixed the 'animating?' check method. It returned wrong results in some
  31. #     very specific cases.
  32. #   - Added a method to check the current time in the animation as well as the
  33. #     remaining time of it.
  34. # * Version 1.4 (20/04/2018)
  35. #   - Minor performance update.
  36. # * Version 1.5 (27/06/2019)
  37. #   - Moved the update method for the animations to the update_basic method of
  38. #     Scene_Base instead of the update method. More compatible this way.
  39. #-------------------------------------------------------------------------------
  40. # * < Description >
  41. #-------------------------------------------------------------------------------
  42. # * This script will let you animate whatever you want for any object, as long
  43. #   as the thing you want to animate is represented with a numeric value.
  44. #   This means that it can be:
  45. #   - Position change (X and Y).
  46. #   - Size change.
  47. #   - Zoom change.
  48. #   - Opacity change.
  49. #   - Angle change.
  50. #   - And so on, and so on...
  51. #   So, basically anything can be animated!
  52. # * When I say "animate" here, I mean the ability to smoothly change these
  53. #   properties over time, instead of just setting the value instantly.
  54. # * Easing animations are possible to make too!
  55. # * Stop, pause, speed up, slow down, or skip the animations!
  56. # * Checking method to see if an object is being animated or not.
  57. # * NOTE: This is a tool meant to be used by experienced scripters!
  58. #         This script will NOT do anything on it's own just by being installed!
  59. #         The scripter must set the animations up in other scripts to see the
  60. #         effects of this script!
  61. #-------------------------------------------------------------------------------
  62. # * < Script Calls >
  63. #-------------------------------------------------------------------------------
  64. # * To add a new animation for an object, use this script call:
  65. #
  66. #     SmoothAnim.add_d(object,property,end_value,time,type,mcall)
  67. #
  68. #   This will let you set the destination value for the animated property
  69. #   (the end_value) directly, hence the name 'add_d' ("add direct").
  70. #
  71. #   Replace the object with the object you want to animate.
  72. #   This can be anything from Sprites to Windows, Colors, Tones, Rects, etc.
  73. #   NOTE:
  74. #   If the object is disposed or returns nil, nothing will happen!
  75. #   Also, if the object would get disposed while an animation on it still runs,
  76. #   the remaining animation(s) will be discarded automatically!
  77. #
  78. #   The property is a valid variable of the object you want to animate.
  79. #   This property must have a getter and setter method defined! If there is no
  80. #   such methods, nothing will happen!
  81. #   Must be a string, and the object must have a getter and setter method
  82. #   defined the same way (with the setter method looking like: property= ).
  83. #
  84. #   The end_value is the value of the property after the end of the animation.
  85. #   In other words, you want to smoothly change the value of the property from
  86. #   whatever it's value currently is to this end value you set here.
  87. #   Must be a numeric value!
  88. #  
  89. #   The time is the time in frames for the animation to complete.
  90. #   This much time the animation will last, and this much time is needed to
  91. #   reach the end value of the property you have set up in the script call.
  92. #   Must be a numeric value!
  93. #
  94. #   And the type will decide the animation type you want to use.
  95. #   There are many types available to use, elastic, bouncing, exponential, and
  96. #   so on. The linear animation is the default value of this argument.
  97. #   This must be a symbol or a string, and there must be a method named the same
  98. #   way in the SmoothAnim module!
  99. #
  100. #   And the mcall argument can be used to call a method on any object you want
  101. #   (not just on the animated object) every time the value of the animated
  102. #   property changes. This must be an array with the following structure:
  103. #     [object, method_name, arg1, arg2, arg3, ...]
  104. #   The object here is the object the method will be called on.
  105. #   The method_name is... well, it's the name of the method, obviously.
  106. #   And the following elements in the array will all be arguments for the
  107. #   method you called. These are optional, you don't have to use them if the
  108. #   method got no arguments (you should NOT use them than, actually).
  109. #   This argument is optional. If you omit it, no other methods will be called
  110. #   on any objects.
  111. #
  112. #   Examples:
  113. #
  114. #     SmoothAnim.add_d(@help_window,"x",120,90,:bounce_in)
  115. #   Will smoothly move the @help_window object to the X position of 120.
  116. #   The animation will last 90 frames (1 and a half second), and it will use the
  117. #   "bounce_in" easing animation for the movement.
  118. #
  119. #     SmoothAnim.add_d(@img,"angle",360,180)
  120. #   Will rotate the @img object by 360 angles (a full cycle). The animation
  121. #   lasts 180 frames (3 seconds). It will use the "linear" animation mode
  122. #   (because the type argument is omitted), which is what it's name suggests,
  123. #   a static change in the angle without any special animation effects.
  124. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  125. # * To add a new animation for an object, use this script call:
  126. #
  127. #     SmoothAnim.add_c(object,property,change,time,type,mcall)
  128. #
  129. #   Deja Vu, right? Well, this script call is the same as the above one with a
  130. #   small difference (aside from the obviously different method name).
  131. #   Instead of specifying the end value, here you will specify the value of
  132. #   change (and this is why it's named 'add_c' - "add change").
  133. #
  134. #   Everything is the same here like in the above script call, except the change
  135. #   argument. That one replaces the end_value argument, and specifies the value
  136. #   of change in the animated property.
  137. #
  138. #   Examples:
  139. #  
  140. #     SmoothAnim.add_c(@img.src_rect,"width",-200,300,:cubic_out)
  141. #   This will modify the Rect of the @img object (which is a sprite), it's
  142. #   width, to be more specific.
  143. #   Will slowly shrink it by 200 pixels within 300 frames using the "cubic_out"
  144. #   easing animation method.
  145. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  146. # * To delete an animation on an object, use this script call:
  147. #
  148. #     SmoothAnim.del(object,finish?,property)
  149. #
  150. #   With this, you can either stop the animation permanently (so, you won't be
  151. #   able to resume it later!), or instantly skip to the end of the animation,
  152. #   which means that the value of the animated properties will be instantly set
  153. #   to the values they would get after finishing the animation.
  154. #
  155. #   The object is the same as in the other script calls.
  156. #
  157. #   The finish? argument can be true or false.
  158. #   If true, the animation will be finished instantly (in other words, it will
  159. #   be skipped to the end).
  160. #   If false, the animation will be permanently deleted and it will NOT be
  161. #   finished, so wherever it stopped, it will stay that way!
  162. #   If you omit this argument, true will be used by default!
  163. #
  164. #   And the property must be a variable of the object.
  165. #   Additionally, if you want to stop/skip all of the currently playing
  166. #   animations on the object, you can use the symbol :all for this argument.
  167. #   If you want to directly stop/skip a specific variable, this argument must
  168. #   be a string!
  169. #   If you omit this, :all will be used by default!
  170. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  171. # * To clear all animations at once, use this script call:
  172. #
  173. #     SmoothAnim.clear(finish?)
  174. #
  175. #   This will remove all animations on all of your animated objects.
  176. #  
  177. #   Set the finish? to true if you want to finish the animations before
  178. #   clearing them, or set it to false if you want to end them without finishing
  179. #   them. The default value is false.
  180. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  181. # * The following script calls are all used to control the speed of the already
  182. #   existing animations on the objects:
  183. #
  184. #     SmoothAnim.pause(object,property)
  185. #     SmoothAnim.speed_set(object,speed,property)
  186. #     SmoothAnim.speed_up(object,speed,property)
  187. #     SmoothAnim.slow_down(object,speed,property)
  188. #    
  189. #   The name of the methods should tell what they do.
  190. #   Again, if the object is disposed or if they would return nil, these will
  191. #   not do anything!
  192. #   Similarly, if the entered property is not a valid one, nothing happens!
  193. #  
  194. #   The object is the animated object you want to manipulate (speed up, etc.
  195. #  
  196. #   The speed is a numeric value, and that will decide the change in the speed
  197. #   of the animations.
  198. #   The default values are:
  199. #   Set: 1 (1 is the default speed of every animation!)
  200. #   Speed up: 2 (2 will double the speed of the animation - multiplier!)
  201. #   Slow down: 2 (2 will halve the speed of the animation - divider!)
  202. #   Pause: 0 (0 will stop the animation - this can't be changed!
  203. #             This is not really an argument because you can't cahnge it in the
  204. #             script call, just noting here that this will set it to 0.)
  205. #   So, in case you omit this argument, the default will be used.
  206. #  
  207. #   And the property must be a variable of the object.
  208. #   Additionally, if you want to manipulate all of the currently playing
  209. #   animations on the object, you can use the symbol :all for this argument.
  210. #   If you want to directly manipulate a specific variable, this argument must
  211. #   be a string!
  212. #   If you omit this, :all will be used by default!
  213. #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  214. # * To check if an object is currently being animated or not, use this script
  215. #   call:
  216. #
  217. #     SmoothAnim.animating?(object,property)
  218. #
  219. #   Obviously, if the object is disposed or returns nil, this will return false!
  220. #  
  221. #   The property can be the symbol :any, which means that the check will return
  222. #   true if there is any kind of animation on the object, or a string, in which
  223. #   case you will only check for the animation of that specific variable.
  224. #-------------------------------------------------------------------------------
  225. # * < Installation >
  226. #-------------------------------------------------------------------------------
  227. # * Place this script between Materials and Main!
  228. #-------------------------------------------------------------------------------
  229. # * < Compatibility Info >
  230. #-------------------------------------------------------------------------------
  231. # * No known incompatibilities.
  232. #-------------------------------------------------------------------------------
  233. # * < Known Issues >
  234. #-------------------------------------------------------------------------------
  235. # * No known issues.
  236. #-------------------------------------------------------------------------------
  237. # * < Terms of Use >
  238. #-------------------------------------------------------------------------------
  239. # * Free to use for whatever purposes you want.
  240. # * Credit me (Sixth) in your game, pretty please! :P
  241. # * Posting modified versions of this script is allowed as long as you notice me
  242. #   about it with a link to it!
  243. #===============================================================================
  244. $imported = {} if $imported.nil?
  245. $imported["SixthABSSmoothAnim"] = true
  246. #===============================================================================
  247. # No Settings! o.O
  248. #===============================================================================
  249.  
  250. module SmoothAnim
  251.  
  252.   attr_accessor :anim
  253.  
  254.   @gspd = 1
  255.  
  256.   # Animation container
  257.   def self.anim
  258.     @anim = {} if @anim.nil?
  259.     return @anim
  260.   end
  261.  
  262.   # Clears all animations. You can finish them before the purge if needed.
  263.   def self.clear(finish=false)
  264.     self.anim.each do |obj,props|
  265.       if finish
  266.         props.each {|var,info|
  267.           obj.send(var+'=',info[:end])
  268.           info[:mobj].send(info[:mcall],*info[:margs]) if info[:mcall]
  269.         }
  270.       end
  271.       self.anim.delete(obj)
  272.     end
  273.   end
  274.    
  275.   # Adding an animation for the object - type 1
  276.   def self.add_d(obj,var,dest,time,type=:linear,mcall=nil,*args)
  277.     return if obj.nil? || obj.disposed?
  278.     return unless obj.respond_to?(var+"=")
  279.     self.anim[obj] = {} if self.anim[obj].nil?
  280.     start = obj.send(var,*args)
  281.     mcall = mcall.clone if mcall
  282.     self.anim[obj][var] = {
  283.       :start => start.to_f,
  284.       :end => dest.to_f,
  285.       :change => dest - start,
  286.       :time => time.to_f,
  287.       :type => type.is_a?(Array) ? SmoothAnim.rand_anim(*type) : type,
  288.       :c_time => 0.0,
  289.       :spd => 1.0,
  290.       :mobj => mcall.nil? ? nil : mcall.shift,
  291.       :mcall => mcall.nil? ? nil : mcall.shift,
  292.       :margs => mcall,
  293.       :args => args,
  294.     }
  295.   end
  296.  
  297.   # Adding an animation for the object - type 2
  298.   def self.add_c(obj,var,change,time,type=:linear,mcall=nil,*args)
  299.     return if obj.nil? || obj.disposed?
  300.     return unless obj.respond_to?(var+"=")
  301.     self.anim[obj] = {} if self.anim[obj].nil?
  302.     start = obj.send(var,*args)
  303.     mcall = mcall.clone if mcall
  304.     self.anim[obj][var] = {
  305.       :start => start.to_f,
  306.       :end => start + change.to_f,
  307.       :change => change.to_f,
  308.       :time => time.to_f,
  309.       :type => type.is_a?(Array) ? SmoothAnim.rand_anim(*type) : type,
  310.       :c_time => 0.0,
  311.       :spd => 1.0,
  312.       :mobj => mcall.nil? ? nil : mcall.shift,
  313.       :mcall => mcall.nil? ? nil : mcall.shift,
  314.       :margs => mcall,
  315.       :args => args,
  316.     }
  317.   end
  318.  
  319.   # Deletes the animation for the object.
  320.   # Can set the finishing values for the object if needed (making a "skip animation" effect)
  321.   # Omit the last argument to remove all animations for the object
  322.   def self.del(obj,finish=true,var=:all)
  323.     return if obj.nil? || obj.disposed?
  324.     return unless self.anim[obj]
  325.     if var == :all
  326.       if finish
  327.         self.anim[obj].each {|var,info|
  328.           obj.send(var+'=',info[:end])
  329.           info[:mobj].send(info[:mcall],*info[:margs]) if info[:mcall]
  330.         }
  331.       end
  332.       self.anim.delete(obj)
  333.     else
  334.       return unless self.anim[obj][var]
  335.       if finish
  336.         an = self.anim[obj][var]
  337.         obj.send(var+'=',an[:end])
  338.         an[:mobj].send(an[:mcall],*an[:margs]) if an[:mcall]
  339.       end
  340.       self.anim[obj].delete(var)
  341.     end
  342.   end
  343.  
  344.   # Gets the remaining time of the animation
  345.   def self.rem_time(obj,prop=:any)
  346.     return 0 if obj.nil? || obj.disposed?
  347.     return 0 unless self.anim[obj]
  348.     if prop == :any
  349.       high = self.anim[obj].max_by {|var,info| info[:c_time] }[1]
  350.       return high[:time] - high[:c_time]
  351.     else
  352.       return 0 unless self.anim[obj][prop]
  353.       andt = self.anim[obj][prop]
  354.       return andt[:time] - andt[:c_time]
  355.     end
  356.   end
  357.  
  358.   # Gets the current time of the animation
  359.   def self.get_frame(obj,prop=:all)
  360.     return 0 if obj.nil? || obj.disposed?
  361.     return 0 unless self.anim[obj]
  362.     if prop == :all
  363.       high = self.anim[obj].max_by {|var,info| info[:c_time] }[1]
  364.       return high[:c_time]
  365.     else
  366.       return 0 unless self.anim[obj][prop]
  367.       return self.anim[obj][prop][:c_time]
  368.     end
  369.   end
  370.  
  371.   # Skips to the specified frame of the animation
  372.   def self.set_frame(obj,frame,prop=:all)
  373.     return if obj.nil? || obj.disposed?
  374.     return unless self.anim[obj]
  375.     if prop == :all
  376.       self.anim[obj].each {|var,info| info[:c_time] = frame }
  377.     else
  378.       return unless self.anim[obj][prop]
  379.       self.anim[obj][prop][:c_time] = frame
  380.     end
  381.   end
  382.    
  383.   # Pause the animation
  384.   def self.pause(obj,var=:all)
  385.     return if obj.nil? || obj.disposed?
  386.     return unless self.anim[obj]
  387.     if var == :all
  388.       self.anim[obj].each {|var,info| info[:spd] = 0 }
  389.     else
  390.       return unless self.anim[obj][var]
  391.       self.anim[obj][var][:spd] = 0
  392.     end
  393.   end
  394.  
  395.   # Sets a speed modifier for all animations
  396.   def self.set_speed_mod(spd=1)
  397.     @gspd = spd
  398.   end
  399.  
  400.   # Normalize the speed of the animation
  401.   def self.speed_set(obj,spd=1,var=:all)
  402.     return if obj.nil? || obj.disposed?
  403.     return unless self.anim[obj]
  404.     if var == :all
  405.       self.anim[obj].each {|var,info| info[:spd] = spd }
  406.     else
  407.       return unless self.anim[obj][var]
  408.       self.anim[obj][var][:spd] = spd
  409.     end
  410.   end
  411.  
  412.   # Speed up the animation by 'spd'
  413.   def self.speed_up(obj,spd=2,var=:all)
  414.     return if obj.nil? || obj.disposed?
  415.     return unless self.anim[obj]
  416.     if var == :all
  417.       self.anim[obj].each {|var,info| info[:spd] *= spd }
  418.     else
  419.       return unless self.anim[obj][var]
  420.       self.anim[obj][var][:spd] *= spd
  421.     end
  422.   end
  423.  
  424.   # Slow down the animation by 'spd'
  425.   def self.slow_down(obj,spd=2,var=:all)
  426.     return if obj.nil? || obj.disposed?
  427.     return unless self.anim[obj]
  428.     if var == :all
  429.       self.anim[obj].each {|var,info| info[:spd] /= spd }
  430.     else
  431.       return unless self.anim[obj][var]
  432.       self.anim[obj][var][:spd] /= spd
  433.     end
  434.   end
  435.    
  436.   # Checks if an object got an animation or not
  437.   def self.animating?(obj,var=:any)
  438.     return false if obj.nil? || obj.disposed?
  439.     return false unless self.anim[obj]
  440.     if var == :any
  441.       return !self.anim[obj].nil? && !self.anim[obj].empty?
  442.     else
  443.       return self.anim[obj][var]
  444.     end
  445.   end
  446.  
  447.   # Forcibly updates the animated object without proceeding it
  448.   def self.force_update(obj)
  449.     return unless self.anim[obj]
  450.     self.anim[obj].each do |var,an|
  451.       break if obj.nil? || obj.disposed?
  452.       update_force_anim(obj,var,an)
  453.     end
  454.   end
  455.  
  456.   # Part of the force update method above
  457.   def self.update_force_anim(obj,var,an)
  458.     if an[:c_time] >= an[:time]
  459.       obj.send(var+'=',an[:end])
  460.       an[:mobj].send(an[:mcall],*an[:margs]) if an[:mcall]
  461.       self.anim[obj].delete(var)
  462.       self.anim.delete(obj) if self.anim[obj].empty?
  463.     else
  464.       an[:c_time] = an[:time] if an[:c_time] > an[:time]
  465.       new_val = send(an[:type],an[:start],an[:change],an[:c_time],an[:time])
  466.       obj.send(var+'=',new_val)
  467.       an[:mobj].send(an[:mcall],*an[:margs]) if an[:mcall]
  468.     end
  469.   end
  470.  
  471.   # Animation update for all objects currently animated
  472.   def self.update
  473.     #p "updating smooth anim!"
  474.     self.anim.each do |obj,data|
  475.       if obj.nil? || obj.disposed?
  476.         self.anim.delete(obj)
  477.       else
  478.         data.each do |var,an|
  479.           break if obj.nil? || obj.disposed?
  480.           update_anim_ex(obj,var,an)
  481.         end
  482.       end
  483.     end
  484.   end
  485.  
  486.   # Animation process
  487.   def self.update_anim_ex(obj,var,an)
  488.     if an[:c_time] >= an[:time]
  489.       obj.send(var+'=',an[:end])
  490.       an[:mobj].send(an[:mcall],*an[:margs]) if an[:mcall]
  491.       self.anim[obj].delete(var)
  492.       self.anim.delete(obj) if self.anim[obj].empty?
  493.     else
  494.       an[:c_time] += an[:spd] * @gspd
  495.       an[:c_time] = an[:time] if an[:c_time] > an[:time]
  496.       new_val = send(an[:type],an[:start],an[:change],an[:c_time],an[:time])
  497.       obj.send(var+'=',new_val)
  498.       an[:mobj].send(an[:mcall],*an[:margs]) if an[:mcall]
  499.     end
  500.   end
  501.    
  502. end
  503.  
  504. class SmoothNum
  505.  
  506.   attr_accessor :value, :anim
  507.  
  508.   def initialize(value=0,anim=nil)
  509.     @value = value
  510.     @anim = anim
  511.   end
  512.  
  513.   def value(round=false)
  514.     return round ? @value.to_i : @value
  515.   end
  516.  
  517.   def value=(value)
  518.     @value = value
  519.   end
  520.  
  521. end
  522.  
  523. class Scene_Base
  524.  
  525.   # Added the update method here...
  526.   # Might move it to the Graphics module instead...
  527.   alias add_smooth_anims8827 update_basic
  528.   def update_basic
  529.     add_smooth_anims8827
  530.     SmoothAnim.update
  531.   end
  532.  
  533. end
  534.  
  535. class Object
  536.  
  537.   def disposed?
  538.     return false
  539.   end
  540.  
  541. end
  542.  
  543. class Scene_Title < Scene_Base
  544.  
  545.   alias clear_anims9917 start
  546.   def start
  547.     SmoothAnim.clear
  548.     clear_anims9917
  549.   end
  550.  
  551. end
  552.  
  553. class Scene_Gameover < Scene_Base
  554.  
  555.   alias clear_anims1117 start
  556.   def start
  557.     SmoothAnim.clear
  558.     clear_anims1117
  559.   end
  560.  
  561. end
  562. #==============================================================================
  563. # !!END OF SCRIPT - OHH, NOES!!
  564. #==============================================================================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement