metro 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +19 -0
- data/changelog.md +8 -0
- data/lib/assets/missing_animation.png +0 -0
- data/lib/commands/generate_model.rb +2 -2
- data/lib/commands/generate_scene.rb +12 -2
- data/lib/commands/generate_view.rb +1 -1
- data/lib/gosu_ext/color.rb +1 -1
- data/lib/gosu_ext/image.rb +5 -0
- data/lib/metro.rb +18 -5
- data/lib/metro/animation/animation.rb +31 -0
- data/lib/metro/asset_path.rb +9 -0
- data/lib/metro/events/event_dictionary.rb +53 -0
- data/lib/metro/events/event_factory.rb +5 -3
- data/lib/metro/events/has_events.rb +5 -6
- data/lib/metro/game.rb +1 -1
- data/lib/metro/models/dimensions.rb +21 -0
- data/lib/metro/models/model.rb +149 -52
- data/lib/metro/models/model_factory.rb +4 -5
- data/lib/metro/models/{generic.rb → models/generic.rb} +0 -0
- data/lib/metro/models/{grid_drawer.rb → models/grid_drawer.rb} +4 -9
- data/lib/metro/models/{image.rb → models/image.rb} +11 -14
- data/lib/metro/models/models/label.rb +44 -0
- data/lib/metro/models/{menu.rb → models/menu.rb} +23 -18
- data/lib/metro/models/{rectangle.rb → models/rectangle.rb} +6 -5
- data/lib/metro/models/point.rb +23 -0
- data/lib/metro/models/properties/angle.rb +43 -0
- data/lib/metro/models/properties/animation.rb +143 -0
- data/lib/metro/models/properties/color.rb +113 -0
- data/lib/metro/models/properties/dimensions.rb +66 -0
- data/lib/metro/models/properties/font.rb +155 -0
- data/lib/metro/models/properties/image.rb +101 -0
- data/lib/metro/models/properties/numeric.rb +29 -0
- data/lib/metro/models/properties/position.rb +84 -0
- data/lib/metro/models/properties/property.rb +111 -0
- data/lib/metro/models/properties/scale.rb +89 -0
- data/lib/metro/models/properties/text.rb +66 -0
- data/lib/metro/models/properties/velocity.rb +80 -0
- data/lib/metro/models/scale.rb +21 -0
- data/lib/metro/scene.rb +19 -1
- data/lib/metro/scenes.rb +91 -31
- data/lib/metro/transitions/scene_transitions.rb +8 -0
- data/lib/metro/version.rb +1 -1
- data/lib/metro/views/view.rb +9 -1
- data/lib/templates/game/metro.tt +1 -1
- data/lib/templates/game/models/game_model.rb +3 -0
- data/lib/templates/game/scenes/brand_scene.rb +1 -1
- data/lib/templates/game/scenes/brand_to_title_scene.rb +1 -1
- data/lib/templates/game/scenes/game_scene.rb +19 -0
- data/lib/templates/game/scenes/title_scene.rb +1 -1
- data/lib/templates/game/views/brand_to_title.yaml +2 -2
- data/lib/templates/game/views/title.yaml +3 -3
- data/lib/templates/{model.rb.erb → model.rb.tt} +1 -1
- data/lib/templates/{scene.rb.erb → scene.rb.tt} +1 -1
- data/lib/templates/view.yaml.tt +6 -0
- data/spec/metro/models/models/label_spec.rb +110 -0
- data/spec/metro/models/properties/color_spec.rb +85 -0
- data/spec/metro/models/properties/font_spec.rb +129 -0
- data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
- data/spec/metro/models/properties/position_property_spec.rb +90 -0
- data/spec/metro/scenes_spec.rb +77 -0
- metadata +50 -16
- data/lib/metro/models/label.rb +0 -63
- data/lib/templates/view.yaml.erb +0 -32
@@ -0,0 +1,89 @@
|
|
1
|
+
module Metro
|
2
|
+
class Model
|
3
|
+
|
4
|
+
#
|
5
|
+
# A scale property maintains an x and y scaling factor. This scale is not applied to any
|
6
|
+
#
|
7
|
+
# A font property also defines a `font_size` property and a `font_name` property which allows a
|
8
|
+
# more direct interface. Changing these values will update the font the next time that it is drawn.
|
9
|
+
#
|
10
|
+
# A font is stored in the properties as a hash representation and is converted into
|
11
|
+
# a Gosu::Font when it is retrieved within the system. When retrieving a font the Font
|
12
|
+
# Property will attempt to use a font that already exists that meets that criteria.
|
13
|
+
#
|
14
|
+
# The fonts are cached within the font property to help performance by reducing the unncessary
|
15
|
+
# creation of similar fonts.
|
16
|
+
#
|
17
|
+
# @example Defining a font property
|
18
|
+
#
|
19
|
+
# class Scoreboard < Metro::Model
|
20
|
+
# property :font
|
21
|
+
#
|
22
|
+
# def draw
|
23
|
+
# font.draw text, x, y, z_order, x_factor, y_factor, color
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @example Defining a font property providing a default
|
29
|
+
#
|
30
|
+
# class Hero < Metro::Model
|
31
|
+
# property :font, default: { name: 'Comic Sans', size: 80 }
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @example Using the `font_size` and `font_name` properties
|
35
|
+
#
|
36
|
+
# class Hero < Metro::Model
|
37
|
+
# property :color, default: "rgba(255,0,0,1.0)"
|
38
|
+
#
|
39
|
+
# def dignified
|
40
|
+
# self.font_size = 45
|
41
|
+
# self.font_name = 'Helvetica'
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example Using a font property with a different property name
|
46
|
+
#
|
47
|
+
# class Hero < Metro::Model
|
48
|
+
# property :alt_font, type: :font, default: "rgba(255,0,255,1.0)"
|
49
|
+
#
|
50
|
+
# def draw
|
51
|
+
# puts "Font: #{alt_font_name}:#{alt_font_size}"
|
52
|
+
# alt_font.draw text, x, y, z_order, x_factor, y_factor, color
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
class ScaleProperty < Property
|
57
|
+
|
58
|
+
define_property :x_factor
|
59
|
+
|
60
|
+
define_property :y_factor
|
61
|
+
|
62
|
+
get do |value|
|
63
|
+
default_scale
|
64
|
+
end
|
65
|
+
|
66
|
+
get String do |value|
|
67
|
+
Scale.parse(value)
|
68
|
+
end
|
69
|
+
|
70
|
+
set do |value|
|
71
|
+
default_scale.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
set String do |value|
|
75
|
+
value
|
76
|
+
end
|
77
|
+
|
78
|
+
set Scale do |value|
|
79
|
+
value.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_scale
|
83
|
+
(options[:default] and options[:default].is_a? Scale) ? options[:default] : Scale.one
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Metro
|
2
|
+
class Model
|
3
|
+
|
4
|
+
#
|
5
|
+
# A text property maintains a string of text
|
6
|
+
#
|
7
|
+
# Text is stored as text in properties. When retrieving the text, the contents of the text will
|
8
|
+
# be evaluated within the instance of the model's scene. Which means that text may contain
|
9
|
+
# escaped variables referencing anything in the scene or the game.
|
10
|
+
#
|
11
|
+
# @example Defining a text property
|
12
|
+
#
|
13
|
+
# class Scoreboard < Metro::Model
|
14
|
+
# property :text
|
15
|
+
#
|
16
|
+
# def draw
|
17
|
+
# font.draw text, x, y, z_order, x_factor, y_factor, color
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @example Defining with a default and text that will be instance evaluated.
|
23
|
+
#
|
24
|
+
# class ScoreBoard < Metro::Model
|
25
|
+
# property :font, default: 'Score is #{player.score}'
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @example Using a text property with a different property name
|
29
|
+
#
|
30
|
+
# class Hero < Metro::Model
|
31
|
+
# property :description, type: :text
|
32
|
+
#
|
33
|
+
# def draw
|
34
|
+
# description_font.draw text, x, y, z_order, x_factor, y_factor, color
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
class TextProperty < Property
|
39
|
+
|
40
|
+
# When no text is found for the field use the default text.
|
41
|
+
get do |value|
|
42
|
+
evalute_within_scene default_text
|
43
|
+
end
|
44
|
+
|
45
|
+
# When getting the text, evaluate the text within the scene.
|
46
|
+
get String do |value|
|
47
|
+
evalute_within_scene(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
# When saving, simply save whatever is given as text.
|
51
|
+
set do |value|
|
52
|
+
value.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def evalute_within_scene(text)
|
56
|
+
model.scene.instance_eval( "\"#{text}\"" )
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_text
|
60
|
+
options[:default] || 'Text for #{model} not specified!'
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Metro
|
2
|
+
class Model
|
3
|
+
|
4
|
+
class VectorProperty < Property
|
5
|
+
|
6
|
+
def get(value)
|
7
|
+
value ? value : Vector.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(value)
|
11
|
+
Vector.new value
|
12
|
+
end
|
13
|
+
|
14
|
+
class Vector
|
15
|
+
|
16
|
+
def initialize(angle,velocity)
|
17
|
+
@angle = angle
|
18
|
+
@velocity = velocity
|
19
|
+
end
|
20
|
+
|
21
|
+
def decay!
|
22
|
+
@velocity.decay!
|
23
|
+
end
|
24
|
+
|
25
|
+
def accelerate(amount,angle)
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def apply_x(x_position)
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply_y(y_position)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class VelocityProperty < Property
|
43
|
+
|
44
|
+
def get(value)
|
45
|
+
value ? value : Velocity.new(0.0,0.95)
|
46
|
+
end
|
47
|
+
|
48
|
+
def set(value)
|
49
|
+
Velocity.new value
|
50
|
+
end
|
51
|
+
|
52
|
+
class Velocity
|
53
|
+
|
54
|
+
def initialize(value,decay = default_decay)
|
55
|
+
@value = value.to_f
|
56
|
+
@decay = decay || default_decay
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_decay
|
60
|
+
0.95
|
61
|
+
end
|
62
|
+
|
63
|
+
def decay
|
64
|
+
@value *= @decay
|
65
|
+
end
|
66
|
+
|
67
|
+
def accelerate(amount)
|
68
|
+
@value += amount
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_f
|
72
|
+
@value
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Metro
|
2
|
+
class Scale < Struct.new(:x_factor,:y_factor)
|
3
|
+
|
4
|
+
def self.one
|
5
|
+
new 1.0, 1.0
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.to(x,y)
|
9
|
+
new x.to_f, y.to_f
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parse(string)
|
13
|
+
to *string.split(",",2).map(&:to_f)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{x_factor},#{y_factor}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/metro/scene.rb
CHANGED
@@ -251,6 +251,7 @@ module Metro
|
|
251
251
|
registering_actor.window = window
|
252
252
|
|
253
253
|
drawers.push(registering_actor)
|
254
|
+
updaters.push(registering_actor)
|
254
255
|
|
255
256
|
register_events_for_target(registering_actor,registering_actor.class.events)
|
256
257
|
end
|
@@ -281,12 +282,29 @@ module Metro
|
|
281
282
|
#
|
282
283
|
def self.scene_name(scene_name=nil)
|
283
284
|
@scene_name ||= begin
|
284
|
-
to_s
|
285
|
+
if to_s == "Metro::Scene"
|
286
|
+
to_s.underscore
|
287
|
+
else
|
288
|
+
to_s.gsub(/_?Scene$/i,'').underscore
|
289
|
+
end
|
285
290
|
end
|
286
291
|
|
287
292
|
scene_name ? @scene_name = scene_name.to_s : @scene_name
|
288
293
|
end
|
289
294
|
|
295
|
+
#
|
296
|
+
# @return a common name that can be used through the system as a common identifier.
|
297
|
+
#
|
298
|
+
def self.metro_name
|
299
|
+
scene_name
|
300
|
+
end
|
301
|
+
|
302
|
+
#
|
303
|
+
# @return an array of all the scene names of all the ancestor scenes
|
304
|
+
#
|
305
|
+
def self.hierarchy
|
306
|
+
ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
|
307
|
+
end
|
290
308
|
|
291
309
|
#
|
292
310
|
# Allows you to set or retrieve the scene name for the Scene.
|
data/lib/metro/scenes.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative 'transitions/scene_transitions'
|
2
|
-
|
3
1
|
module Metro
|
4
2
|
|
5
3
|
#
|
@@ -11,7 +9,6 @@ module Metro
|
|
11
9
|
#
|
12
10
|
# Scenes.find("intro") # => IntroScene
|
13
11
|
# Scenes.find(:intro) # => IntroScene
|
14
|
-
# Scenes.find(IntroScene) # => IntroScene
|
15
12
|
#
|
16
13
|
# @example Creating a scene instance based on the scene name
|
17
14
|
#
|
@@ -21,7 +18,11 @@ module Metro
|
|
21
18
|
#
|
22
19
|
# Scenes.generate("intro") # => [SCENE: title]
|
23
20
|
# Scenes.generate(:intro) # => [SCENE: title]
|
24
|
-
#
|
21
|
+
#
|
22
|
+
# @example Finding a scene that does not exist
|
23
|
+
#
|
24
|
+
# scene = Scenes.find(:unknown)
|
25
|
+
# scene.missing_scene # => :unknown
|
25
26
|
#
|
26
27
|
module Scenes
|
27
28
|
extend self
|
@@ -33,18 +34,7 @@ module Metro
|
|
33
34
|
# @return the Scene class that is found matching the specified scene name.
|
34
35
|
#
|
35
36
|
def find(scene_name)
|
36
|
-
|
37
|
-
|
38
|
-
if found_scene
|
39
|
-
found_scene.constantize
|
40
|
-
else
|
41
|
-
create_missing_scene(scene_name)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def create_missing_scene(scene_name)
|
46
|
-
MissingScene.missing_scene = scene_name
|
47
|
-
MissingScene
|
37
|
+
scene_class( scenes_hash[scene_name] )
|
48
38
|
end
|
49
39
|
|
50
40
|
#
|
@@ -55,16 +45,18 @@ module Metro
|
|
55
45
|
# @return an instance of Scene that is found matching the specified scene name
|
56
46
|
#
|
57
47
|
def generate(scene_or_scene_name,options = {})
|
58
|
-
new_scene =
|
59
|
-
|
60
|
-
post_filters.inject(new_scene) {|scene,post| post.filter(scene,options) }
|
48
|
+
new_scene = generate_scene_from(scene_or_scene_name)
|
49
|
+
apply_post_filters(new_scene,options)
|
61
50
|
end
|
62
51
|
|
63
52
|
#
|
64
53
|
# If we have been given a scene, then we simply want to use it otherwise
|
65
54
|
# we need to find and generate our scene from the scene name.
|
66
|
-
#
|
67
|
-
|
55
|
+
#
|
56
|
+
# @param [String,Sybmol,Class] scene_or_scene_name the name of the scene or an instance
|
57
|
+
# of Scene.
|
58
|
+
#
|
59
|
+
def generate_scene_from(scene_or_scene_name)
|
68
60
|
if scene_or_scene_name.is_a? Scene
|
69
61
|
scene_or_scene_name
|
70
62
|
else
|
@@ -75,27 +67,95 @@ module Metro
|
|
75
67
|
#
|
76
68
|
# Post filters are applied to the scene after it has been found. These are
|
77
69
|
# all objects that can respond to the #filter method.
|
78
|
-
#
|
70
|
+
#
|
79
71
|
def post_filters
|
80
|
-
|
72
|
+
@post_filters ||= []
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Register a filter that will be executed after a scene is found and generated. This
|
77
|
+
# allows for the scene to be modified or changed based on the provided options.
|
78
|
+
#
|
79
|
+
# A filter is any object that responds to #filter and accepts two parameters: the
|
80
|
+
# scene and a hash of options.
|
81
|
+
#
|
82
|
+
# @param [#filter] post_filter a filter is an object that can act as a filter.
|
83
|
+
#
|
84
|
+
def register_post_filter(post_filter)
|
85
|
+
post_filters.push(post_filter)
|
81
86
|
end
|
82
87
|
|
83
88
|
private
|
84
89
|
|
90
|
+
#
|
91
|
+
# Apply all the post filtering to the specified scene with the given options
|
92
|
+
#
|
93
|
+
# @return a Scene object that has been filtered.
|
94
|
+
#
|
95
|
+
def apply_post_filters(new_scene,options)
|
96
|
+
post_filters.inject(new_scene) {|scene,post| post.filter(scene,options) }
|
97
|
+
end
|
98
|
+
|
85
99
|
#
|
86
100
|
# @return a Hash that allows for accessing symbol names of the scenes
|
87
101
|
# as well as the class name constants to allow for the scenes to be found.
|
88
102
|
#
|
89
103
|
def scenes_hash
|
90
|
-
@scenes_hash ||= Scene.scenes
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
104
|
+
@scenes_hash ||= build_map_of_scenes(Scene.scenes)
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# Generate a map from the scene or scenes to include all the sub-classes of
|
109
|
+
# these scenes.
|
110
|
+
#
|
111
|
+
# @param [Scene,Array<Scene>] scenes a scene or scene subclass or an array of
|
112
|
+
# scene subclasses.
|
113
|
+
#
|
114
|
+
# @see #scenes_hash
|
115
|
+
#
|
116
|
+
def build_map_of_scenes(scenes)
|
117
|
+
hash = hash_with_missing_scene_default
|
118
|
+
all_scenes_for(scenes).inject(hash) do |hash,scene|
|
119
|
+
hash[scene.scene_name] = scene.to_s
|
120
|
+
hash
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Create a hash that will return a setup missing scene by default.
|
126
|
+
#
|
127
|
+
def hash_with_missing_scene_default
|
128
|
+
ActiveSupport::HashWithIndifferentAccess.new do |hash,key|
|
129
|
+
missing_scene = scene_class(hash[:missing_scene])
|
130
|
+
missing_scene.missing_scene = key.to_sym
|
131
|
+
missing_scene
|
97
132
|
end
|
98
133
|
end
|
99
134
|
|
135
|
+
#
|
136
|
+
# Returns all subclassed scenes of the scene or scenes provided. This method is
|
137
|
+
# meant to be called recursively to generate the entire list of all the scenes.
|
138
|
+
#
|
139
|
+
# @param [Scene,Array<Scene>] scenes a scene or scene subclass or an array of
|
140
|
+
# scene subclasses.
|
141
|
+
#
|
142
|
+
def all_scenes_for(scenes)
|
143
|
+
Array(scenes).map do |scene_class_name|
|
144
|
+
scene = scene_class(scene_class_name)
|
145
|
+
[ scene ] + all_scenes_for(scene.scenes)
|
146
|
+
end.flatten.compact
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# @param [String,Symbol] class_name the name of the class that you want the class
|
151
|
+
#
|
152
|
+
# @return the class with the given class name
|
153
|
+
#
|
154
|
+
def scene_class(class_or_class_name)
|
155
|
+
class_or_class_name.class == Class ? class_or_class_name : class_or_class_name.constantize
|
156
|
+
end
|
157
|
+
|
100
158
|
end
|
101
|
-
end
|
159
|
+
end
|
160
|
+
|
161
|
+
require_relative 'transitions/scene_transitions'
|