metro 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|