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.
- data/lib/gosu_ext/color.rb +24 -0
- data/lib/metro.rb +6 -2
- data/lib/metro/animation/animation.rb +78 -49
- data/lib/metro/animation/easing.rb +22 -19
- data/lib/metro/animation/implicit_animation.rb +84 -25
- data/lib/metro/game.rb +5 -1
- data/lib/metro/game/dsl.rb +4 -0
- data/lib/metro/models/generic.rb +12 -0
- data/lib/metro/models/image.rb +29 -0
- data/lib/metro/models/label.rb +29 -0
- data/lib/metro/models/model.rb +188 -0
- data/lib/metro/models/select.rb +77 -0
- data/lib/metro/scene.rb +106 -6
- data/lib/metro/scene_actor.rb +26 -0
- data/lib/metro/scene_view/scene_view.rb +24 -27
- data/lib/metro/version.rb +1 -1
- data/lib/metro/window.rb +1 -1
- metadata +9 -9
- data/lib/metro/model.rb +0 -12
- data/lib/metro/scene_view/drawers/artists_block.rb +0 -17
- data/lib/metro/scene_view/drawers/composite_drawer.rb +0 -87
- data/lib/metro/scene_view/drawers/drawer.rb +0 -115
- data/lib/metro/scene_view/drawers/image.rb +0 -31
- data/lib/metro/scene_view/drawers/label.rb +0 -28
- data/lib/metro/scene_view/drawers/select.rb +0 -70
@@ -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
|
-
#
|
174
|
-
#
|
175
|
-
#
|
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
|