metro 0.1.4 → 0.1.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.
Files changed (42) hide show
  1. data/changelog.md +9 -0
  2. data/lib/commands/generate_model.rb +2 -2
  3. data/lib/commands/generate_scene.rb +2 -2
  4. data/lib/commands/generate_view.rb +1 -1
  5. data/lib/gosu_ext/color.rb +16 -2
  6. data/lib/metro.rb +50 -10
  7. data/lib/metro/events/event_data.rb +61 -0
  8. data/lib/metro/events/event_relay.rb +10 -3
  9. data/lib/metro/events/hit_list.rb +77 -0
  10. data/lib/metro/models/draws.rb +6 -1
  11. data/lib/metro/models/grid_drawer.rb +57 -0
  12. data/lib/metro/models/image.rb +18 -2
  13. data/lib/metro/models/label.rb +22 -6
  14. data/lib/metro/models/menu.rb +20 -0
  15. data/lib/metro/models/model.rb +47 -6
  16. data/lib/metro/models/model_factory.rb +2 -2
  17. data/lib/metro/models/rectangle_bounds.rb +28 -0
  18. data/lib/metro/scene.rb +46 -11
  19. data/lib/metro/scenes.rb +10 -9
  20. data/lib/metro/transitions/edit_transition_scene.rb +73 -0
  21. data/lib/metro/transitions/scene_transitions.rb +8 -2
  22. data/lib/metro/transitions/transition_scene.rb +2 -1
  23. data/lib/metro/version.rb +1 -1
  24. data/lib/metro/views/json_view.rb +60 -0
  25. data/lib/metro/{scene_view → views}/no_view.rb +12 -4
  26. data/lib/metro/views/parsers.rb +26 -0
  27. data/lib/metro/views/scene_view.rb +107 -0
  28. data/lib/metro/views/view.rb +125 -0
  29. data/lib/metro/views/writers.rb +28 -0
  30. data/lib/metro/views/yaml_view.rb +94 -0
  31. data/lib/metro/window.rb +19 -0
  32. data/metro.gemspec +1 -0
  33. data/spec/core_ext/string_spec.rb +13 -13
  34. data/spec/metro/scene_spec.rb +15 -0
  35. data/spec/metro/scene_views/json_view_spec.rb +27 -0
  36. data/spec/metro/scene_views/yaml_view_spec.rb +1 -1
  37. data/spec/metro/views/view_spec.rb +53 -0
  38. metadata +41 -11
  39. data/lib/core_ext/string.rb +0 -15
  40. data/lib/metro/scene_view/json_view.rb +0 -41
  41. data/lib/metro/scene_view/scene_view.rb +0 -83
  42. data/lib/metro/scene_view/yaml_view.rb +0 -45
@@ -3,10 +3,10 @@ module Metro
3
3
 
4
4
  #
5
5
  # Draws a string of text
6
- #
6
+ #
7
7
  # @example Using the Label in a view file
8
8
  # model: "metro::models::label"
9
- #
9
+ #
10
10
  class Label < Model
11
11
 
12
12
  attr_accessor :x, :y, :x_factor, :y_factor, :z_order
@@ -20,19 +20,35 @@ module Metro
20
20
  @size = 20
21
21
  @font_family = Gosu::default_font_name
22
22
  end
23
-
23
+
24
24
  def font
25
25
  @font ||= Gosu::Font.new(window, font_family, size)
26
26
  end
27
-
27
+
28
28
  def x
29
29
  @x || (Game.width/2 - font.text_width(text)/2)
30
30
  end
31
-
31
+
32
32
  def y
33
33
  @y || (Game.height/2 - font.height/2)
34
34
  end
35
-
35
+
36
+ def bounds
37
+ Bounds.new x, y, x + width, y + height
38
+ end
39
+
40
+ def width
41
+ font.text_width(text) * x_factor
42
+ end
43
+
44
+ def height
45
+ font.height * y_factor
46
+ end
47
+
48
+ def contains?(x,y)
49
+ bounds.contains?(x,y)
50
+ end
51
+
36
52
  def text
37
53
  scene.instance_eval( "\"#{@text}\"" )
38
54
  end
@@ -56,6 +56,26 @@ module Metro
56
56
  @font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
57
57
  end
58
58
 
59
+ def contains?(x,y)
60
+ bounds.contains?(x,y)
61
+ end
62
+
63
+ def bounds
64
+ Metro::Models::Bounds.new x, y, x + width, y + height
65
+ end
66
+
67
+ def width
68
+ font.text_width(longest_option_text)# * x_factor
69
+ end
70
+
71
+ def longest_option_text
72
+ longest = options.map {|opt| opt }.inject("") {|longest,opt| opt.length > longest.length ? opt : longest }
73
+ end
74
+
75
+ def height
76
+ options.length * font.height + (options.length - 1) * padding
77
+ end
78
+
59
79
  attr_reader :highlight_color
60
80
 
61
81
  def highlight_color=(value)
@@ -1,4 +1,5 @@
1
1
  require_relative 'key_value_coding'
2
+ require_relative 'rectangle_bounds'
2
3
 
3
4
  module Metro
4
5
 
@@ -98,6 +99,21 @@ module Metro
98
99
  color.alpha = value.to_i
99
100
  end
100
101
 
102
+ def saveable?
103
+ true
104
+ end
105
+
106
+ # Belongs to positionable items only
107
+ def contains?(x,y)
108
+ false
109
+ end
110
+
111
+ # Belongs to positionable items only
112
+ def offset(x,y)
113
+ self.x += x
114
+ self.y += y
115
+ end
116
+
101
117
  #
102
118
  # Create an instance of a model.
103
119
  #
@@ -121,7 +137,7 @@ module Metro
121
137
  options.each do |raw_key,value|
122
138
 
123
139
  key = raw_key.to_s.dup
124
- key = key.gsub(/-/,'_').snake_case
140
+ key = key.gsub(/-/,'_').underscore
125
141
 
126
142
  unless respond_to? key
127
143
  self.class.send :define_method, key do
@@ -153,17 +169,38 @@ module Metro
153
169
  # to another model.
154
170
  #
155
171
  def _save
156
- data_export = @_loaded_options.map {|option| [ option, send(option) ] }.flatten
172
+ data_export = _loaded_options.map {|option| [ option, send(option) ] }.flatten
157
173
  Hash[*data_export]
158
174
  end
159
175
 
176
+ #
177
+ # Generate a hash representation of the model. Currently this is ugly
178
+ #
179
+ def to_hash
180
+ export = _loaded_options.map {|option| [ option, send(option) ] }
181
+ export_with_name = export.reject {|item| item.first == "name" }
182
+
183
+ hash = export_with_name.inject({}) {|hash,elem| hash[elem.first] = elem.last ; hash }
184
+
185
+ # TODO:: color is a class that cannot be yamlized as it is and needs to be turned into a string.
186
+ # TODO: Hack to save the Gosu::Color class as a string value (this is
187
+ # what I hoped that the properties would solve)
188
+ hash.each do |subkey,subvalue|
189
+ if subvalue.is_a? Gosu::Color
190
+ hash[subkey] = subvalue.to_s
191
+ end
192
+ end
193
+
194
+ { name => hash }
195
+ end
196
+
160
197
  #
161
198
  # Captures all classes that subclass Model.
162
199
  #
163
200
  # @see #self.scenes
164
201
  #
165
202
  def self.inherited(base)
166
- models << base
203
+ models << base.to_s
167
204
  end
168
205
 
169
206
  #
@@ -182,12 +219,15 @@ module Metro
182
219
  def self.model(name)
183
220
  @models_hash ||= begin
184
221
 
185
- hash = Hash.new(Models::Generic)
222
+ hash = Hash.new("Metro::Models::Generic")
186
223
 
187
224
  models.each do |model|
188
- common_name = model.to_s.snake_case
225
+ common_name = model.to_s.underscore
226
+ hash[model.to_s] = model
227
+ hash[model.downcase] = model
189
228
  hash[common_name] = model
190
229
  end
230
+
191
231
  hash
192
232
  end
193
233
 
@@ -201,4 +241,5 @@ require_relative 'generic'
201
241
  require_relative 'label'
202
242
  require_relative 'menu'
203
243
  require_relative 'image'
204
- require_relative 'rectangle'
244
+ require_relative 'rectangle'
245
+ require_relative 'grid_drawer'
@@ -8,7 +8,7 @@ module Metro
8
8
  @options = options
9
9
  end
10
10
 
11
- def create(contents = {})
11
+ def create
12
12
  contents = {} unless contents
13
13
  actor_class = class_for_actor(model_name(contents))
14
14
  instance = actor_class.new
@@ -25,7 +25,7 @@ module Metro
25
25
  end
26
26
 
27
27
  def class_for_actor(model_name)
28
- Model.model(model_name)
28
+ Model.model(model_name).constantize
29
29
  end
30
30
  end
31
31
  end
@@ -0,0 +1,28 @@
1
+ module Metro
2
+ module Models
3
+
4
+ class RectangleBounds
5
+
6
+ attr_reader :min_x, :min_y, :max_x, :max_y
7
+
8
+ def initialize(min_x,min_y,max_x,max_y)
9
+ @min_x = min_x
10
+ @min_y = min_y
11
+ @max_x = max_x
12
+ @max_y = max_y
13
+ end
14
+
15
+ def contains?(x,y)
16
+ x > min_x and x < max_x and y > min_y and y < max_y
17
+ end
18
+
19
+ def to_s
20
+ "(#{min_x},#{min_y}) to (#{max_x},#{max_y})"
21
+ end
22
+
23
+ end
24
+
25
+ Bounds = RectangleBounds
26
+
27
+ end
28
+ end
data/lib/metro/scene.rb CHANGED
@@ -1,4 +1,4 @@
1
- require_relative 'scene_view/scene_view'
1
+ require_relative 'views/scene_view'
2
2
 
3
3
  require_relative 'events/has_events'
4
4
  require_relative 'events/event_relay'
@@ -172,14 +172,16 @@ module Metro
172
172
  # @see #after_initialize
173
173
  #
174
174
  def initialize
175
+ add_actors_to_scene
176
+ after_initialize
177
+ end
178
+
179
+ def add_actors_to_scene
175
180
  self.class.actors.each do |scene_actor|
176
- actor_data = { 'name' => scene_actor.name }.merge (view[scene_actor.name] || {})
177
- actor_instance = scene_actor.create(actor_data)
181
+ actor_instance = scene_actor.create
178
182
  actor_instance.scene = self
179
183
  send "#{scene_actor.name}=", actor_instance
180
184
  end
181
-
182
- after_initialize
183
185
  end
184
186
 
185
187
  #
@@ -259,12 +261,9 @@ module Metro
259
261
  # @example Retrieving the default scene name
260
262
  #
261
263
  # class ExampleScene
262
- # def show
263
- # puts "Showing Scene: #{self.class.scene_name}"
264
- # end
265
264
  # end
266
265
  #
267
- # ExampleScene.scene_name
266
+ # ExampleScene.scene_name # => "example"
268
267
  #
269
268
  # @example Setting a custom name for the Scene
270
269
  #
@@ -272,6 +271,8 @@ module Metro
272
271
  # scene_name "credits"
273
272
  # end
274
273
  #
274
+ # RollingCreditsScene.scene_name # => "credits"
275
+ #
275
276
  # @param [String] scene_name when specified it will set the scene name for the class
276
277
  # to the value specified.
277
278
  #
@@ -280,12 +281,30 @@ module Metro
280
281
  #
281
282
  def self.scene_name(scene_name=nil)
282
283
  @scene_name ||= begin
283
- to_s.gsub(/_?Scene$/i,'').snake_case
284
+ to_s.gsub(/_?Scene$/i,'').underscore
284
285
  end
285
286
 
286
287
  scene_name ? @scene_name = scene_name.to_s : @scene_name
287
288
  end
288
289
 
290
+
291
+ #
292
+ # Allows you to set or retrieve the scene name for the Scene.
293
+ #
294
+ # @example Retrieving the default scene name
295
+ #
296
+ # class ExampleScene
297
+ # def show
298
+ # puts "Showing Scene: #{self.scene_name}" # => Showing Scene: example
299
+ # end
300
+ # end
301
+ #
302
+ # @return the string name of the Scene.
303
+ #
304
+ def scene_name
305
+ self.class.scene_name
306
+ end
307
+
289
308
  #
290
309
  # @return the string representation of a scene, this is used for debugging.
291
310
  #
@@ -299,7 +318,7 @@ module Metro
299
318
  # @see #self.scenes
300
319
  #
301
320
  def self.inherited(base)
302
- scenes << base
321
+ scenes << base.to_s
303
322
  end
304
323
 
305
324
  #
@@ -356,6 +375,7 @@ module Metro
356
375
  def base_update
357
376
  updaters.each { |updater| updater.update }
358
377
  update
378
+ updaters.reject! { |updater| updater.completed? }
359
379
  end
360
380
 
361
381
  #
@@ -476,5 +496,20 @@ module Metro
476
496
  end
477
497
  end
478
498
 
499
+
500
+ #
501
+ # A Scene represented as a hash currently only contains the drawers
502
+ #
503
+ # @return a hash of all the drawers
504
+ #
505
+ def to_hash
506
+ drawn = drawers.find_all{|draw| draw.saveable? }.inject({}) do |hash,drawer|
507
+ drawer_hash = drawer.to_hash
508
+ hash.merge drawer_hash
509
+ end
510
+
511
+ drawn
512
+ end
513
+
479
514
  end
480
515
  end
data/lib/metro/scenes.rb CHANGED
@@ -34,12 +34,12 @@ module Metro
34
34
  #
35
35
  def find(scene_name)
36
36
  found_scene = scenes_hash[scene_name]
37
-
38
- unless found_scene
39
- found_scene = create_missing_scene(scene_name)
37
+
38
+ if found_scene
39
+ found_scene.constantize
40
+ else
41
+ create_missing_scene(scene_name)
40
42
  end
41
-
42
- found_scene
43
43
  end
44
44
 
45
45
  def create_missing_scene(scene_name)
@@ -87,11 +87,12 @@ module Metro
87
87
  # as well as the class name constants to allow for the scenes to be found.
88
88
  #
89
89
  def scenes_hash
90
- @scenes_hash ||= Scene.scenes.inject({}) do |dict,scene|
90
+ @scenes_hash ||= Scene.scenes.inject({}) do |dict,scene_classname|
91
+ scene = scene_classname.constantize
91
92
  name = scene.scene_name
92
- dict[name] = scene
93
- dict[name.to_sym] = scene
94
- dict[scene] = scene
93
+ dict[name] = scene_classname
94
+ dict[name.to_sym] = scene_classname
95
+ dict[scene] = scene_classname
95
96
  dict
96
97
  end
97
98
  end
@@ -0,0 +1,73 @@
1
+ require_relative '../events/hit_list'
2
+
3
+ module Metro
4
+
5
+ class EditTransitionScene < Metro::TransitionScene
6
+
7
+ def initialize
8
+ #
9
+ # The EditTransitionScene needs to have all the drawers
10
+ # cleared from the class because it may still have
11
+ # drawers from other things that this was executed.
12
+ #
13
+ # This is a product of using the classes to store the definitions
14
+ # of scene. This means we need to change this so that it is much
15
+ # easier to dup scenes.
16
+ #
17
+ self.class.drawings.clear
18
+ self.class.draw :overlay, model: "Metro::Models::GridDrawer"
19
+ add_actors_to_scene
20
+ after_initialize
21
+ end
22
+
23
+ def prepare_transition_from(old_scene)
24
+ next_scene.prepare_transition_from(old_scene)
25
+ @previous_scene = old_scene
26
+
27
+ # Set the view name to the previous scene's view name
28
+ self.class.view_name old_scene.view_name
29
+ self.class.view.format = old_scene.class.view.format
30
+
31
+ # import all the actors from the previous scene into the current scene.
32
+ old_scene.class.actors.each do |scene_actor|
33
+ self.class.draw scene_actor.name, scene_actor.options
34
+ end
35
+
36
+ add_actors_to_scene
37
+ end
38
+
39
+ def show
40
+ window.show_cursor
41
+ end
42
+
43
+ event :on_up, KbE do
44
+ transition_to next_scene.scene_name
45
+ end
46
+
47
+ #
48
+ # Generate a hitlist which manages the click start, hold, and release
49
+ # of the mouse button.
50
+ #
51
+ def hitlist
52
+ @hitlist ||= HitList.new(drawers)
53
+ end
54
+
55
+ event :on_down, MsLeft do |event|
56
+ hitlist.hit(event)
57
+ end
58
+
59
+ event :on_hold, MsLeft do |event|
60
+ hitlist.update(event)
61
+ end
62
+
63
+ event :on_up, MsLeft do |event|
64
+ hitlist.release(event)
65
+ end
66
+
67
+ event :on_up, KbS do
68
+ save_view
69
+ end
70
+
71
+ end
72
+
73
+ end