metro 0.0.3 → 0.0.5

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,29 @@
1
+ module Metro
2
+ module Models
3
+
4
+ #
5
+ # Draws a string of text
6
+ #
7
+ # @example Using the Label in a view file
8
+ # model: "metro::models::label"
9
+ #
10
+ class Label < Model
11
+
12
+ attr_accessor :x, :y, :x_factor, :y_factor, :z_order
13
+
14
+ def initialize
15
+ @x_factor = @y_factor = 1.0
16
+ end
17
+
18
+ def font
19
+ @font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
20
+ end
21
+
22
+ def draw
23
+ label_text = scene.instance_eval( "\"#{text}\"" )
24
+ font.draw label_text, x, y, z_order, x_factor, y_factor, color
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,188 @@
1
+ module Metro
2
+
3
+ #
4
+ # The Model is a basic, generic representation of a game object
5
+ # that has a visual representation within the scene's window.
6
+ #
7
+ # Model is designed to be an abstract class, to be subclassed by
8
+ # other models.
9
+ #
10
+ # @see Models::Generic
11
+ #
12
+ class Model
13
+
14
+ #
15
+ # The window that this model that this window is currently being
16
+ # displayed.
17
+ #
18
+ # The current value of window is managed by the scene
19
+ # as this is set when the Scene is added to the window. All the
20
+ # models gain access to the window.
21
+ #
22
+ # @see Window
23
+ #
24
+ attr_accessor :window
25
+
26
+ #
27
+ # The scene that this model is currently being displayed.
28
+ #
29
+ # The current value of scene is managed by the scene as this
30
+ # is set when the scene is created.
31
+ #
32
+ # @see Scene
33
+ attr_accessor :scene
34
+
35
+ #
36
+ # This is an entry point for customization. As the model's {#initialize}
37
+ # method performs may perform some initialization that may be necessary.
38
+ #
39
+ # @note This method should be implemented in the Model subclass.
40
+ #
41
+ def after_initialize ; end
42
+
43
+ #
44
+ # Returns the color of the model. In most cases where color is a prominent
45
+ # attribute (e.g. label) this will be the color. In the cases where color
46
+ # is less promenint (e.g. image) this will likely be a color that can be
47
+ # used to influence the drawing of it.
48
+ #
49
+ # @see #alpha
50
+ #
51
+ attr_reader :color
52
+
53
+ #
54
+ # Sets the color of the model.
55
+ #
56
+ # @param [String,Fixnum,Gosu::Color] value the new color to set.
57
+ #
58
+ def color=(value)
59
+ @color = Gosu::Color.new(value)
60
+ end
61
+
62
+ #
63
+ # @return the alpha value of the model's color. This is an integer value
64
+ # between 0 and 255.
65
+ #
66
+ def alpha
67
+ color.alpha
68
+ end
69
+
70
+ #
71
+ # Sets the alpha of the model.
72
+ #
73
+ # @param [String,Fixnum] value the new value of the alpha level for the model.
74
+ # This value should be between 0 and 255.
75
+ #
76
+ def alpha=(value)
77
+ # TODO: coerce the value is between 0 and 255
78
+ color.alpha = value.to_i
79
+ end
80
+
81
+ #
82
+ # Create an instance of a model.
83
+ #
84
+ # @note Overridding initialize method should be avoided, using the {#aftter_initialize)
85
+ # method or done with care to ensure that functionality is preserved.
86
+ #
87
+ def initialize(options = {})
88
+ after_initialize
89
+ end
90
+
91
+ #
92
+ # Loads a hash of content into the model. This process will convert the hash
93
+ # of content into setter and getter methods with appropriate ruby style names.
94
+ #
95
+ # This is used internally when the model is created for the Scene. It is loaded
96
+ # with the contents of the view.
97
+ #
98
+ def _load(options = {})
99
+ options = {} unless options
100
+
101
+ options.each do |raw_key,value|
102
+
103
+ key = raw_key.dup
104
+ key.gsub!(/-/,'_')
105
+ key.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
106
+ key.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
107
+
108
+ unless respond_to? key
109
+ self.class.send :define_method, key do
110
+ instance_variable_get("@#{key}")
111
+ end
112
+ end
113
+
114
+ unless respond_to? "#{key}="
115
+ self.class.send :define_method, "#{key}=" do |value|
116
+ instance_variable_set("@#{key}",value)
117
+ end
118
+ end
119
+
120
+ _loaded_options.push key
121
+ send "#{key}=", value
122
+ end
123
+
124
+ end
125
+
126
+ def _loaded_options
127
+ @_loaded_options ||= []
128
+ end
129
+
130
+ #
131
+ # Generate a hash export of all the fields that were previously stored within
132
+ # the model.
133
+ #
134
+ # This is used internally within the scene to transfer the data from one model
135
+ # to another model.
136
+ #
137
+ def _save
138
+ data_export = @_loaded_options.map {|option| [ option, send(option) ] }.flatten
139
+ Hash[*data_export]
140
+ end
141
+
142
+ #
143
+ # Captures all classes that subclass Model.
144
+ #
145
+ # @see #self.scenes
146
+ #
147
+ def self.inherited(base)
148
+ models << base
149
+ end
150
+
151
+ #
152
+ # All subclasses of Model, this should be all the defined model within the game.
153
+ #
154
+ # @return an Array of Scene subclasses
155
+ #
156
+ def self.models
157
+ @models ||= []
158
+ end
159
+
160
+ #
161
+ # Convert the specified model name into the class of the model.
162
+ #
163
+ # @return the Model class given the specified model name.
164
+ def self.model(name)
165
+ @models_hash ||= begin
166
+
167
+ hash = Hash.new(Models::Generic)
168
+
169
+ models.each do |model|
170
+ common_name = model.to_s.gsub(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
171
+ common_name.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
172
+ common_name.downcase!
173
+
174
+ hash[common_name] = model
175
+ end
176
+ hash
177
+ end
178
+
179
+ @models_hash[name]
180
+ end
181
+
182
+ end
183
+ end
184
+
185
+ require_relative 'generic'
186
+ require_relative 'label'
187
+ require_relative 'select'
188
+ require_relative 'image'
@@ -0,0 +1,77 @@
1
+ module Metro
2
+ module Models
3
+
4
+ #
5
+ # Draws a a menu of options. It is called a Select as it is named after the HTML
6
+ # element select. A select model also inserts itself into the scene as an event
7
+ # target as it needs to maintain the state of the menu. When an option is selected
8
+ # an event is fired based on the name of the option.
9
+ #
10
+ # @note Only one 'select' can be defined for a given scene.
11
+ #
12
+ class Select < Model
13
+ attr_accessor :selected_index, :options
14
+
15
+ def initialize
16
+ @selected_index = 0
17
+ end
18
+
19
+ def window=(value)
20
+ @window = value
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
+ end
33
+
34
+ def selection
35
+ scene_method = options[selected_index].downcase.gsub(/\s/,'_')
36
+ scene.send scene_method
37
+ end
38
+
39
+ def previous_option
40
+ @selected_index = @selected_index - 1
41
+ @selected_index = options.length - 1 if @selected_index <= -1
42
+ end
43
+
44
+ def next_option
45
+ @selected_index = @selected_index + 1
46
+ @selected_index = 0 if @selected_index >= options.length
47
+ end
48
+
49
+ def font
50
+ @font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
51
+ end
52
+
53
+ attr_reader :highlight_color
54
+
55
+ def highlight_color=(value)
56
+ @highlight_color = Gosu::Color.new(value)
57
+ end
58
+
59
+ def alpha=(value)
60
+ color.alpha = value.floor
61
+ highlight_color.alpha = value.floor
62
+ end
63
+
64
+ def draw
65
+ options.each_with_index do |option,index|
66
+
67
+ draw_color = color
68
+ draw_color = highlight_color if index == selected_index
69
+
70
+ y_position = y + padding * index
71
+ font.draw option, x, y_position, Metro::Game::UI, 1.0, 1.0, draw_color
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
data/lib/metro/scene.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'scene_view/scene_view'
2
+ require_relative 'scene_actor'
2
3
  require_relative 'event_relay'
3
4
  require_relative 'animation/animation'
4
5
 
@@ -20,6 +21,15 @@ module Metro
20
21
  #
21
22
  class Scene
22
23
 
24
+ #
25
+ # As Scene does a lot of work for you with regarding to setting up content, it is
26
+ # best not to override #initialize and instead define an #after_initialize method
27
+ # within the subclasses of Scene.
28
+ #
29
+ # @note This method should be implemented in the Scene subclass.
30
+ #
31
+ def after_initialize ; end
32
+
23
33
  #
24
34
  # The events method is where a scene has access to configure the events that it
25
35
  # would like to listen for during the scene.
@@ -79,6 +89,62 @@ module Metro
79
89
  #
80
90
  def prepare_transition_from(old_scene) ; end
81
91
 
92
+
93
+ #
94
+ # Define a scene actor with the given name and options.
95
+ #
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
108
+ end
109
+
110
+ #
111
+ # Define several standard scene actors.
112
+ #
113
+ def self.draws(*actor_names)
114
+ actor_names = actor_names.flatten.compact
115
+
116
+ actor_names.each do |actor_name|
117
+ draw actor_name
118
+ end
119
+
120
+ scene_actors
121
+ end
122
+
123
+ #
124
+ # @return a list of all the SceneActors that have been defined for this Scene.
125
+ #
126
+ def self.scene_actors
127
+ @scene_actors ||= []
128
+ end
129
+
130
+ #
131
+ # Setups up the Actors for the Scene based on the SceneActors that have been
132
+ # defined.
133
+ #
134
+ # @note this method should not be overriden, otherwise the actors will perish!
135
+ # @see #after_initialize
136
+ #
137
+ def initialize
138
+ self.class.scene_actors.each do |scene_actor|
139
+ actor_data = { 'name' => scene_actor.name }.merge (view[scene_actor.name] || {})
140
+ actor_instance = scene_actor.create(actor_data)
141
+ actor_instance.scene = self
142
+ send "#{scene_actor.name}=", actor_instance
143
+ end
144
+
145
+ after_initialize
146
+ end
147
+
82
148
  #
83
149
  # The window is the main instance of the game. Using window can access a lot of
84
150
  # underlying Metro::Window, a subclass of Gosu::Window, that the Scene class is
@@ -104,6 +170,16 @@ module Metro
104
170
 
105
171
  @event_relays << @scene_events
106
172
 
173
+ @updaters = []
174
+
175
+ @drawers = []
176
+
177
+ self.class.scene_actors.each do |scene_actor|
178
+ actor = send(scene_actor.name)
179
+ actor.window = window
180
+ @drawers << actor
181
+ end
182
+
107
183
  show
108
184
  end
109
185
 
@@ -170,17 +246,35 @@ module Metro
170
246
  end
171
247
 
172
248
  #
173
- # The `base_draw` method is called by the Game Window. This is allow for any special
174
- # drawing needs to be handled before calling the traditional `draw` method defined
175
- # in the subclassed Scene.
249
+ # Enqueue will add an updater to the list of updaters that are run initially when
250
+ # update is called. An updater is any object that can respond to #update. This
251
+ # is used for animations.
252
+ #
253
+ def enqueue(updater)
254
+ @updaters << updater
255
+ end
256
+
257
+ #
258
+ # The `base_update` method is called by the Game Window. This is to allow for any
259
+ # special update needs to be handled before calling the traditional `update` method
260
+ # defined in the subclassed Scene.
261
+ #
262
+ def base_update
263
+ @updaters.each { |updater| updater.update }
264
+ update
265
+ end
266
+
267
+ #
268
+ # The `base_draw` method is called by the Game Window. This is to allow for any
269
+ # special drawing needs to be handled before calling the traditional `draw` method
270
+ # defined in the subclassed Scene.
176
271
  #
177
272
  def base_draw
273
+ @drawers.each { |drawer| drawer.draw }
178
274
  draw
179
275
  end
180
276
 
181
277
  # This provides the functionality for view handling.
182
- # @note the inclusion of view functionality redefines {#base_draw} so it must proceed
183
- # the declaration of that method.
184
278
  include SceneView
185
279
 
186
280
  #
@@ -196,7 +290,6 @@ module Metro
196
290
  window.scene = new_scene
197
291
  end
198
292
 
199
-
200
293
  #
201
294
  # Before a scene is transitioned away from to a new scene, this private method is
202
295
  # here to allow for any housekeeping or other work that needs to be done before
@@ -207,6 +300,13 @@ module Metro
207
300
  #
208
301
  def _prepare_transition(new_scene)
209
302
  log.debug "Preparing to transition from scene #{self} to #{new_scene}"
303
+
304
+ new_scene.class.scene_actors.find_all {|actor| actor.load_from_previous_scene? }.each do |scene_actor|
305
+ new_actor = new_scene.send(scene_actor.name)
306
+ current_actor = send(scene_actor.name)
307
+ new_actor._load current_actor._save
308
+ end
309
+
210
310
  prepare_transition_to(new_scene)
211
311
  new_scene.prepare_transition_from(self)
212
312
  end