metro 0.1.2 → 0.1.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 (49) hide show
  1. data/README.md +29 -13
  2. data/changelog.md +10 -0
  3. data/lib/core_ext/numeric.rb +59 -0
  4. data/lib/gosu_ext/gosu_constants.rb +53 -0
  5. data/lib/locale/en.yml +16 -0
  6. data/lib/locale/locale.rb +1 -0
  7. data/lib/metro.rb +30 -16
  8. data/lib/metro/animation/after_interval_factory.rb +12 -0
  9. data/lib/metro/animation/animation_factory.rb +3 -2
  10. data/lib/metro/animation/has_animations.rb +3 -3
  11. data/lib/metro/animation/implicit_animation.rb +33 -19
  12. data/lib/metro/animation/{animation.rb → on_update_operation.rb} +6 -4
  13. data/lib/metro/animation/scene_animation.rb +16 -0
  14. data/lib/metro/events/control_definition.rb +11 -0
  15. data/lib/metro/events/controls.rb +42 -0
  16. data/lib/metro/events/event_relay.rb +49 -11
  17. data/lib/metro/events/has_events.rb +6 -5
  18. data/lib/metro/game.rb +17 -11
  19. data/lib/metro/game/dsl.rb +8 -0
  20. data/lib/metro/models/image.rb +3 -1
  21. data/lib/metro/models/key_value_coding.rb +38 -0
  22. data/lib/metro/models/label.rb +18 -3
  23. data/lib/metro/models/menu.rb +6 -5
  24. data/lib/metro/models/model.rb +11 -4
  25. data/lib/metro/models/rectangle.rb +28 -0
  26. data/lib/metro/scene.rb +76 -15
  27. data/lib/metro/scene_view/yaml_view.rb +11 -4
  28. data/lib/metro/scenes.rb +27 -3
  29. data/lib/metro/template_message.rb +33 -4
  30. data/lib/metro/transitions/fade_transition_scene.rb +59 -0
  31. data/lib/metro/transitions/scene_transitions.rb +30 -0
  32. data/lib/metro/transitions/transition_scene.rb +18 -0
  33. data/lib/metro/version.rb +1 -1
  34. data/lib/metro/window.rb +0 -2
  35. data/lib/templates/game/metro.tt +13 -0
  36. data/lib/templates/game/scenes/brand_scene.rb +10 -4
  37. data/lib/templates/game/scenes/brand_to_title_scene.rb +3 -3
  38. data/lib/templates/game/scenes/title_scene.rb +1 -1
  39. data/lib/templates/game/views/brand_to_title.yaml +2 -4
  40. data/lib/templates/game/views/title.yaml +2 -4
  41. data/lib/templates/message.erb +1 -1
  42. data/lib/templates/model.rb.erb +2 -2
  43. data/lib/templates/scene.rb.erb +3 -3
  44. data/metro.gemspec +1 -0
  45. data/spec/core_ext/numeric_spec.rb +78 -0
  46. data/spec/metro/models/key_value_coding_spec.rb +61 -0
  47. data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
  48. metadata +44 -6
  49. data/lib/metro/error.rb +0 -21
@@ -10,25 +10,26 @@ module Metro
10
10
  #
11
11
  class Menu < Model
12
12
 
13
- event :on_up, Gosu::KbLeft, Gosu::GpLeft, Gosu::KbUp, Gosu::GpUp do
13
+ event :on_up, KbLeft, GpLeft, KbUp, GpUp do
14
14
  previous_option
15
15
  end
16
16
 
17
- event :on_up, Gosu::KbRight, Gosu::GpRight, Gosu::KbDown, Gosu::GpDown do
17
+ event :on_up, KbRight, GpRight, KbDown, GpDown do
18
18
  next_option
19
19
  end
20
20
 
21
- event :on_up, Gosu::KbEnter, Gosu::KbReturn, Gosu::GpButton0 do
21
+ event :on_up, KbEnter, KbReturn, GpButton0 do
22
22
  selection
23
23
  end
24
24
 
25
25
  attr_reader :selected_index, :menu_options
26
26
 
27
- attr_accessor :padding
27
+ attr_accessor :padding, :z_order
28
28
 
29
29
  def after_initialize
30
30
  @selected_index = 0
31
31
  @padding = 40
32
+ @z_order = 1
32
33
  end
33
34
 
34
35
  def window=(value)
@@ -79,7 +80,7 @@ module Metro
79
80
  draw_color = highlight_color if index == selected_index
80
81
 
81
82
  y_position = y + padding * index
82
- font.draw option_name, x, y_position, Metro::Game::UI, 1.0, 1.0, draw_color
83
+ font.draw option_name, x, y_position, z_order, 1.0, 1.0, draw_color
83
84
  end
84
85
  end
85
86
 
@@ -1,3 +1,5 @@
1
+ require_relative 'key_value_coding'
2
+
1
3
  module Metro
2
4
 
3
5
  #
@@ -32,6 +34,8 @@ module Metro
32
34
  # @see Scene
33
35
  attr_accessor :scene
34
36
 
37
+ include KeyValueCoding
38
+
35
39
  #
36
40
  # This is an entry point for customization. As the model's {#initialize}
37
41
  # method performs may perform some initialization that may be necessary.
@@ -44,14 +48,14 @@ module Metro
44
48
  # Generate a custom notification event with the given name.
45
49
  #
46
50
  # @param [Symbol] event the name of the notification to generate.
47
- #
51
+ #
48
52
  def notification(event)
49
53
  scene.notification(event.to_sym)
50
54
  end
51
55
 
52
56
  #
53
57
  # Allows for the definition of events within the scene.
54
- #
58
+ #
55
59
  include HasEvents
56
60
 
57
61
  #
@@ -62,7 +66,9 @@ module Metro
62
66
  #
63
67
  # @see #alpha
64
68
  #
65
- attr_reader :color
69
+ def color
70
+ @color
71
+ end
66
72
 
67
73
  #
68
74
  # Sets the color of the model.
@@ -199,4 +205,5 @@ end
199
205
  require_relative 'generic'
200
206
  require_relative 'label'
201
207
  require_relative 'menu'
202
- require_relative 'image'
208
+ require_relative 'image'
209
+ require_relative 'rectangle'
@@ -0,0 +1,28 @@
1
+ module Metro
2
+ module Models
3
+
4
+ class Rectangle < ::Metro::Model
5
+
6
+ attr_accessor :x, :y, :z_order, :width, :height
7
+
8
+ def after_initialize
9
+ @x = @y = 0
10
+ @z_order = 1
11
+ end
12
+
13
+ def width
14
+ @width || window.width
15
+ end
16
+
17
+ def height
18
+ @height || window.height
19
+ end
20
+
21
+ def draw
22
+ window.draw_quad(x,y,color,width,x,color,
23
+ width,height,color,y,height,color,
24
+ z_order)
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/metro/scene.rb CHANGED
@@ -7,7 +7,8 @@ require_relative 'events/unknown_sender'
7
7
  require_relative 'models/draws'
8
8
 
9
9
  require_relative 'animation/has_animations'
10
- require_relative 'animation/animation'
10
+ require_relative 'animation/scene_animation'
11
+ require_relative 'animation/after_interval_factory'
11
12
 
12
13
  module Metro
13
14
 
@@ -91,8 +92,12 @@ module Metro
91
92
  #
92
93
  # @return the actor with the given name.
93
94
  #
94
- def actor(name)
95
- send(name)
95
+ def actor(actor_or_actor_name)
96
+ if actor_or_actor_name.is_a? String or actor_or_actor_name.is_a? Symbol
97
+ send(actor_or_actor_name)
98
+ else
99
+ actor_or_actor_name
100
+ end
96
101
  end
97
102
 
98
103
  #
@@ -125,6 +130,47 @@ module Metro
125
130
  #
126
131
  include HasAnimations
127
132
 
133
+ #
134
+ # Allow the definition of a updater that will be executed when the scene starts.
135
+ #
136
+ # @example Setting up an event to 2 seconds after the scene has started.
137
+ #
138
+ # class ExampleScene
139
+ #
140
+ # draws :title
141
+ #
142
+ # after 2.seconds do
143
+ # transition_to :next_scene
144
+ # end
145
+ # end
146
+ #
147
+ def self.after(ticks,&block)
148
+ after_intervals.push AfterIntervalFactory.new ticks, &block
149
+ end
150
+
151
+ #
152
+ # Perform an operation after the specified interval.
153
+ #
154
+ # class ExampleScene
155
+ #
156
+ # draws :player
157
+ #
158
+ # def update
159
+ # if player.is_dead?
160
+ # after 2.seconds do
161
+ # transition_to :game_over
162
+ # end
163
+ # end
164
+ # end
165
+ #
166
+ # end
167
+ #
168
+ def after(ticks,&block)
169
+ tick = OnUpdateOperation.new interval: ticks, context: self
170
+ tick.on_complete(&block)
171
+ enqueue tick
172
+ end
173
+
128
174
  #
129
175
  # Setups up the Actors for the Scene based on the ModelFactories that have been
130
176
  # defined.
@@ -166,6 +212,7 @@ module Metro
166
212
  register_events!
167
213
  register_actors!
168
214
  register_animations!
215
+ register_after_intervals!
169
216
 
170
217
  show
171
218
  end
@@ -189,7 +236,13 @@ module Metro
189
236
  #
190
237
  def register_animations!
191
238
  self.class.animations.each do |animation|
192
- animate animation.options, &animation.on_complete_block
239
+ animate animation.actor, animation.options, &animation.on_complete_block
240
+ end
241
+ end
242
+
243
+ def register_after_intervals!
244
+ self.class.after_intervals.each do |after_interval|
245
+ after after_interval.ticks, &after_interval.block
193
246
  end
194
247
  end
195
248
 
@@ -282,13 +335,20 @@ module Metro
282
335
  # A simplier syntax to enqueue an animation. At the moment this animation is going
283
336
  # to be an implicit animation.
284
337
  #
285
- def animate(options,&block)
286
- options[:actor] = actor(options[:actor]) if options[:actor].is_a? Symbol
287
- animation = Metro::ImplicitAnimation.new options.merge(context: self)
288
- animation.on_complete(&block) if block
289
- enqueue animation
338
+ def animate(actor_or_actor_name,options,&block)
339
+ options[:actor] = actor(actor_or_actor_name)
340
+ options[:context] = self
341
+ animation_group = SceneAnimation.build options, &block
342
+ enqueue animation_group
290
343
  end
291
344
 
345
+ #
346
+ # The class defined updaters which will be converted to instance updaters when the scene
347
+ # has started.
348
+ #
349
+ def self.after_intervals
350
+ @after_intervals ||= []
351
+ end
292
352
 
293
353
  #
294
354
  # The objects that need to be executed on every update. These objects are traditionally
@@ -334,11 +394,12 @@ module Metro
334
394
  # `transition_to` performs the work of transitioning this scene
335
395
  # to another scene.
336
396
  #
337
- # @param [String,Symbol,Class] scene_name the name of the Scene which can be either
338
- # the class or a string/symbol representation of the shortened scene name.
397
+ # @param [String,Symbol,Object] scene_or_scene_name the name of the Scene which can
398
+ # be either the class or a string/symbol representation of the shortened scene name.
399
+ # This could also be an instance of scene.
339
400
  #
340
- def transition_to(scene_name)
341
- new_scene = Scenes.generate(scene_name)
401
+ def transition_to(scene_or_scene_name,options = {})
402
+ new_scene = Scenes.generate(scene_or_scene_name,options)
342
403
  _prepare_transition(new_scene)
343
404
  window.scene = new_scene
344
405
  end
@@ -412,7 +473,7 @@ module Metro
412
473
  #
413
474
  def button_up(id)
414
475
  event_relays.each do |relay|
415
- relay.button_up(id)
476
+ relay.fire_button_up(id)
416
477
  end
417
478
  end
418
479
 
@@ -422,7 +483,7 @@ module Metro
422
483
  #
423
484
  def button_down(id)
424
485
  event_relays.each do |relay|
425
- relay.button_down(id)
486
+ relay.fire_button_down(id)
426
487
  end
427
488
  end
428
489
 
@@ -12,7 +12,7 @@ module Metro
12
12
  # @return a true if the yaml view exists and false if it does not exist.
13
13
  #
14
14
  def self.exists?(view_name)
15
- File.exists? yaml_view_name(view_name)
15
+ yaml_view_names(view_name).find { |view_name| File.exists? view_name }
16
16
  end
17
17
 
18
18
  #
@@ -25,12 +25,19 @@ module Metro
25
25
  YAML.load File.read yaml_view_name(view_name)
26
26
  end
27
27
 
28
+ #
29
+ # A helper method to get the view file.
30
+ #
31
+ def self.yaml_view_name(view_name)
32
+ yaml_view_names(view_name).find { |view_name| File.exists? view_name }
33
+ end
34
+
28
35
  #
29
36
  # A helper method to generate the name of the yaml view file. In this case
30
- # it is the view name with the suffix .yaml.
37
+ # it is the view name with the suffix `.yaml` or `.yml`.
31
38
  #
32
- def self.yaml_view_name(view_name)
33
- File.extname(view_name) == "" ? "#{view_name}.yaml" : view_name
39
+ def self.yaml_view_names(view_name)
40
+ File.extname(view_name) == "" ? [ "#{view_name}.yaml", "#{view_name}.yml" ] : [ view_name ]
34
41
  end
35
42
  end
36
43
 
data/lib/metro/scenes.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require_relative 'transitions/scene_transitions'
2
+
1
3
  module Metro
2
4
 
3
5
  #
@@ -49,11 +51,33 @@ module Metro
49
51
  # Finds the scene with the specified name and then creates an instance of that
50
52
  # scene.
51
53
  #
52
- # @param [String,Symbol] scene_name the name of the scene to locate.
54
+ # @param [String,Symbol,Object] scene_name the name of the scene to locate.
53
55
  # @return an instance of Scene that is found matching the specified scene name
54
56
  #
55
- def generate(scene_name)
56
- find(scene_name).new
57
+ def generate(scene_or_scene_name,options = {})
58
+ new_scene = use_scene_or_generate_scene(scene_or_scene_name)
59
+
60
+ post_filters.inject(new_scene) {|scene,post| post.filter(scene,options) }
61
+ end
62
+
63
+ #
64
+ # If we have been given a scene, then we simply want to use it otherwise
65
+ # we need to find and generate our scene from the scene name.
66
+ #
67
+ def use_scene_or_generate_scene(scene_or_scene_name)
68
+ if scene_or_scene_name.is_a? Scene
69
+ scene_or_scene_name
70
+ else
71
+ find(scene_or_scene_name).new
72
+ end
73
+ end
74
+
75
+ #
76
+ # Post filters are applied to the scene after it has been found. These are
77
+ # all objects that can respond to the #filter method.
78
+ #
79
+ def post_filters
80
+ [ SceneTransitions ]
57
81
  end
58
82
 
59
83
  private
@@ -2,18 +2,47 @@ class TemplateMessage
2
2
 
3
3
  def initialize(details = {})
4
4
  @messages = Array(details[:message]) + Array(details[:messages])
5
+ @details = details[:details]
5
6
  @website = details[:website]
6
- @email = Array(details[:email])
7
+ @email = details[:contact]
7
8
  end
8
9
 
9
- attr_reader :messages
10
+ class Message
11
+
12
+ attr_reader :name, :details
13
+
14
+ def initialize(name,details)
15
+ @name = name
16
+ @details = details
17
+ end
18
+
19
+ def field_locale(field)
20
+ I18n.t("#{name}.#{field}",details)
21
+ end
22
+
23
+ def title
24
+ field_locale 'title'
25
+ end
26
+
27
+ def message
28
+ field_locale 'message'
29
+ end
30
+
31
+ def actions
32
+ Array( field_locale('actions') ).map {|action| "* #{action}" }.join("\n")
33
+ end
34
+ end
35
+
36
+ def messages
37
+ @messages.map {|m| Message.new m, @details }
38
+ end
10
39
 
11
40
  def website
12
- "* #{@website}"
41
+ Array(@website).map {|website| "* #{website}" }.join("\n")
13
42
  end
14
43
 
15
44
  def email
16
- @email.map {|email| "* #{email}" }.join("\n")
45
+ Array(@email).map {|email| "* #{email}" }.join("\n")
17
46
  end
18
47
 
19
48
  def message_filename
@@ -0,0 +1,59 @@
1
+ module Metro
2
+ class FadeTransitionScene < TransitionScene
3
+
4
+ draw :rectangle, model: "metro::models::rectangle"
5
+
6
+ #
7
+ # When the scene is shown set up the starting color for the rectangle
8
+ # and queue the animation to transition the color to the final color.
9
+ #
10
+ def show
11
+ rectangle.color = starting_color
12
+
13
+ animate :rectangle, to: { color: final_color }, interval: interval do
14
+ transition_to next_scene
15
+ end
16
+ end
17
+
18
+ def interval
19
+ options[:interval] || default_interval
20
+ end
21
+
22
+ def default_interval
23
+ 60
24
+ end
25
+
26
+ def starting_color
27
+ options_starting_color || default_starting_color
28
+ end
29
+
30
+ def options_starting_color
31
+ color_from_options(:from)
32
+ end
33
+
34
+ def default_starting_color
35
+ Gosu::Color.new "rgb(255,255,255)"
36
+ end
37
+
38
+ def final_color
39
+ options_final_color || default_final_color
40
+ end
41
+
42
+ def options_final_color
43
+ color_from_options(:to)
44
+ end
45
+
46
+ def default_final_color
47
+ Gosu::Color.new "rgb(0,0,0)"
48
+ end
49
+
50
+ def color_from_options(position)
51
+ if options[position]
52
+ if options[position][:color]
53
+ Gosu::Color.new options[position][:color]
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end