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 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