metro 0.0.6 → 0.1.0
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/.rspec +2 -0
- data/Gemfile +7 -0
- data/Guardfile +4 -0
- data/README.md +8 -0
- data/lib/gosu_ext/color.rb +25 -1
- data/lib/metro.rb +30 -2
- data/lib/metro/animation/animation_factory.rb +14 -0
- data/lib/metro/animation/has_animations.rb +37 -0
- data/lib/metro/error.rb +21 -0
- data/lib/metro/events/event_factory.rb +15 -0
- data/lib/metro/{event_relay.rb → events/event_relay.rb} +83 -25
- data/lib/metro/events/has_events.rb +108 -0
- data/lib/metro/events/unknown_sender.rb +5 -0
- data/lib/metro/game.rb +12 -0
- data/lib/metro/game/dsl.rb +21 -2
- data/lib/metro/missing_scene.rb +21 -0
- data/lib/metro/models/draws.rb +71 -0
- data/lib/metro/models/label.rb +2 -0
- data/lib/metro/models/menu.rb +32 -15
- data/lib/metro/models/model.rb +14 -0
- data/lib/metro/{scene_actor.rb → models/model_factory.rb} +1 -1
- data/lib/metro/scene.rb +124 -70
- data/lib/metro/scenes.rb +8 -5
- data/lib/metro/template_message.rb +31 -0
- data/lib/metro/version.rb +30 -1
- data/lib/templates/message.erb +24 -0
- data/metro.gemspec +38 -6
- data/spec/gosu_ext/color_spec.rb +80 -0
- data/spec/spec_helper.rb +18 -0
- metadata +69 -8
data/lib/metro/game.rb
CHANGED
@@ -42,6 +42,18 @@ module Metro
|
|
42
42
|
config.name
|
43
43
|
end
|
44
44
|
|
45
|
+
def authors
|
46
|
+
config.authors
|
47
|
+
end
|
48
|
+
|
49
|
+
def website
|
50
|
+
config.website
|
51
|
+
end
|
52
|
+
|
53
|
+
def contact
|
54
|
+
config.contact
|
55
|
+
end
|
56
|
+
|
45
57
|
# TODO: ZOrder related constants that belong to Starry Knight
|
46
58
|
Background, Stars, Players, UI = *0..3
|
47
59
|
|
data/lib/metro/game/dsl.rb
CHANGED
@@ -27,15 +27,34 @@ module Metro
|
|
27
27
|
def fullscreen(set_fullscreen = nil)
|
28
28
|
set_fullscreen.nil? ? @fullscreen : @fullscreen = set_fullscreen
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def debug(set_debug = nil)
|
32
32
|
set_debug.nil? ? @debug : @debug = set_debug
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def name(set_name = nil)
|
36
36
|
set_name.nil? ? @name : @name = set_name
|
37
37
|
end
|
38
38
|
|
39
|
+
def author(name)
|
40
|
+
authors.push name
|
41
|
+
end
|
42
|
+
|
43
|
+
def authors
|
44
|
+
@authors ||= []
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :artist, :author
|
48
|
+
alias_method :designer, :author
|
49
|
+
|
50
|
+
def website(game_website = nil)
|
51
|
+
game_website ? @website = game_website : @website
|
52
|
+
end
|
53
|
+
|
54
|
+
def contact(game_contact = nil)
|
55
|
+
game_contact ? @contact = game_contact : @contact
|
56
|
+
end
|
57
|
+
|
39
58
|
end
|
40
59
|
end
|
41
60
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Metro
|
2
|
+
class MissingScene < Scene
|
3
|
+
scene_name :missing_scene
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :missing_scene
|
7
|
+
end
|
8
|
+
|
9
|
+
draw :title, text: "Missing Scene!",
|
10
|
+
x: 20, y: 20, z_order: 1,
|
11
|
+
x_factor: 3, y_factor: 3,
|
12
|
+
color: 0xffffffff,
|
13
|
+
model: "metro::models::label"
|
14
|
+
|
15
|
+
draw :message, text: 'The scene `#{self.class.missing_scene}` was requested, but is missing!',
|
16
|
+
x: 20, y: 100, z_order: 1,
|
17
|
+
color: 0xffffffff,
|
18
|
+
model: "metro::models::label"
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative 'model_factory'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module Draws
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
#
|
13
|
+
# Define an actor with the given name and options.
|
14
|
+
#
|
15
|
+
# As a convience the draw method will define `getter` and `setter`
|
16
|
+
# methods for the specified actor.
|
17
|
+
#
|
18
|
+
# @example Defining a title label within a scene
|
19
|
+
#
|
20
|
+
# class ExampleScene
|
21
|
+
# draw :title, 'text' => 'Title Screen',
|
22
|
+
# 'x' => 20, 'y' => 20, 'z-order' => 0,
|
23
|
+
# 'x-factor' => 3, 'y-factor' => 3,
|
24
|
+
# 'color' => 0xffffffff,
|
25
|
+
# 'model' => 'metro::models::label'
|
26
|
+
#
|
27
|
+
# def show
|
28
|
+
# puts "Where is my title? #{title.x},#{title.y}"
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
def draw(actor_name,options = {})
|
33
|
+
scene_actor = ModelFactory.new actor_name, options
|
34
|
+
|
35
|
+
define_method actor_name do
|
36
|
+
instance_variable_get("@#{actor_name}")
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method "#{actor_name}=" do |value|
|
40
|
+
instance_variable_set("@#{actor_name}",value)
|
41
|
+
end
|
42
|
+
|
43
|
+
drawings.push scene_actor
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Define several actors to be drawn.
|
48
|
+
#
|
49
|
+
def draws(*actor_names)
|
50
|
+
actor_names = actor_names.flatten.compact
|
51
|
+
|
52
|
+
actor_names.each do |actor_name|
|
53
|
+
draw actor_name
|
54
|
+
end
|
55
|
+
|
56
|
+
drawings
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# All of the model factories that have been defined.
|
61
|
+
#
|
62
|
+
def drawings
|
63
|
+
@drawings ||= []
|
64
|
+
end
|
65
|
+
|
66
|
+
alias_method :actors, :drawings
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/metro/models/label.rb
CHANGED
data/lib/metro/models/menu.rb
CHANGED
@@ -6,29 +6,34 @@ module Metro
|
|
6
6
|
# target as it needs to maintain the state of the menu. When an option is selected
|
7
7
|
# an event is fired based on the name of the option.
|
8
8
|
#
|
9
|
-
# @note Only one 'menu' can be defined for a given scene
|
9
|
+
# @note Only one 'menu' can be defined for a given scene
|
10
10
|
#
|
11
11
|
class Menu < Model
|
12
|
+
|
13
|
+
event :on_up, Gosu::KbLeft, Gosu::GpLeft, Gosu::KbUp, Gosu::GpUp do
|
14
|
+
previous_option
|
15
|
+
end
|
16
|
+
|
17
|
+
event :on_up, Gosu::KbRight, Gosu::GpRight, Gosu::KbDown, Gosu::GpDown do
|
18
|
+
next_option
|
19
|
+
end
|
20
|
+
|
21
|
+
event :on_up, Gosu::KbEnter, Gosu::KbReturn, Gosu::GpButton0 do
|
22
|
+
selection
|
23
|
+
end
|
24
|
+
|
12
25
|
attr_reader :selected_index, :menu_options
|
13
26
|
|
27
|
+
attr_accessor :padding
|
28
|
+
|
14
29
|
def after_initialize
|
15
30
|
@selected_index = 0
|
31
|
+
@padding = 40
|
16
32
|
end
|
17
33
|
|
18
34
|
def window=(value)
|
19
35
|
@window = value
|
20
36
|
@menu_options = options.map {|option| Option.new option }
|
21
|
-
events
|
22
|
-
end
|
23
|
-
|
24
|
-
def events
|
25
|
-
relay = EventRelay.new(self,window)
|
26
|
-
|
27
|
-
relay.on_up Gosu::KbLeft, Gosu::GpLeft, Gosu::KbUp, Gosu::GpUp, do: :previous_option
|
28
|
-
relay.on_up Gosu::KbRight, Gosu::GpRight, Gosu::KbDown, Gosu::GpDown, do: :next_option
|
29
|
-
relay.on_up Gosu::KbEnter, Gosu::KbReturn, Gosu::GpButton0, do: :selection
|
30
|
-
|
31
|
-
scene.add_event_relay relay
|
32
37
|
end
|
33
38
|
|
34
39
|
def selection
|
@@ -78,11 +83,25 @@ module Metro
|
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
86
|
+
#
|
87
|
+
# The Option represents a choice within the menu.
|
88
|
+
#
|
81
89
|
class Option
|
82
90
|
|
91
|
+
#
|
92
|
+
# The raw data that was used to create the option.
|
93
|
+
#
|
83
94
|
attr_reader :data
|
84
95
|
|
85
|
-
|
96
|
+
#
|
97
|
+
# The human readable name of the option.
|
98
|
+
#
|
99
|
+
attr_accessor :name
|
100
|
+
|
101
|
+
#
|
102
|
+
# The method to execute within the scene when the option is selected.
|
103
|
+
#
|
104
|
+
attr_accessor :method
|
86
105
|
|
87
106
|
def initialize(data)
|
88
107
|
@data = data
|
@@ -94,9 +113,7 @@ module Metro
|
|
94
113
|
@name = data
|
95
114
|
@method = data.to_s.downcase.gsub(/\s/,'_').gsub(/^[^a-zA-Z]*/,'').gsub(/[^a-zA-Z0-9\s_]/,'')
|
96
115
|
end
|
97
|
-
|
98
116
|
end
|
99
|
-
|
100
117
|
end
|
101
118
|
|
102
119
|
end
|
data/lib/metro/models/model.rb
CHANGED
@@ -40,6 +40,20 @@ module Metro
|
|
40
40
|
#
|
41
41
|
def after_initialize ; end
|
42
42
|
|
43
|
+
#
|
44
|
+
# Generate a custom notification event with the given name.
|
45
|
+
#
|
46
|
+
# @param [Symbol] event the name of the notification to generate.
|
47
|
+
#
|
48
|
+
def notification(event)
|
49
|
+
scene.notification(event.to_sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Allows for the definition of events within the scene.
|
54
|
+
#
|
55
|
+
include HasEvents
|
56
|
+
|
43
57
|
#
|
44
58
|
# Returns the color of the model. In most cases where color is a prominent
|
45
59
|
# attribute (e.g. label) this will be the color. In the cases where color
|
data/lib/metro/scene.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require_relative 'scene_view/scene_view'
|
2
|
-
|
3
|
-
require_relative '
|
2
|
+
|
3
|
+
require_relative 'events/has_events'
|
4
|
+
require_relative 'events/event_relay'
|
5
|
+
require_relative 'events/unknown_sender'
|
6
|
+
|
7
|
+
require_relative 'models/draws'
|
8
|
+
|
9
|
+
require_relative 'animation/has_animations'
|
4
10
|
require_relative 'animation/animation'
|
5
11
|
|
6
12
|
module Metro
|
@@ -30,19 +36,6 @@ module Metro
|
|
30
36
|
#
|
31
37
|
def after_initialize ; end
|
32
38
|
|
33
|
-
#
|
34
|
-
# The events method is where a scene has access to configure the events that it
|
35
|
-
# would like to listen for during the scene.
|
36
|
-
#
|
37
|
-
# @note This method should be implemented in the Scene subclass.
|
38
|
-
#
|
39
|
-
# @param [EventRelay] e is the EventRelay that you can register for button up,
|
40
|
-
# button down, or button held events.
|
41
|
-
#
|
42
|
-
# @see EventRelay
|
43
|
-
#
|
44
|
-
def events(e) ; end
|
45
|
-
|
46
39
|
#
|
47
40
|
# This method is called right after the scene has been adopted by the window
|
48
41
|
#
|
@@ -89,53 +82,58 @@ module Metro
|
|
89
82
|
#
|
90
83
|
def prepare_transition_from(old_scene) ; end
|
91
84
|
|
85
|
+
include Draws
|
92
86
|
|
93
87
|
#
|
94
|
-
#
|
88
|
+
# When an actor is defined, through the class method `draw` a getter and setter method
|
89
|
+
# is defined. However, it is a better interface internally not to rely heavily on send
|
90
|
+
# and have this small amount of obfuscation in the event that this needs to change.
|
95
91
|
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
instance_variable_get("@#{actor_name}")
|
101
|
-
end
|
102
|
-
|
103
|
-
define_method "#{actor_name}=" do |value|
|
104
|
-
instance_variable_set("@#{actor_name}",value)
|
105
|
-
end
|
106
|
-
|
107
|
-
scene_actors.push scene_actor
|
92
|
+
# @return the actor with the given name.
|
93
|
+
#
|
94
|
+
def actor(name)
|
95
|
+
send(name)
|
108
96
|
end
|
109
97
|
|
110
98
|
#
|
111
|
-
#
|
99
|
+
# Post a custom notification event. This will trigger any objects that are listening
|
100
|
+
# for custom events.
|
112
101
|
#
|
113
|
-
def
|
114
|
-
actor_names = actor_names.flatten.compact
|
102
|
+
def notification(event)
|
115
103
|
|
116
|
-
|
117
|
-
|
118
|
-
|
104
|
+
# __sender__ is made available through the sender gem, this is solely to make the
|
105
|
+
# the api call to generate a notification simply `#notification`. Freeing the caller
|
106
|
+
# from having to include themself in the execution.
|
107
|
+
#
|
108
|
+
# @note if the sender functionality proves troublesome across platforms this can
|
109
|
+
# be dropped and simply require the sender to be included.
|
110
|
+
#
|
111
|
+
sender = __sender__ rescue UnknownSender
|
119
112
|
|
120
|
-
|
113
|
+
event_relays.each do |relay|
|
114
|
+
relay.fire_events_for_notification(event,sender)
|
115
|
+
end
|
121
116
|
end
|
122
117
|
|
123
118
|
#
|
124
|
-
#
|
119
|
+
# A scene has events which it will register when the window is established.
|
125
120
|
#
|
126
|
-
|
127
|
-
@scene_actors ||= []
|
128
|
-
end
|
121
|
+
include HasEvents
|
129
122
|
|
130
123
|
#
|
131
|
-
#
|
124
|
+
# A scene defines animations which it will execute when the scene starts
|
125
|
+
#
|
126
|
+
include HasAnimations
|
127
|
+
|
128
|
+
#
|
129
|
+
# Setups up the Actors for the Scene based on the ModelFactories that have been
|
132
130
|
# defined.
|
133
131
|
#
|
134
132
|
# @note this method should not be overriden, otherwise the actors will perish!
|
135
133
|
# @see #after_initialize
|
136
134
|
#
|
137
135
|
def initialize
|
138
|
-
self.class.
|
136
|
+
self.class.actors.each do |scene_actor|
|
139
137
|
actor_data = { 'name' => scene_actor.name }.merge (view[scene_actor.name] || {})
|
140
138
|
actor_instance = scene_actor.create(actor_data)
|
141
139
|
actor_instance.scene = self
|
@@ -163,24 +161,50 @@ module Metro
|
|
163
161
|
def window=(window)
|
164
162
|
@window = window
|
165
163
|
|
166
|
-
|
164
|
+
event_relays.clear
|
167
165
|
|
168
|
-
|
169
|
-
|
166
|
+
register_events!
|
167
|
+
register_actors!
|
168
|
+
register_animations!
|
170
169
|
|
171
|
-
|
170
|
+
show
|
171
|
+
end
|
172
172
|
|
173
|
-
|
173
|
+
#
|
174
|
+
# Register all the events that were defined for this scene.
|
175
|
+
#
|
176
|
+
def register_events!
|
177
|
+
register_events_for_target(self,self.class.events)
|
178
|
+
end
|
174
179
|
|
175
|
-
|
180
|
+
#
|
181
|
+
# Register all the actors that were defined for this scene.
|
182
|
+
#
|
183
|
+
def register_actors!
|
184
|
+
self.class.actors.each { |actor| register_actor(actor) }
|
185
|
+
end
|
176
186
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
187
|
+
#
|
188
|
+
# Register all the animations that were defined for this scene.
|
189
|
+
#
|
190
|
+
def register_animations!
|
191
|
+
self.class.animations.each do |animation|
|
192
|
+
animate animation.options, &animation.on_complete_block
|
181
193
|
end
|
194
|
+
end
|
182
195
|
|
183
|
-
|
196
|
+
#
|
197
|
+
# Registering an actor involves setting up the actor within
|
198
|
+
# the window, adding them to the list of things that need to be
|
199
|
+
# drawn and then registering any eventst that they might have.
|
200
|
+
#
|
201
|
+
def register_actor(actor_factory)
|
202
|
+
registering_actor = actor(actor_factory.name)
|
203
|
+
registering_actor.window = window
|
204
|
+
|
205
|
+
drawers.push(registering_actor)
|
206
|
+
|
207
|
+
register_events_for_target(registering_actor,registering_actor.class.events)
|
184
208
|
end
|
185
209
|
|
186
210
|
#
|
@@ -210,7 +234,7 @@ module Metro
|
|
210
234
|
#
|
211
235
|
def self.scene_name(scene_name=nil)
|
212
236
|
@scene_name ||= begin
|
213
|
-
root_name = to_s
|
237
|
+
root_name = to_s.gsub(/Scene$/,'')
|
214
238
|
root_name.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
215
239
|
root_name.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
216
240
|
root_name.downcase!
|
@@ -251,7 +275,7 @@ module Metro
|
|
251
275
|
# is used for animations.
|
252
276
|
#
|
253
277
|
def enqueue(updater)
|
254
|
-
|
278
|
+
updaters.push(updater)
|
255
279
|
end
|
256
280
|
|
257
281
|
#
|
@@ -259,28 +283,47 @@ module Metro
|
|
259
283
|
# to be an implicit animation.
|
260
284
|
#
|
261
285
|
def animate(options,&block)
|
286
|
+
options[:actor] = actor(options[:actor]) if options[:actor].is_a? Symbol
|
262
287
|
animation = Metro::ImplicitAnimation.new options.merge(context: self)
|
263
288
|
animation.on_complete(&block) if block
|
264
289
|
enqueue animation
|
265
290
|
end
|
266
291
|
|
292
|
+
|
293
|
+
#
|
294
|
+
# The objects that need to be executed on every update. These objects are traditionally
|
295
|
+
# animations or window events for held pressed buttons. But can be any objects that responds
|
296
|
+
# to the method #update.
|
297
|
+
#
|
298
|
+
def updaters
|
299
|
+
@updaters ||= []
|
300
|
+
end
|
301
|
+
|
267
302
|
#
|
268
303
|
# The `base_update` method is called by the Game Window. This is to allow for any
|
269
304
|
# special update needs to be handled before calling the traditional `update` method
|
270
305
|
# defined in the subclassed Scene.
|
271
306
|
#
|
272
307
|
def base_update
|
273
|
-
|
308
|
+
updaters.each { |updater| updater.update }
|
274
309
|
update
|
275
310
|
end
|
276
311
|
|
312
|
+
#
|
313
|
+
# The objects that need to be drawn with every draw cycle. These objects are traditionally
|
314
|
+
# the model objects, like the actors defined within the scene.
|
315
|
+
#
|
316
|
+
def drawers
|
317
|
+
@drawers ||= []
|
318
|
+
end
|
319
|
+
|
277
320
|
#
|
278
321
|
# The `base_draw` method is called by the Game Window. This is to allow for any
|
279
322
|
# special drawing needs to be handled before calling the traditional `draw` method
|
280
323
|
# defined in the subclassed Scene.
|
281
324
|
#
|
282
325
|
def base_draw
|
283
|
-
|
326
|
+
drawers.each { |drawer| drawer.draw }
|
284
327
|
draw
|
285
328
|
end
|
286
329
|
|
@@ -311,9 +354,9 @@ module Metro
|
|
311
354
|
def _prepare_transition(new_scene)
|
312
355
|
log.debug "Preparing to transition from scene #{self} to #{new_scene}"
|
313
356
|
|
314
|
-
new_scene.class.
|
315
|
-
new_actor = new_scene.
|
316
|
-
current_actor =
|
357
|
+
new_scene.class.actors.find_all {|actor_factory| actor_factory.load_from_previous_scene? }.each do |actor_factory|
|
358
|
+
new_actor = new_scene.actor(actor_factory.name)
|
359
|
+
current_actor = actor(actor_factory.name)
|
317
360
|
new_actor._load current_actor._save
|
318
361
|
end
|
319
362
|
|
@@ -321,6 +364,26 @@ module Metro
|
|
321
364
|
new_scene.prepare_transition_from(self)
|
322
365
|
end
|
323
366
|
|
367
|
+
#
|
368
|
+
# Helper method that is used internally to setup the events for the specified target.
|
369
|
+
#
|
370
|
+
# @param [Object] target the intended target for the specified events. This object
|
371
|
+
# will have the appropriate methods and functionality to respond appropriately
|
372
|
+
# to the action blocks defined in the methods.
|
373
|
+
#
|
374
|
+
# @param [Array<EventFactory>] events an array of EventFactory objects that need to now
|
375
|
+
# be mapped to the specified target.
|
376
|
+
#
|
377
|
+
def register_events_for_target(target,events)
|
378
|
+
target_relay = EventRelay.new(target,window)
|
379
|
+
|
380
|
+
events.each do |target_event|
|
381
|
+
target_relay.send target_event.event, *target_event.buttons, &target_event.block
|
382
|
+
end
|
383
|
+
|
384
|
+
event_relays.push(target_relay)
|
385
|
+
end
|
386
|
+
|
324
387
|
#
|
325
388
|
# The events object that is configured through the {#events} method, which stores
|
326
389
|
# all the gamepad and keyboard events defined. By default a scene has an event
|
@@ -329,17 +392,8 @@ module Metro
|
|
329
392
|
# @see Events
|
330
393
|
# @see #add_event_relay
|
331
394
|
#
|
332
|
-
|
333
|
-
|
334
|
-
#
|
335
|
-
# Add an additional event relay to the list of event relays. It is appended
|
336
|
-
# to the end of the list of relays.
|
337
|
-
#
|
338
|
-
# @param [EventRelay] event_relay an event relay instance that will now
|
339
|
-
# receive events generated from this scene.
|
340
|
-
#
|
341
|
-
def add_event_relay(event_relay)
|
342
|
-
@event_relays << event_relay
|
395
|
+
def event_relays
|
396
|
+
@event_relays ||= []
|
343
397
|
end
|
344
398
|
|
345
399
|
#
|