metro 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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