metro-ld25 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +12 -0
  6. data/Guardfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +189 -0
  9. data/Rakefile +18 -0
  10. data/bin/metro +16 -0
  11. data/changelog.md +157 -0
  12. data/lib/assets/menu-movement.wav +0 -0
  13. data/lib/assets/menu-selection.wav +0 -0
  14. data/lib/assets/missing.ogg +0 -0
  15. data/lib/assets/missing.png +0 -0
  16. data/lib/assets/missing.wav +0 -0
  17. data/lib/assets/missing_animation.png +0 -0
  18. data/lib/commands/generate_game.rb +13 -0
  19. data/lib/commands/generate_model.rb +25 -0
  20. data/lib/commands/generate_scene.rb +36 -0
  21. data/lib/commands/generate_view.rb +21 -0
  22. data/lib/commands/thor.rb +83 -0
  23. data/lib/core_ext/class.rb +14 -0
  24. data/lib/core_ext/numeric.rb +59 -0
  25. data/lib/gosu_ext/color.rb +62 -0
  26. data/lib/gosu_ext/gosu_constants.rb +53 -0
  27. data/lib/locale/en.yml +35 -0
  28. data/lib/locale/locale.rb +1 -0
  29. data/lib/metro.rb +140 -0
  30. data/lib/metro/animation.rb +135 -0
  31. data/lib/metro/animation/after_interval_factory.rb +12 -0
  32. data/lib/metro/animation/animation_factory.rb +15 -0
  33. data/lib/metro/animation/easing/ease_in.rb +15 -0
  34. data/lib/metro/animation/easing/easing.rb +51 -0
  35. data/lib/metro/animation/easing/linear.rb +15 -0
  36. data/lib/metro/animation/has_animations.rb +70 -0
  37. data/lib/metro/animation/implicit_animation.rb +100 -0
  38. data/lib/metro/animation/on_update_operation.rb +96 -0
  39. data/lib/metro/animation/scene_animation.rb +16 -0
  40. data/lib/metro/asset_path.rb +97 -0
  41. data/lib/metro/events/control_definition.rb +11 -0
  42. data/lib/metro/events/controls.rb +42 -0
  43. data/lib/metro/events/event_data.rb +60 -0
  44. data/lib/metro/events/event_dictionary.rb +52 -0
  45. data/lib/metro/events/event_factory.rb +17 -0
  46. data/lib/metro/events/event_relay.rb +300 -0
  47. data/lib/metro/events/event_state_manager.rb +63 -0
  48. data/lib/metro/events/events.rb +3 -0
  49. data/lib/metro/events/has_events.rb +108 -0
  50. data/lib/metro/events/hit_list.rb +75 -0
  51. data/lib/metro/events/unknown_sender.rb +5 -0
  52. data/lib/metro/font.rb +69 -0
  53. data/lib/metro/game.rb +102 -0
  54. data/lib/metro/game/dsl.rb +68 -0
  55. data/lib/metro/image.rb +68 -0
  56. data/lib/metro/logging.rb +33 -0
  57. data/lib/metro/missing_scene.rb +21 -0
  58. data/lib/metro/models/audio/song.rb +33 -0
  59. data/lib/metro/models/draws.rb +86 -0
  60. data/lib/metro/models/key_value_coding.rb +38 -0
  61. data/lib/metro/models/model.rb +236 -0
  62. data/lib/metro/models/model_factory.rb +32 -0
  63. data/lib/metro/models/models.rb +62 -0
  64. data/lib/metro/models/properties/animation_property.rb +115 -0
  65. data/lib/metro/models/properties/array_property.rb +24 -0
  66. data/lib/metro/models/properties/boolean_property.rb +27 -0
  67. data/lib/metro/models/properties/color_property.rb +116 -0
  68. data/lib/metro/models/properties/dimensions_property.rb +84 -0
  69. data/lib/metro/models/properties/font_property.rb +130 -0
  70. data/lib/metro/models/properties/image_property.rb +96 -0
  71. data/lib/metro/models/properties/model_property.rb +84 -0
  72. data/lib/metro/models/properties/numeric_property.rb +29 -0
  73. data/lib/metro/models/properties/options_property/no_option.rb +29 -0
  74. data/lib/metro/models/properties/options_property/options.rb +94 -0
  75. data/lib/metro/models/properties/options_property/options_property.rb +125 -0
  76. data/lib/metro/models/properties/position_property.rb +90 -0
  77. data/lib/metro/models/properties/property.rb +221 -0
  78. data/lib/metro/models/properties/property_owner.rb +137 -0
  79. data/lib/metro/models/properties/sample_property.rb +84 -0
  80. data/lib/metro/models/properties/scale_property.rb +80 -0
  81. data/lib/metro/models/properties/song_property.rb +89 -0
  82. data/lib/metro/models/properties/text_property.rb +75 -0
  83. data/lib/metro/models/ui/animated_sprite.rb +85 -0
  84. data/lib/metro/models/ui/border.rb +95 -0
  85. data/lib/metro/models/ui/fps.rb +54 -0
  86. data/lib/metro/models/ui/generic.rb +66 -0
  87. data/lib/metro/models/ui/grid_drawer.rb +74 -0
  88. data/lib/metro/models/ui/image.rb +87 -0
  89. data/lib/metro/models/ui/label.rb +175 -0
  90. data/lib/metro/models/ui/menu.rb +214 -0
  91. data/lib/metro/models/ui/model_label.rb +65 -0
  92. data/lib/metro/models/ui/model_labeler.rb +79 -0
  93. data/lib/metro/models/ui/rectangle.rb +59 -0
  94. data/lib/metro/models/ui/sprite.rb +79 -0
  95. data/lib/metro/models/ui/tile_map.rb +162 -0
  96. data/lib/metro/models/ui/ui.rb +13 -0
  97. data/lib/metro/parameters/command_line_args_parser.rb +68 -0
  98. data/lib/metro/parameters/options.rb +25 -0
  99. data/lib/metro/parameters/parameters.rb +2 -0
  100. data/lib/metro/sample.rb +40 -0
  101. data/lib/metro/scene.rb +477 -0
  102. data/lib/metro/scenes.rb +154 -0
  103. data/lib/metro/song.rb +56 -0
  104. data/lib/metro/template_message.rb +60 -0
  105. data/lib/metro/transitions/edit_transition_scene.rb +100 -0
  106. data/lib/metro/transitions/fade_transition_scene.rb +66 -0
  107. data/lib/metro/transitions/scene_transitions.rb +44 -0
  108. data/lib/metro/transitions/transition_scene.rb +19 -0
  109. data/lib/metro/units/bounds.rb +8 -0
  110. data/lib/metro/units/calculation_validations.rb +74 -0
  111. data/lib/metro/units/dimensions.rb +60 -0
  112. data/lib/metro/units/point.rb +51 -0
  113. data/lib/metro/units/rectangle_bounds.rb +85 -0
  114. data/lib/metro/units/scale.rb +46 -0
  115. data/lib/metro/units/units.rb +6 -0
  116. data/lib/metro/version.rb +32 -0
  117. data/lib/metro/views/json_view.rb +60 -0
  118. data/lib/metro/views/no_view.rb +34 -0
  119. data/lib/metro/views/parsers.rb +42 -0
  120. data/lib/metro/views/scene_view.rb +107 -0
  121. data/lib/metro/views/view.rb +133 -0
  122. data/lib/metro/views/writers.rb +43 -0
  123. data/lib/metro/views/yaml_view.rb +94 -0
  124. data/lib/metro/window.rb +94 -0
  125. data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
  126. data/lib/setup_handlers/game_execution.rb +65 -0
  127. data/lib/setup_handlers/load_game_configuration.rb +65 -0
  128. data/lib/setup_handlers/load_game_files.rb +101 -0
  129. data/lib/setup_handlers/move_to_game_directory.rb +25 -0
  130. data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
  131. data/lib/templates/game/README.md.tt +52 -0
  132. data/lib/templates/game/assets/brand.jpg +0 -0
  133. data/lib/templates/game/assets/hero.png +0 -0
  134. data/lib/templates/game/lib/custom_easing.rb +32 -0
  135. data/lib/templates/game/metro.tt +63 -0
  136. data/lib/templates/game/models/hero.rb +62 -0
  137. data/lib/templates/game/scenes/brand_scene.rb +19 -0
  138. data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
  139. data/lib/templates/game/scenes/first_scene.rb +28 -0
  140. data/lib/templates/game/scenes/game_scene.rb +43 -0
  141. data/lib/templates/game/scenes/title_scene.rb +15 -0
  142. data/lib/templates/game/views/brand.yaml +4 -0
  143. data/lib/templates/game/views/brand_to_title.yaml +8 -0
  144. data/lib/templates/game/views/first.yaml +26 -0
  145. data/lib/templates/game/views/title.yaml +11 -0
  146. data/lib/templates/message.erb +23 -0
  147. data/lib/templates/model.rb.tt +111 -0
  148. data/lib/templates/scene.rb.tt +140 -0
  149. data/lib/templates/view.yaml.tt +11 -0
  150. data/lib/tmxed_ext/tile_set.rb +34 -0
  151. data/metro.gemspec +56 -0
  152. data/spec/core_ext/numeric_spec.rb +78 -0
  153. data/spec/core_ext/string_spec.rb +33 -0
  154. data/spec/gosu_ext/color_spec.rb +80 -0
  155. data/spec/metro/events/event_state_manager_spec.rb +5 -0
  156. data/spec/metro/models/key_value_coding_spec.rb +61 -0
  157. data/spec/metro/models/properties/array_property_spec.rb +60 -0
  158. data/spec/metro/models/properties/color_property_spec.rb +85 -0
  159. data/spec/metro/models/properties/dimensions_spec.rb +29 -0
  160. data/spec/metro/models/properties/font_property_spec.rb +127 -0
  161. data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
  162. data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
  163. data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
  164. data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
  165. data/spec/metro/models/properties/position_property_spec.rb +90 -0
  166. data/spec/metro/models/ui/label_spec.rb +259 -0
  167. data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
  168. data/spec/metro/scene_spec.rb +15 -0
  169. data/spec/metro/scene_views/json_view_spec.rb +27 -0
  170. data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
  171. data/spec/metro/scenes_spec.rb +77 -0
  172. data/spec/metro/units/point_spec.rb +132 -0
  173. data/spec/metro/views/view_spec.rb +53 -0
  174. data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
  175. data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
  176. data/spec/spec_helper.rb +20 -0
  177. metadata +374 -0
@@ -0,0 +1,135 @@
1
+ module Metro
2
+
3
+ #
4
+ # The animation is an wrapper object for an array of Gosu::Images that also contains
5
+ # the additional information on the path, height, width, and tileability.
6
+ #
7
+ class Animation
8
+
9
+ attr_accessor :images, :path, :height, :width, :tileable, :time_per_image
10
+
11
+ def initialize(params = {})
12
+ @images = Array(params[:images])
13
+ @path = params[:path]
14
+ @height = params[:height]
15
+ @width = params[:width]
16
+ @tileable = params[:tileable]
17
+ @time_per_image = params[:time_per_image]
18
+ end
19
+
20
+ #
21
+ # @return a hash representation of the Animation
22
+ #
23
+ def to_hash
24
+ { path: path,
25
+ width: width.to_i, height: height.to_i,
26
+ tileable: !!tileable,
27
+ time_per_image: time_per_image }
28
+ end
29
+
30
+ #
31
+ # @return [Fixnum] the game time when the animation started to display.
32
+ #
33
+ def start_time
34
+ @start_time ||= current_time
35
+ end
36
+
37
+ #
38
+ # @return [Fixnum] the current time in the game.
39
+ #
40
+ def current_time
41
+ Gosu::milliseconds
42
+ end
43
+
44
+ #
45
+ # @return [Fixnum] the age of the animation.
46
+ #
47
+ def age
48
+ current_time - start_time
49
+ end
50
+
51
+ #
52
+ # @return the current animation image count.
53
+ #
54
+ def current_index
55
+ age / time_per_image
56
+ end
57
+
58
+ #
59
+ # @return the current animation image to display.
60
+ #
61
+ def current_image_index
62
+ current_index % images.size
63
+ end
64
+
65
+ #
66
+ # @return the animation is complete if it the current index exceeds the
67
+ # number of images.
68
+ #
69
+ def complete?
70
+ current_index > (images.size - 1)
71
+ end
72
+
73
+ #
74
+ # @return a Gosu::Image to be displayed in a animation sequence.
75
+ #
76
+ def image
77
+ images[current_image_index]
78
+ end
79
+
80
+ #
81
+ # Finds an existing image or creates a new image given the window, path,
82
+ # width, height and tileablilty.
83
+ #
84
+ # @example Finding or creating an Animation image
85
+ #
86
+ # Metro::Animation.find_or_create window: model.window,
87
+ # path: "asset_path", tileable: tileable, width: 64, height: 64,
88
+ # time_per_image: 50
89
+ #
90
+ def self.find_or_create(options)
91
+ new options.merge(images: find_or_create_gosu_images(options))
92
+ end
93
+
94
+ #
95
+ # Create an animation image given the window, path, width, height,
96
+ # and tileability.
97
+ #
98
+ # @example Creating an Animation Image
99
+ #
100
+ # Metro::Animation.create window: model.window,
101
+ # path: "asset_path", tileable: tileable, width: 64, height: 64,
102
+ # time_per_image: 50
103
+ #
104
+ def self.create(options)
105
+ new options.merge(images: create_gosu_images(options))
106
+ end
107
+
108
+ private
109
+
110
+ def self.create_gosu_images(options)
111
+ path = AssetPath.with(options[:path]).to_s
112
+ images[path] = Gosu::Image.load_tiles(*create_params(options))
113
+ end
114
+
115
+ def self.find_or_create_gosu_images(options)
116
+ path = AssetPath.with(options[:path]).to_s
117
+ images[path] or create_gosu_images(options)
118
+ end
119
+
120
+ def self.create_params(options)
121
+ options.symbolize_keys!
122
+ window = options[:window]
123
+ asset_path = AssetPath.with(options[:path]).filepath
124
+ width = options[:width].to_i
125
+ height = options[:height].to_i
126
+ tileable = !!options[:tileable]
127
+ [ window, asset_path, width, height, tileable ]
128
+ end
129
+
130
+ def self.images
131
+ @images ||= {}
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,12 @@
1
+ module Metro
2
+
3
+ class AfterIntervalFactory
4
+ attr_reader :ticks, :block
5
+
6
+ def initialize(ticks,&block)
7
+ @ticks = ticks
8
+ @block = block
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,15 @@
1
+ module Metro
2
+
3
+ class AnimationFactory
4
+
5
+ attr_reader :actor, :options, :on_complete_block
6
+
7
+ def initialize(actor,options = {},&block)
8
+ @actor = actor
9
+ @options = options
10
+ @on_complete_block = block
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module Metro
2
+ class Easing
3
+
4
+ #
5
+ # Perform a ease-in motion between the start position and the final position.
6
+ #
7
+ class EaseIn < Easing
8
+ def self.calculation(moment,start,change,interval)
9
+ change * (moment = moment / interval) * moment + start
10
+ end
11
+ end
12
+
13
+ register :ease_in, EaseIn
14
+ end
15
+ end
@@ -0,0 +1,51 @@
1
+ module Metro
2
+
3
+ #
4
+ # An easing is a means to calculate the steps between the start and the final
5
+ # over an interval.
6
+ #
7
+ class Easing
8
+
9
+ #
10
+ # The calculate method is called within the ImplicitAnimation and will create
11
+ # an array of all the states between the start and the final value.
12
+ #
13
+ def self.calculate(start,final,interval)
14
+ change = final - start
15
+ (1..interval).map { |time| calculation(time.to_f,start,change,interval) }
16
+ end
17
+
18
+ #
19
+ # The calculation method is to be overriden in the Easing subclasses.
20
+ # This calculation figures out the value at the current moemnt.
21
+ #
22
+ def self.calculation(moment,start,change,interval) ; 0 ; end
23
+
24
+ #
25
+ # Register an easing within the game system.
26
+ #
27
+ def self.register(name,easing_class)
28
+ easings[name] = easing_class.to_s
29
+ end
30
+
31
+ #
32
+ # @return the easing class based on the specified easing name.
33
+ #
34
+ def self.easing_for(easing)
35
+ easing_classname = easings[easing]
36
+ easing_classname.constantize
37
+ end
38
+
39
+ #
40
+ # A hash of all the supported easings within metro or game.
41
+ #
42
+ def self.easings
43
+ @easings_hash ||= HashWithIndifferentAccess.new("Metro::Easing::Linear")
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ require_relative 'linear'
51
+ require_relative 'ease_in'
@@ -0,0 +1,15 @@
1
+ module Metro
2
+ class Easing
3
+
4
+ #
5
+ # Perform a linear motion between the start position and the final position.
6
+ #
7
+ class Linear < Easing
8
+ def self.calculation(moment,start,change,interval)
9
+ change * moment / interval + start
10
+ end
11
+ end
12
+
13
+ register :linear, Linear
14
+ end
15
+ end
@@ -0,0 +1,70 @@
1
+ require_relative 'animation_factory'
2
+
3
+ module Metro
4
+ module HasAnimations
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ #
11
+ # Define an animation from within another animation block, an event block
12
+ # or a method.
13
+ #
14
+ # @example Defining an animation that fades out the hero when they have
15
+ # died.
16
+ #
17
+ # class HellScene
18
+ # draws :hero
19
+ #
20
+ # def update
21
+ # if hero.dead?
22
+ # animate :hero, to: { alpha: 0 }, interval: 60.ticks do
23
+ # transition_to :game_over
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # end
29
+ #
30
+ def animate(actor_or_actor_name,options,&block)
31
+ options[:actor] = actor(actor_or_actor_name)
32
+ options[:context] = self
33
+ animation_group = SceneAnimation.build options, &block
34
+ enqueue animation_group
35
+ end
36
+
37
+ # An alternative to stating `animate` syntax.
38
+ alias_method :change, :animate
39
+
40
+ module ClassMethods
41
+
42
+ #
43
+ # Define an animation to execute when the scene starts.
44
+ #
45
+ # @example Defining an animation that fades in and moves a logo when it is
46
+ # done, transition to the title scene.
47
+ #
48
+ # animate :logo, to: { y: 80, alpha: 50 }, interval: 120.ticks do
49
+ # transition_to :title
50
+ # end
51
+ #
52
+ def animate(actor_name,options,&block)
53
+ scene_animation = AnimationFactory.new actor_name, options, &block
54
+ animations.push scene_animation
55
+ end
56
+
57
+ # Provide an alternative to the `animate` syntax.
58
+ alias_method :change, :animate
59
+
60
+ #
61
+ # All the animations that are defined for the scene to be run the scene starts.
62
+ #
63
+ def animations
64
+ @animations ||= []
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,100 @@
1
+ require_relative 'easing/easing'
2
+
3
+ module Metro
4
+
5
+ #
6
+ # An Implicit Animation is an animation without all the work.
7
+ # This little animation will take care of figuring out moving an
8
+ # actor from one position to another, the rotation, the alpha,
9
+ # etc.
10
+ #
11
+ # @example Creating an explicit animation that moves a player
12
+ #
13
+ # animation = ImplicitAnimation.new actor: player,
14
+ # to: { x: final_x, y: final_y },
15
+ # interval: 80,
16
+ # easing: :ease_in,
17
+ # context: scene
18
+ #
19
+ # animation.on_complete do
20
+ # transition_to :main
21
+ # end
22
+ #
23
+ # Here an animation is created that will move the player to the
24
+ # position (final_x,final_y), specified in the :to hash that is
25
+ # provided, over the interval of 80 steps. Additionally the movement
26
+ # is done with an easing in.
27
+ #
28
+ # @note The actor object must respond to setter methods that match
29
+ # the specified attributes (e.g. x, y).
30
+ #
31
+ # The context provided is the context that the 'on_complete' block
32
+ # is executed. In this case, upon completition, transition the scene
33
+ # from the current one to the main scene.
34
+ #
35
+ class ImplicitAnimation < OnUpdateOperation
36
+
37
+ def animations
38
+ @animations ||= []
39
+ end
40
+
41
+ #
42
+ # @return the type of easing that the implicit animation should employ.
43
+ # By default it uses linear but can be overridden when the easing is
44
+ # configured.
45
+ #
46
+ attr_reader :easing
47
+
48
+ #
49
+ # Additional initializion is required to calculate the attributes
50
+ # that are going to be animated and to determine each of their deltas.
51
+ #
52
+ def after_initialize
53
+ to.each do |attribute,final|
54
+ start = actor.send(attribute)
55
+ animations.push build_animation_step(attribute,start,final)
56
+ end
57
+ end
58
+
59
+ def build_animation_step(attribute,start,final)
60
+ step = AnimationStep.new
61
+ step.actor = actor
62
+ step.attribute = attribute
63
+ step.deltas = easing_for(easing).calculate(start.to_f,final.to_f,interval.to_f)
64
+ step
65
+ end
66
+
67
+ class AnimationStep
68
+ attr_accessor :actor, :attribute, :deltas
69
+
70
+ def execute_step(step)
71
+ actor.set(attribute,deltas.at(step))
72
+ end
73
+ end
74
+
75
+ #
76
+ # @return the correct easing based on the specified name. When the name
77
+ # provided does not match anything then default to linear easing.
78
+ #
79
+ def easing_for(name)
80
+ Metro::Easing.easing_for(name)
81
+ end
82
+
83
+ #
84
+ # The ImplicitAnimation overrides the {Animation#execute_step} and
85
+ # updates the attributes of the actor based upon the value of the
86
+ # current animation step.
87
+ #
88
+ def execute_step
89
+ animations.each {|step| step.execute_step(current_step) }
90
+ end
91
+
92
+ #
93
+ # @return the delta for the attribute for the given step
94
+ #
95
+ def delta_for_step(attribute)
96
+ deltas[attribute].at(current_step)
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,96 @@
1
+ module Metro
2
+
3
+ #
4
+ # OnUpdateOperation is an object that executes on the update cycle
5
+ # of the game. This usually take the form of an animation or some operation
6
+ # that needs to execute with each update of the game.
7
+ #
8
+ class OnUpdateOperation
9
+
10
+ def after_initialize ; end
11
+
12
+ def initialize(options)
13
+ @current_step = 0
14
+
15
+ options.each do |key,value|
16
+ send :instance_variable_set, "@#{key}".to_sym, value
17
+ self.class.send :define_method, key do
18
+ instance_variable_get("@#{key}")
19
+ end
20
+ end
21
+ after_initialize
22
+ end
23
+
24
+ #
25
+ # Sets the action that happens with each step of the animation.
26
+ #
27
+ def on_step(&block)
28
+ @step_block = block
29
+ end
30
+
31
+ #
32
+ # Sets the action that happens when the animation is completed.
33
+ #
34
+ def on_complete(&block)
35
+ @complete_block = block
36
+ end
37
+
38
+ #
39
+ # Perform a step of an animation, if it hasn't already been completed.
40
+ #
41
+ def update
42
+ return if completed?
43
+
44
+ execute_step
45
+ next_step
46
+
47
+ complete! if completed?
48
+ end
49
+
50
+ #
51
+ # @return the current step of the animation.
52
+ #
53
+ attr_reader :current_step
54
+
55
+ attr_reader :step_block, :complete_block
56
+
57
+ #
58
+ # Move to the next step in the animation.
59
+ #
60
+ def next_step
61
+ @current_step = current_step + step_interval
62
+ end
63
+
64
+ #
65
+ # @return the interval at which the animation take place.
66
+ #
67
+ def step_interval
68
+ 1
69
+ end
70
+
71
+ #
72
+ # @return true if the animation has completed all the actions, false
73
+ # if there are remaining actions.
74
+ #
75
+ def completed?
76
+ current_step >= interval
77
+ end
78
+
79
+ #
80
+ # Perform the action that happens with each step of the animation.
81
+ #
82
+ def execute_step
83
+ context.instance_eval(&@step_block) if step_block and context
84
+ end
85
+
86
+ #
87
+ # Perform the action that happens when the animation is completed.
88
+ #
89
+ def complete!
90
+ context.instance_eval(&@complete_block) if complete_block and context
91
+ end
92
+
93
+ end
94
+ end
95
+
96
+ require_relative 'implicit_animation'