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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +12 -0
- data/Guardfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +189 -0
- data/Rakefile +18 -0
- data/bin/metro +16 -0
- data/changelog.md +157 -0
- data/lib/assets/menu-movement.wav +0 -0
- data/lib/assets/menu-selection.wav +0 -0
- data/lib/assets/missing.ogg +0 -0
- data/lib/assets/missing.png +0 -0
- data/lib/assets/missing.wav +0 -0
- data/lib/assets/missing_animation.png +0 -0
- data/lib/commands/generate_game.rb +13 -0
- data/lib/commands/generate_model.rb +25 -0
- data/lib/commands/generate_scene.rb +36 -0
- data/lib/commands/generate_view.rb +21 -0
- data/lib/commands/thor.rb +83 -0
- data/lib/core_ext/class.rb +14 -0
- data/lib/core_ext/numeric.rb +59 -0
- data/lib/gosu_ext/color.rb +62 -0
- data/lib/gosu_ext/gosu_constants.rb +53 -0
- data/lib/locale/en.yml +35 -0
- data/lib/locale/locale.rb +1 -0
- data/lib/metro.rb +140 -0
- data/lib/metro/animation.rb +135 -0
- data/lib/metro/animation/after_interval_factory.rb +12 -0
- data/lib/metro/animation/animation_factory.rb +15 -0
- data/lib/metro/animation/easing/ease_in.rb +15 -0
- data/lib/metro/animation/easing/easing.rb +51 -0
- data/lib/metro/animation/easing/linear.rb +15 -0
- data/lib/metro/animation/has_animations.rb +70 -0
- data/lib/metro/animation/implicit_animation.rb +100 -0
- data/lib/metro/animation/on_update_operation.rb +96 -0
- data/lib/metro/animation/scene_animation.rb +16 -0
- data/lib/metro/asset_path.rb +97 -0
- data/lib/metro/events/control_definition.rb +11 -0
- data/lib/metro/events/controls.rb +42 -0
- data/lib/metro/events/event_data.rb +60 -0
- data/lib/metro/events/event_dictionary.rb +52 -0
- data/lib/metro/events/event_factory.rb +17 -0
- data/lib/metro/events/event_relay.rb +300 -0
- data/lib/metro/events/event_state_manager.rb +63 -0
- data/lib/metro/events/events.rb +3 -0
- data/lib/metro/events/has_events.rb +108 -0
- data/lib/metro/events/hit_list.rb +75 -0
- data/lib/metro/events/unknown_sender.rb +5 -0
- data/lib/metro/font.rb +69 -0
- data/lib/metro/game.rb +102 -0
- data/lib/metro/game/dsl.rb +68 -0
- data/lib/metro/image.rb +68 -0
- data/lib/metro/logging.rb +33 -0
- data/lib/metro/missing_scene.rb +21 -0
- data/lib/metro/models/audio/song.rb +33 -0
- data/lib/metro/models/draws.rb +86 -0
- data/lib/metro/models/key_value_coding.rb +38 -0
- data/lib/metro/models/model.rb +236 -0
- data/lib/metro/models/model_factory.rb +32 -0
- data/lib/metro/models/models.rb +62 -0
- data/lib/metro/models/properties/animation_property.rb +115 -0
- data/lib/metro/models/properties/array_property.rb +24 -0
- data/lib/metro/models/properties/boolean_property.rb +27 -0
- data/lib/metro/models/properties/color_property.rb +116 -0
- data/lib/metro/models/properties/dimensions_property.rb +84 -0
- data/lib/metro/models/properties/font_property.rb +130 -0
- data/lib/metro/models/properties/image_property.rb +96 -0
- data/lib/metro/models/properties/model_property.rb +84 -0
- data/lib/metro/models/properties/numeric_property.rb +29 -0
- data/lib/metro/models/properties/options_property/no_option.rb +29 -0
- data/lib/metro/models/properties/options_property/options.rb +94 -0
- data/lib/metro/models/properties/options_property/options_property.rb +125 -0
- data/lib/metro/models/properties/position_property.rb +90 -0
- data/lib/metro/models/properties/property.rb +221 -0
- data/lib/metro/models/properties/property_owner.rb +137 -0
- data/lib/metro/models/properties/sample_property.rb +84 -0
- data/lib/metro/models/properties/scale_property.rb +80 -0
- data/lib/metro/models/properties/song_property.rb +89 -0
- data/lib/metro/models/properties/text_property.rb +75 -0
- data/lib/metro/models/ui/animated_sprite.rb +85 -0
- data/lib/metro/models/ui/border.rb +95 -0
- data/lib/metro/models/ui/fps.rb +54 -0
- data/lib/metro/models/ui/generic.rb +66 -0
- data/lib/metro/models/ui/grid_drawer.rb +74 -0
- data/lib/metro/models/ui/image.rb +87 -0
- data/lib/metro/models/ui/label.rb +175 -0
- data/lib/metro/models/ui/menu.rb +214 -0
- data/lib/metro/models/ui/model_label.rb +65 -0
- data/lib/metro/models/ui/model_labeler.rb +79 -0
- data/lib/metro/models/ui/rectangle.rb +59 -0
- data/lib/metro/models/ui/sprite.rb +79 -0
- data/lib/metro/models/ui/tile_map.rb +162 -0
- data/lib/metro/models/ui/ui.rb +13 -0
- data/lib/metro/parameters/command_line_args_parser.rb +68 -0
- data/lib/metro/parameters/options.rb +25 -0
- data/lib/metro/parameters/parameters.rb +2 -0
- data/lib/metro/sample.rb +40 -0
- data/lib/metro/scene.rb +477 -0
- data/lib/metro/scenes.rb +154 -0
- data/lib/metro/song.rb +56 -0
- data/lib/metro/template_message.rb +60 -0
- data/lib/metro/transitions/edit_transition_scene.rb +100 -0
- data/lib/metro/transitions/fade_transition_scene.rb +66 -0
- data/lib/metro/transitions/scene_transitions.rb +44 -0
- data/lib/metro/transitions/transition_scene.rb +19 -0
- data/lib/metro/units/bounds.rb +8 -0
- data/lib/metro/units/calculation_validations.rb +74 -0
- data/lib/metro/units/dimensions.rb +60 -0
- data/lib/metro/units/point.rb +51 -0
- data/lib/metro/units/rectangle_bounds.rb +85 -0
- data/lib/metro/units/scale.rb +46 -0
- data/lib/metro/units/units.rb +6 -0
- data/lib/metro/version.rb +32 -0
- data/lib/metro/views/json_view.rb +60 -0
- data/lib/metro/views/no_view.rb +34 -0
- data/lib/metro/views/parsers.rb +42 -0
- data/lib/metro/views/scene_view.rb +107 -0
- data/lib/metro/views/view.rb +133 -0
- data/lib/metro/views/writers.rb +43 -0
- data/lib/metro/views/yaml_view.rb +94 -0
- data/lib/metro/window.rb +94 -0
- data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
- data/lib/setup_handlers/game_execution.rb +65 -0
- data/lib/setup_handlers/load_game_configuration.rb +65 -0
- data/lib/setup_handlers/load_game_files.rb +101 -0
- data/lib/setup_handlers/move_to_game_directory.rb +25 -0
- data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
- data/lib/templates/game/README.md.tt +52 -0
- data/lib/templates/game/assets/brand.jpg +0 -0
- data/lib/templates/game/assets/hero.png +0 -0
- data/lib/templates/game/lib/custom_easing.rb +32 -0
- data/lib/templates/game/metro.tt +63 -0
- data/lib/templates/game/models/hero.rb +62 -0
- data/lib/templates/game/scenes/brand_scene.rb +19 -0
- data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
- data/lib/templates/game/scenes/first_scene.rb +28 -0
- data/lib/templates/game/scenes/game_scene.rb +43 -0
- data/lib/templates/game/scenes/title_scene.rb +15 -0
- data/lib/templates/game/views/brand.yaml +4 -0
- data/lib/templates/game/views/brand_to_title.yaml +8 -0
- data/lib/templates/game/views/first.yaml +26 -0
- data/lib/templates/game/views/title.yaml +11 -0
- data/lib/templates/message.erb +23 -0
- data/lib/templates/model.rb.tt +111 -0
- data/lib/templates/scene.rb.tt +140 -0
- data/lib/templates/view.yaml.tt +11 -0
- data/lib/tmxed_ext/tile_set.rb +34 -0
- data/metro.gemspec +56 -0
- data/spec/core_ext/numeric_spec.rb +78 -0
- data/spec/core_ext/string_spec.rb +33 -0
- data/spec/gosu_ext/color_spec.rb +80 -0
- data/spec/metro/events/event_state_manager_spec.rb +5 -0
- data/spec/metro/models/key_value_coding_spec.rb +61 -0
- data/spec/metro/models/properties/array_property_spec.rb +60 -0
- data/spec/metro/models/properties/color_property_spec.rb +85 -0
- data/spec/metro/models/properties/dimensions_spec.rb +29 -0
- data/spec/metro/models/properties/font_property_spec.rb +127 -0
- data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
- data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
- data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
- data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
- data/spec/metro/models/properties/position_property_spec.rb +90 -0
- data/spec/metro/models/ui/label_spec.rb +259 -0
- data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
- data/spec/metro/scene_spec.rb +15 -0
- data/spec/metro/scene_views/json_view_spec.rb +27 -0
- data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
- data/spec/metro/scenes_spec.rb +77 -0
- data/spec/metro/units/point_spec.rb +132 -0
- data/spec/metro/views/view_spec.rb +53 -0
- data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
- data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
- data/spec/spec_helper.rb +20 -0
- 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,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'
|