metro 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +15 -0
- data/changelog.md +7 -0
- data/lib/metro/missing_scene.rb +2 -2
- data/lib/metro/models/draws.rb +2 -2
- data/lib/metro/models/model.rb +14 -119
- data/lib/metro/models/properties/property.rb +2 -1
- data/lib/metro/models/properties/property_owner.rb +136 -0
- data/lib/metro/models/ui/image.rb +1 -1
- data/lib/metro/models/ui/label.rb +89 -5
- data/lib/metro/models/ui/rectangle.rb +21 -5
- data/lib/metro/transitions/edit_transition_scene.rb +1 -1
- data/lib/metro/transitions/fade_transition_scene.rb +1 -1
- data/lib/metro/version.rb +1 -1
- data/lib/templates/game/README.md.tt +17 -3
- data/lib/templates/game/views/brand.yaml +1 -1
- data/lib/templates/game/views/brand_to_title.yaml +1 -1
- data/lib/templates/game/views/first.yaml +1 -1
- data/lib/templates/game/views/title.yaml +2 -2
- data/lib/templates/scene.rb.tt +1 -1
- data/lib/templates/view.yaml.tt +1 -1
- data/spec/metro/models/properties/dimensions_spec.rb +1 -1
- data/spec/metro/models/ui/label_spec.rb +218 -0
- metadata +10 -9
- data/spec/metro/models/models/label_spec.rb +0 -110
data/README.md
CHANGED
@@ -59,9 +59,24 @@ This should generate a scene in the scenes directory. The scene file contains a
|
|
59
59
|
|
60
60
|
### Resources
|
61
61
|
|
62
|
+
#### Programming
|
63
|
+
|
64
|
+
* [YAML for Ruby](http://www.yaml.org/YAML_for_ruby.html) reference which can help you define views in the game.
|
65
|
+
* [JSONLint](http://jsonlint.com/) is a JSON Validator
|
66
|
+
|
62
67
|
#### Art
|
63
68
|
|
64
69
|
* [Lost Garden](http://www.lostgarden.com/2007/05/dancs-miraculously-flexible-game.html)
|
70
|
+
* [TimelieFX](http://www.rigzsoft.co.uk/) particle editor allows you to export animations.
|
71
|
+
* [Text to ASCII Art Generator](http://patorjk.com/software/taag)
|
72
|
+
* [Icons](http://css-tricks.com/flat-icons-icon-fonts/)
|
73
|
+
* [Subtle Patterns](http://subtlepatterns.com/) various backgrounds and textures.
|
74
|
+
|
75
|
+
#### Sound
|
76
|
+
|
77
|
+
* [as3sfxr](http://www.superflashbros.net/as3sfxr/) generates unique sounds.
|
78
|
+
* [Ableton](https://www.ableton.com/en/) music generation tool.
|
79
|
+
|
65
80
|
|
66
81
|
#### Books
|
67
82
|
|
data/changelog.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Metro
|
2
2
|
|
3
|
+
## 0.2.5 / 2012-11-18
|
4
|
+
|
5
|
+
* FIX metro::ui::rectangle calculation
|
6
|
+
* FIX remaining references to metro::models::* to metro::ui::*
|
7
|
+
* FIX Models will use their setters over setting raw properties
|
8
|
+
* Metro::UI::Label now supports horizontal alignment, vertical alignment, and multiple lines
|
9
|
+
|
3
10
|
## 0.2.4 / 2012-11-15
|
4
11
|
|
5
12
|
* All retrieved models from properties are now cached for better performance
|
data/lib/metro/missing_scene.rb
CHANGED
@@ -10,12 +10,12 @@ module Metro
|
|
10
10
|
position: "20,20,1",
|
11
11
|
color: "rgb(255,0,0)",
|
12
12
|
font: {size: 80},
|
13
|
-
model: "metro::
|
13
|
+
model: "metro::ui::label"
|
14
14
|
|
15
15
|
draw :message, text: 'The scene `#{self.class.missing_scene}` was requested, but is missing!',
|
16
16
|
position: "20,100,1",
|
17
17
|
color: "rgb(255,255,255)",
|
18
|
-
model: "metro::
|
18
|
+
model: "metro::ui::label"
|
19
19
|
|
20
20
|
end
|
21
21
|
end
|
data/lib/metro/models/draws.rb
CHANGED
@@ -22,7 +22,7 @@ module Metro
|
|
22
22
|
# 'x' => 20, 'y' => 20, 'z-order' => 0,
|
23
23
|
# 'x-factor' => 3, 'y-factor' => 3,
|
24
24
|
# 'color' => 0xffffffff,
|
25
|
-
# 'model' => 'metro::
|
25
|
+
# 'model' => 'metro::ui::label'
|
26
26
|
#
|
27
27
|
# def show
|
28
28
|
# puts "Where is my title? #{title.x},#{title.y}"
|
@@ -54,7 +54,7 @@ module Metro
|
|
54
54
|
# @see #draw
|
55
55
|
#
|
56
56
|
def play(song_name,options={})
|
57
|
-
draw song_name, options.merge(model: "metro::
|
57
|
+
draw song_name, options.merge(model: "metro::audio::song")
|
58
58
|
end
|
59
59
|
|
60
60
|
#
|
data/lib/metro/models/model.rb
CHANGED
@@ -13,6 +13,7 @@ module Metro
|
|
13
13
|
# @see Models::Generic
|
14
14
|
#
|
15
15
|
class Model
|
16
|
+
include PropertyOwner
|
16
17
|
include Units
|
17
18
|
|
18
19
|
#
|
@@ -28,7 +29,6 @@ module Metro
|
|
28
29
|
#
|
29
30
|
def after_initialize ; end
|
30
31
|
|
31
|
-
|
32
32
|
#
|
33
33
|
# This is an entry point for customization. After the model's properties
|
34
34
|
# have been set and the model has been assigned to the window and scene
|
@@ -39,7 +39,6 @@ module Metro
|
|
39
39
|
#
|
40
40
|
def show ; end
|
41
41
|
|
42
|
-
|
43
42
|
#
|
44
43
|
# This is called every update interval while the actor is in the scene
|
45
44
|
#
|
@@ -47,7 +46,6 @@ module Metro
|
|
47
46
|
#
|
48
47
|
def update ; end
|
49
48
|
|
50
|
-
|
51
49
|
#
|
52
50
|
# This is called after an update. A model normally is not removed after
|
53
51
|
# an update, however if the model responds true to #completed? then it
|
@@ -58,7 +56,6 @@ module Metro
|
|
58
56
|
#
|
59
57
|
def completed? ; false ; end
|
60
58
|
|
61
|
-
|
62
59
|
#
|
63
60
|
# This is called after every {#update} and when the OS wants the window to
|
64
61
|
# repaint itself.
|
@@ -67,124 +64,16 @@ module Metro
|
|
67
64
|
#
|
68
65
|
def draw ; end
|
69
66
|
|
70
|
-
|
71
|
-
#
|
72
|
-
# Define a property for the model. A property has a name and then can optionally specify
|
73
|
-
# a property type which will receive additional options.
|
74
|
-
#
|
75
|
-
# @example Defining various propertys for a model
|
76
67
|
#
|
77
|
-
#
|
78
|
-
# property :position
|
79
|
-
# property :angle, default: 0.0
|
80
|
-
# property :turn_amount, default: 4.5
|
81
|
-
# property :image, path: "player.png"
|
82
|
-
# property :motto, type: :text, default: 'Hometown Heroes!'
|
83
|
-
# end
|
68
|
+
# @return [String] the name of the model class.
|
84
69
|
#
|
85
|
-
|
86
|
-
# happens for the 'position' and 'image' properties defined above. Both of those map to respective
|
87
|
-
# properties with matching names.
|
88
|
-
#
|
89
|
-
# Properties by default are assumed to be numeric properties so the types does not have to be stated.
|
90
|
-
# This is the case for 'angle' and 'turn_amount' properties.
|
91
|
-
#
|
92
|
-
# You may use any particular name for your properties as long as you specify the type. This is the case
|
93
|
-
# for the 'motto' property.
|
94
|
-
#
|
95
|
-
def self.property(name,options={},&block)
|
96
|
-
|
97
|
-
# Use the name as the property type if one has not been provided.
|
98
|
-
|
99
|
-
property_type = options[:type] || name
|
100
|
-
|
101
|
-
property_class = Property.property(property_type)
|
102
|
-
|
103
|
-
define_method name do
|
104
|
-
raw_value = properties[name]
|
105
|
-
|
106
|
-
unless parsed_value = instance_variable_get("@_property_parsed_#{name}")
|
107
|
-
parsed_value = property_class.new(self,options,&block).get(raw_value)
|
108
|
-
instance_variable_set("@_property_parsed_#{name}",parsed_value)
|
109
|
-
end
|
110
|
-
|
111
|
-
parsed_value
|
112
|
-
end
|
113
|
-
|
114
|
-
define_method "#{name}=" do |value|
|
115
|
-
instance_variable_set("@_property_parsed_#{name}",nil)
|
116
|
-
prepared_value = property_class.new(self,options).set(value)
|
117
|
-
properties[name] = prepared_value
|
118
|
-
end
|
119
|
-
|
120
|
-
# Define any sub-properties defined on this property
|
121
|
-
|
122
|
-
# When the name does not match the property type then we want to force
|
123
|
-
# the prefixing to be on for our sub-properties. This is to make sure
|
124
|
-
# that when people define multiple fonts and colors that they do not
|
125
|
-
# overlap.
|
126
|
-
|
127
|
-
override_prefix = !(name == property_type)
|
128
|
-
|
129
|
-
property_class.defined_properties.each do |subproperty|
|
130
|
-
sub_options = { prefix: override_prefix }.merge(subproperty.options)
|
131
|
-
sub_options = sub_options.merge(parents: (Array(sub_options[:parents]) + [name]))
|
132
|
-
_sub_property subproperty.name, sub_options
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
70
|
+
property :model, type: :text
|
136
71
|
|
137
72
|
#
|
138
|
-
#
|
139
|
-
#
|
73
|
+
# @return [String] the name of model as it is used within the view or the scene.
|
74
|
+
# This is the common name, the key within the view file, or the name symbol
|
75
|
+
# name specified in the scene.
|
140
76
|
#
|
141
|
-
def self._sub_property(name,options={},&block)
|
142
|
-
|
143
|
-
# Use the name as the property type if one has not been provided.
|
144
|
-
|
145
|
-
property_type = options[:type] || name
|
146
|
-
|
147
|
-
property_class = Property.property(property_type)
|
148
|
-
|
149
|
-
parents = Array(options[:parents])
|
150
|
-
|
151
|
-
method_name = name
|
152
|
-
|
153
|
-
if options[:prefix]
|
154
|
-
method_name = (parents + [name]).join("_")
|
155
|
-
end
|
156
|
-
|
157
|
-
# Define a getter for the sub-property that will traverse the
|
158
|
-
# parent properties, finally returning the filtered value
|
159
|
-
|
160
|
-
define_method method_name do
|
161
|
-
raw_value = (parents + [name]).inject(self) {|current,method| current.send(method) }
|
162
|
-
property_class.new(self,options).get raw_value
|
163
|
-
end
|
164
|
-
|
165
|
-
# Define a setter for the sub-property that will find the parent
|
166
|
-
# value and set itself on that with the filtered value. The parent
|
167
|
-
# is then set.
|
168
|
-
#
|
169
|
-
# @TODO: If getters return dups and not instances of the original object then a very
|
170
|
-
# deep setter will not be valid.
|
171
|
-
#
|
172
|
-
define_method "#{method_name}=" do |value|
|
173
|
-
parent_value = parents.inject(self) {|current,method| current.send(method) }
|
174
|
-
|
175
|
-
prepared_value = property_class.new(self,options,&block).set(value)
|
176
|
-
parent_value.send("#{name}=",prepared_value)
|
177
|
-
|
178
|
-
send("#{parents.last}=",parent_value)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
|
-
def properties
|
184
|
-
@properties ||= {}
|
185
|
-
end
|
186
|
-
|
187
|
-
property :model, type: :text
|
188
77
|
property :name, type: :text
|
189
78
|
|
190
79
|
#
|
@@ -273,7 +162,13 @@ module Metro
|
|
273
162
|
|
274
163
|
# Clean up and symbolize all the keys then merge that with the existing properties
|
275
164
|
options.keys.each do |key|
|
276
|
-
|
165
|
+
property_name = key.to_s.underscore.to_sym
|
166
|
+
if respond_to? "#{property_name}="
|
167
|
+
send("#{property_name}=",options.delete(key))
|
168
|
+
else
|
169
|
+
options[property_name] = options.delete(key)
|
170
|
+
end
|
171
|
+
|
277
172
|
end
|
278
173
|
|
279
174
|
properties.merge! options
|
@@ -331,7 +226,7 @@ module Metro
|
|
331
226
|
end
|
332
227
|
|
333
228
|
def self.models_hash
|
334
|
-
@models_hash ||= HashWithIndifferentAccess.new("Metro::
|
229
|
+
@models_hash ||= HashWithIndifferentAccess.new("Metro::UI::Generic")
|
335
230
|
end
|
336
231
|
|
337
232
|
end
|
@@ -196,9 +196,10 @@ module Metro
|
|
196
196
|
|
197
197
|
end
|
198
198
|
|
199
|
+
require_relative 'property_owner'
|
200
|
+
|
199
201
|
require_relative 'numeric_property'
|
200
202
|
require_relative 'text_property'
|
201
|
-
|
202
203
|
require_relative 'animation_property'
|
203
204
|
require_relative 'color_property'
|
204
205
|
require_relative 'dimensions_property'
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
module PropertyOwner
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# The raw properties of the model. Most properties defined through the `property`
|
11
|
+
# class method will have getters/setters that will do the appropriate translation
|
12
|
+
# so this should in cases when you need access to the raw properties or there
|
13
|
+
# is not a property accessors defined.
|
14
|
+
#
|
15
|
+
# @return [Hash] the raw properties of the model.
|
16
|
+
#
|
17
|
+
def properties
|
18
|
+
@properties ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
|
23
|
+
#
|
24
|
+
# Define a property for the model. A property has a name and then can optionally specify
|
25
|
+
# a property type which will receive additional options.
|
26
|
+
#
|
27
|
+
# @example Defining various propertys for a model
|
28
|
+
#
|
29
|
+
# class Player
|
30
|
+
# property :position
|
31
|
+
# property :angle, default: 0.0
|
32
|
+
# property :turn_amount, default: 4.5
|
33
|
+
# property :image, path: "player.png"
|
34
|
+
# property :motto, type: :text, default: 'Hometown Heroes!'
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# When the property name matches a property definition with that name they will be used. This is what
|
38
|
+
# happens for the 'position' and 'image' properties defined above. Both of those map to respective
|
39
|
+
# properties with matching names.
|
40
|
+
#
|
41
|
+
# Properties by default are assumed to be numeric properties so the types does not have to be stated.
|
42
|
+
# This is the case for 'angle' and 'turn_amount' properties.
|
43
|
+
#
|
44
|
+
# You may use any particular name for your properties as long as you specify the type. This is the case
|
45
|
+
# for the 'motto' property.
|
46
|
+
#
|
47
|
+
def property(name,options={},&block)
|
48
|
+
|
49
|
+
# Use the name as the property type if one has not been provided.
|
50
|
+
|
51
|
+
property_type = options[:type] || name
|
52
|
+
|
53
|
+
property_class = Model::Property.property(property_type)
|
54
|
+
|
55
|
+
define_method name do
|
56
|
+
raw_value = properties[name]
|
57
|
+
|
58
|
+
unless parsed_value = instance_variable_get("@_property_parsed_#{name}")
|
59
|
+
parsed_value = property_class.new(self,options,&block).get(raw_value)
|
60
|
+
instance_variable_set("@_property_parsed_#{name}",parsed_value)
|
61
|
+
end
|
62
|
+
|
63
|
+
parsed_value
|
64
|
+
end
|
65
|
+
|
66
|
+
define_method "#{name}=" do |value|
|
67
|
+
instance_variable_set("@_property_parsed_#{name}",nil)
|
68
|
+
prepared_value = property_class.new(self,options).set(value)
|
69
|
+
properties[name] = prepared_value
|
70
|
+
end
|
71
|
+
|
72
|
+
# Define any sub-properties defined on this property
|
73
|
+
|
74
|
+
# When the name does not match the property type then we want to force
|
75
|
+
# the prefixing to be on for our sub-properties. This is to make sure
|
76
|
+
# that when people define multiple fonts and colors that they do not
|
77
|
+
# overlap.
|
78
|
+
|
79
|
+
override_prefix = !(name == property_type)
|
80
|
+
|
81
|
+
property_class.defined_properties.each do |subproperty|
|
82
|
+
sub_options = { prefix: override_prefix }.merge(subproperty.options)
|
83
|
+
sub_options = sub_options.merge(parents: (Array(sub_options[:parents]) + [name]))
|
84
|
+
_sub_property subproperty.name, sub_options
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Defines the sub-properties defined within the property. This is to be used internally
|
91
|
+
# by the #property method.
|
92
|
+
#
|
93
|
+
def _sub_property(name,options={},&block)
|
94
|
+
|
95
|
+
# Use the name as the property type if one has not been provided.
|
96
|
+
|
97
|
+
property_type = options[:type] || name
|
98
|
+
|
99
|
+
property_class = Model::Property.property(property_type)
|
100
|
+
|
101
|
+
parents = Array(options[:parents])
|
102
|
+
|
103
|
+
method_name = name
|
104
|
+
|
105
|
+
if options[:prefix]
|
106
|
+
method_name = (parents + [name]).join("_")
|
107
|
+
end
|
108
|
+
|
109
|
+
# Define a getter for the sub-property that will traverse the
|
110
|
+
# parent properties, finally returning the filtered value
|
111
|
+
|
112
|
+
define_method method_name do
|
113
|
+
raw_value = (parents + [name]).inject(self) {|current,method| current.send(method) }
|
114
|
+
property_class.new(self,options).get raw_value
|
115
|
+
end
|
116
|
+
|
117
|
+
# Define a setter for the sub-property that will find the parent
|
118
|
+
# value and set itself on that with the filtered value. The parent
|
119
|
+
# is then set.
|
120
|
+
#
|
121
|
+
# @TODO: If getters return dups and not instances of the original object then a very
|
122
|
+
# deep setter will not be valid.
|
123
|
+
#
|
124
|
+
define_method "#{method_name}=" do |value|
|
125
|
+
parent_value = parents.inject(self) {|current,method| current.send(method) }
|
126
|
+
|
127
|
+
prepared_value = property_class.new(self,options,&block).set(value)
|
128
|
+
parent_value.send("#{name}=",prepared_value)
|
129
|
+
|
130
|
+
send("#{parents.last}=",parent_value)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
@@ -2,10 +2,10 @@ module Metro
|
|
2
2
|
module UI
|
3
3
|
|
4
4
|
#
|
5
|
-
# Draws a string of text
|
5
|
+
# Draws a string of text.
|
6
6
|
#
|
7
7
|
# @example Using the Label in a view file
|
8
|
-
# model: "metro::
|
8
|
+
# model: "metro::ui::label"
|
9
9
|
#
|
10
10
|
class Label < Model
|
11
11
|
|
@@ -19,8 +19,17 @@ module Metro
|
|
19
19
|
|
20
20
|
property :text
|
21
21
|
|
22
|
+
property :align, type: :text, default: "left"
|
23
|
+
property :vertical_align, type: :text, default: "top"
|
24
|
+
|
22
25
|
property :dimensions do
|
23
|
-
Dimensions.of (
|
26
|
+
Dimensions.of (longest_line * x_factor), (line_height * line_count * 2 * y_factor)
|
27
|
+
end
|
28
|
+
|
29
|
+
def draw
|
30
|
+
parsed_text.each_with_index do |line,index|
|
31
|
+
font.draw line, x_position, y_position(index), z_order, x_factor, y_factor, color
|
32
|
+
end
|
24
33
|
end
|
25
34
|
|
26
35
|
def bounds
|
@@ -31,8 +40,83 @@ module Metro
|
|
31
40
|
bounds.contains?(x,y)
|
32
41
|
end
|
33
42
|
|
34
|
-
|
35
|
-
|
43
|
+
private
|
44
|
+
|
45
|
+
def line_height
|
46
|
+
font.height
|
47
|
+
end
|
48
|
+
|
49
|
+
def half_line_height
|
50
|
+
line_height / 2
|
51
|
+
end
|
52
|
+
|
53
|
+
def line_count
|
54
|
+
parsed_text.count
|
55
|
+
end
|
56
|
+
|
57
|
+
def parsed_text
|
58
|
+
text.split("\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
def longest_line
|
62
|
+
parsed_text.map { |line| font.text_width(line) }.max
|
63
|
+
end
|
64
|
+
|
65
|
+
def x_left_alignment
|
66
|
+
x
|
67
|
+
end
|
68
|
+
|
69
|
+
def x_center_alignment
|
70
|
+
x - width / 2
|
71
|
+
end
|
72
|
+
|
73
|
+
def x_right_alignment
|
74
|
+
x - width
|
75
|
+
end
|
76
|
+
|
77
|
+
def horizontal_alignments
|
78
|
+
{ left: :x_left_alignment,
|
79
|
+
center: :x_center_alignment,
|
80
|
+
right: :x_right_alignment }
|
81
|
+
end
|
82
|
+
|
83
|
+
def x_position
|
84
|
+
alignment = horizontal_alignments[align.to_sym]
|
85
|
+
send(alignment)
|
86
|
+
end
|
87
|
+
|
88
|
+
def y_top_alignment(index)
|
89
|
+
y + (index * line_height)
|
90
|
+
end
|
91
|
+
|
92
|
+
def y_bottom_alignment(index)
|
93
|
+
y - line_height * (line_count - index)
|
94
|
+
end
|
95
|
+
|
96
|
+
def y_center_alignment(index)
|
97
|
+
if line_count.even?
|
98
|
+
full_height = (line_count / 2 - index) * line_height
|
99
|
+
else
|
100
|
+
offset = (line_count / 2 - index)
|
101
|
+
if offset < 0
|
102
|
+
full_height = (offset + 1) * line_height - half_line_height
|
103
|
+
else
|
104
|
+
full_height = offset * line_height + half_line_height
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
y - full_height
|
109
|
+
end
|
110
|
+
|
111
|
+
def vertical_alignments
|
112
|
+
{ top: :y_top_alignment,
|
113
|
+
center: :y_center_alignment,
|
114
|
+
bottom: :y_bottom_alignment }
|
115
|
+
end
|
116
|
+
|
117
|
+
def y_position(index)
|
118
|
+
alignment = vertical_alignments[vertical_align.to_sym]
|
119
|
+
send(alignment,index)
|
36
120
|
end
|
37
121
|
|
38
122
|
end
|
@@ -12,12 +12,28 @@ module Metro
|
|
12
12
|
window.dimensions
|
13
13
|
end
|
14
14
|
|
15
|
+
def left_x
|
16
|
+
x
|
17
|
+
end
|
18
|
+
|
19
|
+
def right_x
|
20
|
+
x + width
|
21
|
+
end
|
22
|
+
|
23
|
+
def top_y
|
24
|
+
y
|
25
|
+
end
|
26
|
+
|
27
|
+
def bottom_y
|
28
|
+
y + height
|
29
|
+
end
|
30
|
+
|
15
31
|
def draw
|
16
|
-
window.draw_quad(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
32
|
+
window.draw_quad(left_x,top_y,color,
|
33
|
+
right_x,top_y,color,
|
34
|
+
right_x,bottom_y,color,
|
35
|
+
left_x,bottom_y,color,
|
36
|
+
z_order)
|
21
37
|
end
|
22
38
|
end
|
23
39
|
end
|
data/lib/metro/version.rb
CHANGED
@@ -12,11 +12,25 @@ possibly any notes or caveats about the game.
|
|
12
12
|
|
13
13
|
## Resources
|
14
14
|
|
15
|
-
|
15
|
+
### Programming
|
16
|
+
|
17
|
+
* [YAML for Ruby](http://www.yaml.org/YAML_for_ruby.html) reference which can help you define views in the game.
|
18
|
+
* [JSONLint](http://jsonlint.com/) is a JSON Validator
|
19
|
+
|
20
|
+
### Art
|
16
21
|
|
17
22
|
* [Lost Garden](http://www.lostgarden.com/2007/05/dancs-miraculously-flexible-game.html)
|
23
|
+
* [TimelieFX](http://www.rigzsoft.co.uk/) particle editor allows you to export animations.
|
24
|
+
* [Text to ASCII Art Generator](http://patorjk.com/software/taag)
|
25
|
+
* [Icons](http://css-tricks.com/flat-icons-icon-fonts/)
|
26
|
+
* [Subtle Patterns](http://subtlepatterns.com/) various backgrounds and textures.
|
27
|
+
|
28
|
+
### Sound
|
29
|
+
|
30
|
+
* [as3sfxr](http://www.superflashbros.net/as3sfxr/) generates unique sounds.
|
31
|
+
* [Ableton](https://www.ableton.com/en/) music generation tool.
|
18
32
|
|
19
|
-
|
33
|
+
### Books
|
20
34
|
|
21
35
|
* [Rules of Play](http://www.amazon.com/dp/0262240459)
|
22
36
|
* [Game Programming Gems 8](http://www.amazon.com/dp/1584507020)
|
@@ -26,4 +40,4 @@ possibly any notes or caveats about the game.
|
|
26
40
|
* [Challenges For Game Designers](http://www.amazon.com/dp/158450580X)
|
27
41
|
* [The Art of Game Design: A book of lenses](http://www.amazon.com/dp/0123694965)
|
28
42
|
* [A Theory of Fun](http://www.theoryoffun.com)
|
29
|
-
* [Andrew Rollings and Ernest Adams on Game Design](http://www.amazon.com/dp/1592730019)
|
43
|
+
* [Andrew Rollings and Ernest Adams on Game Design](http://www.amazon.com/dp/1592730019)
|
data/lib/templates/scene.rb.tt
CHANGED
@@ -14,7 +14,7 @@ class <%= scene_class_name %> < GameScene
|
|
14
14
|
# position: '20,20,0',
|
15
15
|
# font: { size: 60 },
|
16
16
|
# color: 'rgb(255,255,255)',
|
17
|
-
# model: 'metro::
|
17
|
+
# model: 'metro::ui::label'
|
18
18
|
#
|
19
19
|
# The draw method can be simplier for models that have content defined
|
20
20
|
# for them in the view or the models themselves define the appropriate
|
data/lib/templates/view.yaml.tt
CHANGED
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Metro::UI::Label do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
label = described_class.new text: expected_text
|
7
|
+
label.window = mock('window')
|
8
|
+
label
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
# Reset the position of the label to the default
|
13
|
+
subject.position = nil
|
14
|
+
subject.scale = Scale.one
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:expected_position) { Point.zero }
|
18
|
+
its(:position) { should eq expected_position }
|
19
|
+
|
20
|
+
its(:x) { should eq expected_position.x }
|
21
|
+
its(:y) { should eq expected_position.y }
|
22
|
+
its(:z) { should eq expected_position.z }
|
23
|
+
its(:z_order) { should eq expected_position.z_order }
|
24
|
+
|
25
|
+
context "when setting the position" do
|
26
|
+
|
27
|
+
it "should be set succesfully" do
|
28
|
+
subject.position = "10,10"
|
29
|
+
subject.position.should eq Point.at(10,10)
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when setting the x property" do
|
33
|
+
let(:expected_x) { 11 }
|
34
|
+
let(:expected_y) { 0 }
|
35
|
+
|
36
|
+
it "should update successfully" do
|
37
|
+
subject.x = expected_x
|
38
|
+
subject.x.should eq expected_x
|
39
|
+
subject.position.x.should eq expected_x
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not effect the paired y property" do
|
43
|
+
subject.x = expected_x
|
44
|
+
subject.y.should eq expected_y
|
45
|
+
subject.position.y.should eq expected_y
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when setting the y property" do
|
50
|
+
before do
|
51
|
+
subject.position = "#{expected_x},#{expected_y}"
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:expected_x) { 320 }
|
55
|
+
let(:expected_y) { 66 }
|
56
|
+
|
57
|
+
it "should update successfully" do
|
58
|
+
subject.y = expected_y
|
59
|
+
subject.y.should eq expected_y
|
60
|
+
subject.position.y.should eq expected_y
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not effect the paired x property" do
|
64
|
+
subject.y = expected_y
|
65
|
+
subject.x.should eq expected_x
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:expected_color) { Gosu::Color.new "rgb(255,255,255)" }
|
72
|
+
let(:expected_alpha) { 255 }
|
73
|
+
|
74
|
+
its(:color) { should eq expected_color }
|
75
|
+
its(:alpha) { should eq expected_alpha }
|
76
|
+
|
77
|
+
describe "font" do
|
78
|
+
before do
|
79
|
+
Metro::Model::FontProperty.stub(:create_font).and_return(font)
|
80
|
+
end
|
81
|
+
|
82
|
+
let(:font) { mock('font', name: expected_font_name, size: expected_font_size) }
|
83
|
+
|
84
|
+
let(:expected_font) { font }
|
85
|
+
its(:font) { should eq expected_font }
|
86
|
+
|
87
|
+
let(:expected_font_name) { 'mock_font_name' }
|
88
|
+
its(:font_name) { should eq expected_font_name }
|
89
|
+
|
90
|
+
let(:expected_font_size) { 12.0 }
|
91
|
+
its(:font_size) { should eq expected_font_size }
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:expected_scale) { Scale.one }
|
96
|
+
|
97
|
+
its(:scale) { should eq expected_scale }
|
98
|
+
its(:x_factor) { should eq expected_scale.x_factor }
|
99
|
+
its(:y_factor) { should eq expected_scale.y_factor }
|
100
|
+
|
101
|
+
context "when setting the scale" do
|
102
|
+
it "should be set successfully" do
|
103
|
+
subject.x_factor = 2.0
|
104
|
+
subject.x_factor.should eq 2.0
|
105
|
+
subject.scale.x_factor.should eq 2.0
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
its(:align) { should eq expected_horizontal_alignment }
|
110
|
+
let(:expected_horizontal_alignment) { "left" }
|
111
|
+
|
112
|
+
its(:vertical_align) { should eq expected_vertical_alignment }
|
113
|
+
let(:expected_vertical_alignment) { "top" }
|
114
|
+
|
115
|
+
its(:text) { should eq expected_text }
|
116
|
+
let(:expected_text) { "Four Score and Seven Years Ago" }
|
117
|
+
|
118
|
+
context "when the text defines multiple lines (lines separated by newline characters)" do
|
119
|
+
|
120
|
+
let(:given_text) { "My name is something that takes\ntwo lines to express!" }
|
121
|
+
let(:first_line) { given_text.split("\n").first }
|
122
|
+
let(:last_line) { given_text.split("\n").last }
|
123
|
+
|
124
|
+
let(:x_position) { 320 }
|
125
|
+
let(:y_position) { 200 }
|
126
|
+
let(:z_order) { 12 }
|
127
|
+
|
128
|
+
let(:scale_x) { 1.0 }
|
129
|
+
let(:scale_y) { 1.0 }
|
130
|
+
|
131
|
+
|
132
|
+
let(:font_height) { 20 }
|
133
|
+
|
134
|
+
before do
|
135
|
+
subject.text = given_text
|
136
|
+
subject.position = Point.at(x_position,y_position,z_order)
|
137
|
+
subject.scale = Scale.to(scale_x,scale_y)
|
138
|
+
subject.stub(:font).and_return(font)
|
139
|
+
end
|
140
|
+
|
141
|
+
let(:font) do
|
142
|
+
font = mock('font')
|
143
|
+
font.stub(:text_width) { 12 }
|
144
|
+
font.stub(:height) { font_height }
|
145
|
+
font
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should have the font draw each of the lines" do
|
149
|
+
font.should_receive(:draw).twice
|
150
|
+
subject.draw
|
151
|
+
end
|
152
|
+
|
153
|
+
context "when the vertical alignment is top" do
|
154
|
+
|
155
|
+
before do
|
156
|
+
subject.vertical_align = "top"
|
157
|
+
end
|
158
|
+
|
159
|
+
let(:first_line_y_position) { y_position }
|
160
|
+
let(:second_line_y_position) { y_position + font_height }
|
161
|
+
|
162
|
+
it "should draw the first line at the y position" do
|
163
|
+
font.should_receive(:draw).with(first_line,x_position,first_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
164
|
+
font.should_receive(:draw).with(last_line,x_position,second_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
165
|
+
subject.draw
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when the vertical alignment is center" do
|
171
|
+
|
172
|
+
before do
|
173
|
+
subject.text = text
|
174
|
+
subject.vertical_align = "center"
|
175
|
+
end
|
176
|
+
|
177
|
+
let(:text) { "Three Lines\nOf Text\nWill Create Fun!" }
|
178
|
+
|
179
|
+
|
180
|
+
let(:first_line) { text.split("\n")[0] }
|
181
|
+
let(:second_line) { text.split("\n")[1] }
|
182
|
+
let(:third_line) { text.split("\n")[2] }
|
183
|
+
|
184
|
+
|
185
|
+
let(:first_line_y_position) { y_position - font_height - font_height / 2 }
|
186
|
+
let(:second_line_y_position) { y_position - font_height / 2 }
|
187
|
+
let(:third_line_y_position) { y_position + font_height / 2 }
|
188
|
+
|
189
|
+
it "should draw the first line at the y position" do
|
190
|
+
font.should_receive(:draw).with(first_line,x_position,first_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
191
|
+
font.should_receive(:draw).with(second_line,x_position,second_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
192
|
+
font.should_receive(:draw).with(third_line,x_position,third_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
193
|
+
subject.draw
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
context "when the vertical alignment is bottom" do
|
199
|
+
|
200
|
+
before do
|
201
|
+
subject.vertical_align = "bottom"
|
202
|
+
end
|
203
|
+
|
204
|
+
let(:first_line_y_position) { y_position - font_height * 2 }
|
205
|
+
let(:second_line_y_position) { y_position - font_height }
|
206
|
+
|
207
|
+
it "should draw the first line at the y position" do
|
208
|
+
font.should_receive(:draw).with(first_line,x_position,first_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
209
|
+
font.should_receive(:draw).with(last_line,x_position,second_line_y_position,z_order,scale_x,scale_y,an_instance_of(Gosu::Color))
|
210
|
+
subject.draw
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gosu
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- lib/metro/models/properties/numeric_property.rb
|
164
164
|
- lib/metro/models/properties/position_property.rb
|
165
165
|
- lib/metro/models/properties/property.rb
|
166
|
+
- lib/metro/models/properties/property_owner.rb
|
166
167
|
- lib/metro/models/properties/sample_property.rb
|
167
168
|
- lib/metro/models/properties/scale_property.rb
|
168
169
|
- lib/metro/models/properties/song_property.rb
|
@@ -220,12 +221,12 @@ files:
|
|
220
221
|
- spec/core_ext/string_spec.rb
|
221
222
|
- spec/gosu_ext/color_spec.rb
|
222
223
|
- spec/metro/models/key_value_coding_spec.rb
|
223
|
-
- spec/metro/models/models/label_spec.rb
|
224
224
|
- spec/metro/models/properties/color_spec.rb
|
225
225
|
- spec/metro/models/properties/dimensions_spec.rb
|
226
226
|
- spec/metro/models/properties/font_spec.rb
|
227
227
|
- spec/metro/models/properties/numeric_property_spec.rb
|
228
228
|
- spec/metro/models/properties/position_property_spec.rb
|
229
|
+
- spec/metro/models/ui/label_spec.rb
|
229
230
|
- spec/metro/scene_spec.rb
|
230
231
|
- spec/metro/scene_views/json_view_spec.rb
|
231
232
|
- spec/metro/scene_views/yaml_view_spec.rb
|
@@ -237,11 +238,11 @@ licenses: []
|
|
237
238
|
post_install_message: ! " ______ ___ _____\n ___ |/ /_____ __ /_______________\n
|
238
239
|
\ __ /|_/ / _ _ \\_ __/__ ___/_ __ \\\n _ / / / / __// /_ _ / /
|
239
240
|
/_/ /\n /_/ /_/ \\___/ \\__/ /_/ \\____/\n\n Thank you for installing
|
240
|
-
metro 0.2.
|
241
|
-
\ Changes:\n \n *
|
242
|
-
|
243
|
-
|
244
|
-
|
241
|
+
metro 0.2.5 / 2012-11-18.\n ---------------------------------------------------------------------\n
|
242
|
+
\ Changes:\n \n * FIX metro::ui::rectangle calculation\n * FIX remaining references
|
243
|
+
to metro::models::* to metro::ui::*\n * FIX Models will use their setters over
|
244
|
+
setting raw properties\n * Metro::UI::Label now supports horizontal alignment,
|
245
|
+
vertical alignment, and multiple lines\n \n\n ---------------------------------------------------------------------\n"
|
245
246
|
rdoc_options: []
|
246
247
|
require_paths:
|
247
248
|
- lib
|
@@ -270,12 +271,12 @@ test_files:
|
|
270
271
|
- spec/core_ext/string_spec.rb
|
271
272
|
- spec/gosu_ext/color_spec.rb
|
272
273
|
- spec/metro/models/key_value_coding_spec.rb
|
273
|
-
- spec/metro/models/models/label_spec.rb
|
274
274
|
- spec/metro/models/properties/color_spec.rb
|
275
275
|
- spec/metro/models/properties/dimensions_spec.rb
|
276
276
|
- spec/metro/models/properties/font_spec.rb
|
277
277
|
- spec/metro/models/properties/numeric_property_spec.rb
|
278
278
|
- spec/metro/models/properties/position_property_spec.rb
|
279
|
+
- spec/metro/models/ui/label_spec.rb
|
279
280
|
- spec/metro/scene_spec.rb
|
280
281
|
- spec/metro/scene_views/json_view_spec.rb
|
281
282
|
- spec/metro/scene_views/yaml_view_spec.rb
|
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Metro::Models::Label do
|
4
|
-
|
5
|
-
subject do
|
6
|
-
label = described_class.new
|
7
|
-
label.window = mock('window')
|
8
|
-
label
|
9
|
-
end
|
10
|
-
|
11
|
-
before do
|
12
|
-
# Reset the position of the label to the default
|
13
|
-
subject.position = nil
|
14
|
-
subject.scale = Scale.one
|
15
|
-
end
|
16
|
-
|
17
|
-
let(:expected_position) { Point.zero }
|
18
|
-
its(:position) { should eq expected_position }
|
19
|
-
|
20
|
-
its(:x) { should eq expected_position.x }
|
21
|
-
its(:y) { should eq expected_position.y }
|
22
|
-
its(:z) { should eq expected_position.z }
|
23
|
-
its(:z_order) { should eq expected_position.z_order }
|
24
|
-
|
25
|
-
context "when setting the position" do
|
26
|
-
|
27
|
-
it "should be set succesfully" do
|
28
|
-
subject.position = "10,10"
|
29
|
-
subject.position.should eq Point.at(10,10)
|
30
|
-
end
|
31
|
-
|
32
|
-
context "when setting the x property" do
|
33
|
-
let(:expected_x) { 11 }
|
34
|
-
let(:expected_y) { 0 }
|
35
|
-
|
36
|
-
it "should update successfully" do
|
37
|
-
subject.x = expected_x
|
38
|
-
subject.x.should eq expected_x
|
39
|
-
subject.position.x.should eq expected_x
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should not effect the paired y property" do
|
43
|
-
subject.x = expected_x
|
44
|
-
subject.y.should eq expected_y
|
45
|
-
subject.position.y.should eq expected_y
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context "when setting the y property" do
|
50
|
-
before do
|
51
|
-
subject.position = "#{expected_x},#{expected_y}"
|
52
|
-
end
|
53
|
-
|
54
|
-
let(:expected_x) { 320 }
|
55
|
-
let(:expected_y) { 66 }
|
56
|
-
|
57
|
-
it "should update successfully" do
|
58
|
-
subject.y = expected_y
|
59
|
-
subject.y.should eq expected_y
|
60
|
-
subject.position.y.should eq expected_y
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should not effect the paired x property" do
|
64
|
-
subject.y = expected_y
|
65
|
-
subject.x.should eq expected_x
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
let(:expected_color) { Gosu::Color.new "rgb(255,255,255)" }
|
72
|
-
let(:expected_alpha) { 255 }
|
73
|
-
|
74
|
-
its(:color) { should eq expected_color }
|
75
|
-
its(:alpha) { should eq expected_alpha }
|
76
|
-
|
77
|
-
|
78
|
-
describe "font" do
|
79
|
-
before do
|
80
|
-
Metro::Model::FontProperty.stub(:create_font).and_return(font)
|
81
|
-
end
|
82
|
-
|
83
|
-
let(:font) { mock('font', name: expected_font_name, size: expected_font_size) }
|
84
|
-
|
85
|
-
let(:expected_font) { font }
|
86
|
-
its(:font) { should eq expected_font }
|
87
|
-
|
88
|
-
let(:expected_font_name) { 'mock_font_name' }
|
89
|
-
its(:font_name) { should eq expected_font_name }
|
90
|
-
|
91
|
-
let(:expected_font_size) { 12.0 }
|
92
|
-
its(:font_size) { should eq expected_font_size }
|
93
|
-
|
94
|
-
end
|
95
|
-
|
96
|
-
let(:expected_scale) { Scale.one }
|
97
|
-
|
98
|
-
its(:scale) { should eq expected_scale }
|
99
|
-
its(:x_factor) { should eq expected_scale.x_factor }
|
100
|
-
its(:y_factor) { should eq expected_scale.y_factor }
|
101
|
-
|
102
|
-
context "when setting the scale" do
|
103
|
-
it "should set" do
|
104
|
-
subject.x_factor = 2.0
|
105
|
-
# subject.x_factor.should eq 2.0
|
106
|
-
subject.scale.x_factor.should eq 2.0
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|