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 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
@@ -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::models::label"
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::models::label"
18
+ model: "metro::ui::label"
19
19
 
20
20
  end
21
21
  end
@@ -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::models::label'
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::models::song")
57
+ draw song_name, options.merge(model: "metro::audio::song")
58
58
  end
59
59
 
60
60
  #
@@ -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
- # class Player
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
- # When the property name matches a property definition with that name they will be used. This is what
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
- # Defines the sub-properties defined within the property. This is to be used internally
139
- # by the #property method.
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
- options[key.to_s.underscore.to_sym] = options.delete(key)
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::Models::Generic")
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
@@ -5,7 +5,7 @@ module Metro
5
5
  # Draws an Image
6
6
  #
7
7
  # @example Using the Image in a view file
8
- # model: "metro::models::image"
8
+ # model: "metro::ui::image"
9
9
  #
10
10
  class Image < Model
11
11
 
@@ -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::models::label"
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 (font.text_width(text) * x_factor), (font.height * y_factor)
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
- def draw
35
- font.draw text, x, y, z_order, x_factor, y_factor, color
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(x,y,color,
17
- width,x,color,
18
- width,height,color,
19
- y,height,color,
20
- z_order)
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
@@ -15,7 +15,7 @@ module Metro
15
15
  # easier to dup scenes.
16
16
  #
17
17
  self.class.drawings.clear
18
- self.class.draw :overlay, model: "Metro::Models::GridDrawer"
18
+ self.class.draw :overlay, model: "Metro::UI::GridDrawer"
19
19
  add_actors_to_scene
20
20
  after_initialize
21
21
  end
@@ -1,7 +1,7 @@
1
1
  module Metro
2
2
  class FadeTransitionScene < TransitionScene
3
3
 
4
- draw :rectangle, model: "metro::models::rectangle"
4
+ draw :rectangle, model: "metro::ui::rectangle"
5
5
 
6
6
  #
7
7
  # When the scene is shown set up the starting color for the rectangle
data/lib/metro/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Metro
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  WEBSITE = "https://github.com/burtlo/metro"
4
4
  CONTACT_EMAILS = ["franklin.webber@gmail.com"]
5
5
 
@@ -12,11 +12,25 @@ possibly any notes or caveats about the game.
12
12
 
13
13
  ## Resources
14
14
 
15
- #### Art
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
- #### Books
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)
@@ -1,4 +1,4 @@
1
1
  brand:
2
- model: metro::models::image
2
+ model: metro::ui::image
3
3
  image: brand.jpg
4
4
  position: "320,240,1"
@@ -1,5 +1,5 @@
1
1
  title:
2
- model: metro::models::label
2
+ model: metro::ui::label
3
3
  text: "#{Game.name}"
4
4
  font:
5
5
  size: 40
@@ -1,5 +1,5 @@
1
1
  instruction: &instruction
2
- model: metro::models::label
2
+ model: metro::ui::label
3
3
  font:
4
4
  name: Arial
5
5
  size: 40
@@ -1,10 +1,10 @@
1
1
  title:
2
- model: metro::models::label
2
+ model: metro::ui::label
3
3
  text: "#{Game.name}"
4
4
  font:
5
5
  size: 40
6
6
  position: "320,100,1"
7
7
  color: rgba(255,255,255,1.0)
8
8
  menu:
9
- model: metro::models::menu
9
+ model: metro::ui::menu
10
10
  position: "260,200,1"
@@ -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::models::label'
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
@@ -1,7 +1,7 @@
1
1
  # http://www.yaml.org/YAML_for_ruby.html
2
2
  ---
3
3
  title:
4
- model: "metro::models::label"
4
+ model: "metro::ui::label"
5
5
  text: "Your Scene"
6
6
  position: "190,200,4"
7
7
  font:
@@ -14,7 +14,7 @@ describe Metro::Model::DimensionsProperty do
14
14
 
15
15
  subject do
16
16
  described_class.new model do
17
- model.window.dimensions
17
+ window.dimensions
18
18
  end
19
19
  end
20
20
 
@@ -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
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-16 00:00:00.000000000 Z
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.4 / 2012-11-15.\n ---------------------------------------------------------------------\n
241
- \ Changes:\n \n * All retrieved models from properties are now cached for better
242
- performance\n * Animations were re-vamped to accept more parameters\n * Metro
243
- models names in code are now refered to as \"metro::models::*\" to \"metro::ui::*\"\n
244
- \ \n\n ---------------------------------------------------------------------\n"
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