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.
@@ -0,0 +1,5 @@
1
+ module Metro
2
+ class UnknownSender
3
+
4
+ end
5
+ end
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
 
@@ -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
@@ -14,6 +14,8 @@ module Metro
14
14
  def after_initialize
15
15
  @text = ""
16
16
  @x_factor = @y_factor = 1.0
17
+ @z_order = 0
18
+ @color = Gosu::Color.new "rgba(255,255,255,1.0)"
17
19
  end
18
20
 
19
21
  def font
@@ -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
- attr_accessor :name, :method
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Metro
2
- class SceneActor
2
+ class ModelFactory
3
3
 
4
4
  attr_reader :name, :options
5
5
 
data/lib/metro/scene.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  require_relative 'scene_view/scene_view'
2
- require_relative 'scene_actor'
3
- require_relative 'event_relay'
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
- # Define a scene actor with the given name and options.
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
- def self.draw(actor_name,options = {})
97
- scene_actor = SceneActor.new actor_name, options
98
-
99
- define_method actor_name do
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
- # Define several standard scene actors.
99
+ # Post a custom notification event. This will trigger any objects that are listening
100
+ # for custom events.
112
101
  #
113
- def self.draws(*actor_names)
114
- actor_names = actor_names.flatten.compact
102
+ def notification(event)
115
103
 
116
- actor_names.each do |actor_name|
117
- draw actor_name
118
- end
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
- scene_actors
113
+ event_relays.each do |relay|
114
+ relay.fire_events_for_notification(event,sender)
115
+ end
121
116
  end
122
117
 
123
118
  #
124
- # @return a list of all the SceneActors that have been defined for this Scene.
119
+ # A scene has events which it will register when the window is established.
125
120
  #
126
- def self.scene_actors
127
- @scene_actors ||= []
128
- end
121
+ include HasEvents
129
122
 
130
123
  #
131
- # Setups up the Actors for the Scene based on the SceneActors that have been
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.scene_actors.each do |scene_actor|
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
- @event_relays = []
164
+ event_relays.clear
167
165
 
168
- @scene_events = EventRelay.new(self,window)
169
- events(@scene_events)
166
+ register_events!
167
+ register_actors!
168
+ register_animations!
170
169
 
171
- @event_relays << @scene_events
170
+ show
171
+ end
172
172
 
173
- @updaters = []
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
- @drawers = []
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
- self.class.scene_actors.each do |scene_actor|
178
- actor = send(scene_actor.name)
179
- actor.window = window
180
- @drawers << actor
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
- show
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[/^(.+)Scene$/,1]
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
- @updaters << updater
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
- @updaters.each { |updater| updater.update }
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
- @drawers.each { |drawer| drawer.draw }
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.scene_actors.find_all {|actor| actor.load_from_previous_scene? }.each do |scene_actor|
315
- new_actor = new_scene.send(scene_actor.name)
316
- current_actor = send(scene_actor.name)
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
- attr_reader :event_relays
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
  #