metro 0.0.6 → 0.1.0

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