metro 0.2.4 → 0.2.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/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
|