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.
- data/README.md +29 -13
- data/changelog.md +10 -0
- data/lib/core_ext/numeric.rb +59 -0
- data/lib/gosu_ext/gosu_constants.rb +53 -0
- data/lib/locale/en.yml +16 -0
- data/lib/locale/locale.rb +1 -0
- data/lib/metro.rb +30 -16
- data/lib/metro/animation/after_interval_factory.rb +12 -0
- data/lib/metro/animation/animation_factory.rb +3 -2
- data/lib/metro/animation/has_animations.rb +3 -3
- data/lib/metro/animation/implicit_animation.rb +33 -19
- data/lib/metro/animation/{animation.rb → on_update_operation.rb} +6 -4
- data/lib/metro/animation/scene_animation.rb +16 -0
- data/lib/metro/events/control_definition.rb +11 -0
- data/lib/metro/events/controls.rb +42 -0
- data/lib/metro/events/event_relay.rb +49 -11
- data/lib/metro/events/has_events.rb +6 -5
- data/lib/metro/game.rb +17 -11
- data/lib/metro/game/dsl.rb +8 -0
- data/lib/metro/models/image.rb +3 -1
- data/lib/metro/models/key_value_coding.rb +38 -0
- data/lib/metro/models/label.rb +18 -3
- data/lib/metro/models/menu.rb +6 -5
- data/lib/metro/models/model.rb +11 -4
- data/lib/metro/models/rectangle.rb +28 -0
- data/lib/metro/scene.rb +76 -15
- data/lib/metro/scene_view/yaml_view.rb +11 -4
- data/lib/metro/scenes.rb +27 -3
- data/lib/metro/template_message.rb +33 -4
- data/lib/metro/transitions/fade_transition_scene.rb +59 -0
- data/lib/metro/transitions/scene_transitions.rb +30 -0
- data/lib/metro/transitions/transition_scene.rb +18 -0
- data/lib/metro/version.rb +1 -1
- data/lib/metro/window.rb +0 -2
- data/lib/templates/game/metro.tt +13 -0
- data/lib/templates/game/scenes/brand_scene.rb +10 -4
- data/lib/templates/game/scenes/brand_to_title_scene.rb +3 -3
- data/lib/templates/game/scenes/title_scene.rb +1 -1
- data/lib/templates/game/views/brand_to_title.yaml +2 -4
- data/lib/templates/game/views/title.yaml +2 -4
- data/lib/templates/message.erb +1 -1
- data/lib/templates/model.rb.erb +2 -2
- data/lib/templates/scene.rb.erb +3 -3
- data/metro.gemspec +1 -0
- data/spec/core_ext/numeric_spec.rb +78 -0
- data/spec/metro/models/key_value_coding_spec.rb +61 -0
- data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
- metadata +44 -6
- data/lib/metro/error.rb +0 -21
data/lib/metro/models/menu.rb
CHANGED
@@ -10,25 +10,26 @@ module Metro
|
|
10
10
|
#
|
11
11
|
class Menu < Model
|
12
12
|
|
13
|
-
event :on_up,
|
13
|
+
event :on_up, KbLeft, GpLeft, KbUp, GpUp do
|
14
14
|
previous_option
|
15
15
|
end
|
16
16
|
|
17
|
-
event :on_up,
|
17
|
+
event :on_up, KbRight, GpRight, KbDown, GpDown do
|
18
18
|
next_option
|
19
19
|
end
|
20
20
|
|
21
|
-
event :on_up,
|
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,
|
83
|
+
font.draw option_name, x, y_position, z_order, 1.0, 1.0, draw_color
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
data/lib/metro/models/model.rb
CHANGED
@@ -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
|
-
|
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/
|
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(
|
95
|
-
|
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(
|
287
|
-
|
288
|
-
|
289
|
-
enqueue
|
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,
|
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(
|
341
|
-
new_scene = Scenes.generate(
|
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.
|
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.
|
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?
|
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
|
37
|
+
# it is the view name with the suffix `.yaml` or `.yml`.
|
31
38
|
#
|
32
|
-
def self.
|
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(
|
56
|
-
|
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 =
|
7
|
+
@email = details[:contact]
|
7
8
|
end
|
8
9
|
|
9
|
-
|
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
|
-
"* #{
|
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
|