metro 0.3.3 → 0.3.4

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 (40) hide show
  1. data/changelog.md +8 -1
  2. data/lib/core_ext/class.rb +14 -0
  3. data/lib/metro.rb +1 -0
  4. data/lib/metro/events/event_data.rb +3 -4
  5. data/lib/metro/events/event_state_manager.rb +63 -0
  6. data/lib/metro/events/events.rb +3 -0
  7. data/lib/metro/events/hit_list.rb +4 -5
  8. data/lib/metro/events/unknown_sender.rb +1 -1
  9. data/lib/metro/models/model.rb +14 -25
  10. data/lib/metro/models/model_factory.rb +1 -1
  11. data/lib/metro/models/models.rb +62 -0
  12. data/lib/metro/models/properties/position_property.rb +1 -1
  13. data/lib/metro/models/ui/animated_sprite.rb +85 -0
  14. data/lib/metro/models/ui/border.rb +44 -18
  15. data/lib/metro/models/ui/fps.rb +1 -1
  16. data/lib/metro/models/ui/generic.rb +24 -3
  17. data/lib/metro/models/ui/model_label.rb +1 -1
  18. data/lib/metro/models/ui/model_labeler.rb +2 -2
  19. data/lib/metro/models/ui/rectangle.rb +1 -1
  20. data/lib/metro/models/ui/sprite.rb +79 -0
  21. data/lib/metro/models/ui/ui.rb +12 -0
  22. data/lib/metro/scene.rb +13 -61
  23. data/lib/metro/scenes.rb +11 -13
  24. data/lib/metro/transitions/edit_transition_scene.rb +2 -2
  25. data/lib/metro/units/calculation_validations.rb +74 -0
  26. data/lib/metro/units/dimensions.rb +11 -19
  27. data/lib/metro/units/point.rb +6 -22
  28. data/lib/metro/units/rectangle_bounds.rb +10 -6
  29. data/lib/metro/units/scale.rb +7 -0
  30. data/lib/metro/units/units.rb +1 -0
  31. data/lib/metro/version.rb +1 -1
  32. data/lib/metro/window.rb +7 -3
  33. data/lib/setup_handlers/reload_game_on_game_file_changes.rb +6 -6
  34. data/lib/templates/game/models/hero.rb +35 -6
  35. data/lib/templates/model.rb.tt +1 -1
  36. data/spec/core_ext/string_spec.rb +0 -20
  37. data/spec/metro/units/point_spec.rb +132 -0
  38. data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
  39. data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
  40. metadata +21 -9
@@ -1,5 +1,12 @@
1
1
  # Metro
2
2
 
3
+ ## 0.3.4 / 2012-12-14
4
+
5
+ * `metro::ui::sprite` and `metro::ui::animated_sprite` model classes
6
+ to make it easier to take care of all the basic model attributes.
7
+ * Event Management changed in the background. The API remains the
8
+ same.
9
+
3
10
  ## 0.3.3 / 2012-11-28
4
11
 
5
12
  * Edit Mode - actors within a scene can have their position edited
@@ -7,7 +14,7 @@
7
14
  specified will appear within the scene with name and bounding box.
8
15
  * Dimensions can now be defined as strings
9
16
  * Game bounds and Game dimensions return objects of that type
10
- * `metr::ui::fps` added and has some shortcut placements settings
17
+ * `metro::ui::fps` added and has some shortcut placements settings
11
18
 
12
19
  ## 0.3.2 / 2012-11-26
13
20
 
@@ -0,0 +1,14 @@
1
+
2
+ class Class
3
+
4
+ #
5
+ # Within Metro often times a Class or the name of the class is being used.
6
+ # ActiveSupport provides the constantize on Strings and Symbols but does
7
+ # not provide it on Class. So instead of providing redundant checks in
8
+ # places this monkeypatch simply makes Classes adhere to the same interface.
9
+ #
10
+ # @return [Class] itself.
11
+ def constantize
12
+ self
13
+ end
14
+ end
@@ -15,6 +15,7 @@ require 'active_support/hash_with_indifferent_access'
15
15
  require 'gosu_ext/color'
16
16
  require 'gosu_ext/gosu_constants'
17
17
  require 'core_ext/numeric'
18
+ require 'core_ext/class'
18
19
 
19
20
  require 'locale/locale'
20
21
 
@@ -1,12 +1,11 @@
1
1
  module Metro
2
2
  class EventData
3
3
 
4
- attr_reader :mouse_x, :mouse_y, :created_at
4
+ attr_reader :mouse_point, :created_at
5
5
 
6
6
  def initialize(window)
7
7
  @created_at = Time.now
8
- @mouse_x = window.mouse_x
9
- @mouse_y = window.mouse_y
8
+ @mouse_point = Metro::Units::Point.at window.mouse_x, window.mouse_y
10
9
 
11
10
  capture_modifier_keys(window)
12
11
  end
@@ -23,7 +22,7 @@ module Metro
23
22
 
24
23
  #
25
24
  # TODO: This attempt to reduce duplication is brittle and will likely end in heartache.
26
- #
25
+ #
27
26
 
28
27
  def self.modifier_key_list_names
29
28
  @modifier_key_list_names ||= %w[ KbLeftControl KbRightControl
@@ -0,0 +1,63 @@
1
+ require_relative 'event_relay'
2
+
3
+ module Metro
4
+
5
+ class EventStateManager
6
+ def initialize
7
+ @current_state = []
8
+ end
9
+
10
+ attr_accessor :window
11
+
12
+ attr_reader :current_state
13
+
14
+ #
15
+ # Clear all the event relays of the current game state
16
+ #
17
+ def clear
18
+ current_state.clear
19
+ end
20
+
21
+ #
22
+ # Fire events for held buttons within the current game state
23
+ #
24
+ def fire_events_for_held_buttons
25
+ current_state.each {|cs| cs.fire_events_for_held_buttons }
26
+ end
27
+
28
+ #
29
+ # Fire events for button up for the current game state
30
+ #
31
+ def fire_button_up(id)
32
+ current_state.each {|cs| cs.fire_button_up(id) }
33
+ end
34
+
35
+ #
36
+ # Fire events for button down within the current game state
37
+ #
38
+ def fire_button_down(id)
39
+ current_state.each {|cs| cs.fire_button_down(id) }
40
+ end
41
+
42
+ #
43
+ # Fire notification events within the current game state
44
+ #
45
+ def fire_events_for_notification(event,sender)
46
+ current_state.each {|cs| cs.fire_events_for_notification(event,sender) }
47
+ end
48
+
49
+ #
50
+ # An an event relay to the current game state
51
+ #
52
+ def add_events_for_target(target,events)
53
+ relay = EventRelay.new(target,window)
54
+
55
+ events.each do |target_event|
56
+ relay.send target_event.event, *target_event.buttons, &target_event.block
57
+ end
58
+
59
+ current_state.push relay
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'has_events'
2
+ require_relative 'event_state_manager'
3
+ require_relative 'unknown_sender'
@@ -10,7 +10,6 @@ module Metro
10
10
  # hit_list.update(next_event)
11
11
  # hit_list.release(last_event)
12
12
  #
13
- #
14
13
  # @see EditTransitionScene
15
14
  #
16
15
  class HitList
@@ -22,7 +21,7 @@ module Metro
22
21
  attr_reader :drawers
23
22
 
24
23
  def hit(event)
25
- add drawers_at(event.mouse_x,event.mouse_y)
24
+ add drawers_at(event.mouse_point)
26
25
  save_event event
27
26
  end
28
27
 
@@ -41,8 +40,8 @@ module Metro
41
40
  clear
42
41
  end
43
42
 
44
- def drawers_at(x,y)
45
- hit_drawers = drawers.find_all { |drawer| drawer.bounds.contains?(x,y) }
43
+ def drawers_at(point)
44
+ hit_drawers = drawers.find_all { |drawer| drawer.bounds.contains?(point) }
46
45
 
47
46
  # assumed that we only want one item
48
47
  top_drawer = hit_drawers.inject(hit_drawers.first) {|top,drawer| drawer.z_order > top.z_order ? drawer : top }
@@ -51,7 +50,7 @@ module Metro
51
50
 
52
51
  def offset_from_last_event(event)
53
52
  return Point.zero unless @last_event
54
- Metro::Units::Point.at (event.mouse_x - @last_event.mouse_x).to_i, (event.mouse_y - @last_event.mouse_y).to_i
53
+ event.mouse_point - @last_event.mouse_point
55
54
  end
56
55
 
57
56
  def save_event(event)
@@ -1,5 +1,5 @@
1
1
  module Metro
2
2
  class UnknownSender
3
-
3
+
4
4
  end
5
5
  end
@@ -1,5 +1,6 @@
1
1
  require_relative 'key_value_coding'
2
2
  require_relative 'properties/property'
3
+ require_relative 'models'
3
4
 
4
5
  module Metro
5
6
 
@@ -64,6 +65,11 @@ module Metro
64
65
  #
65
66
  def draw ; end
66
67
 
68
+ def self.model_name(model_name=nil)
69
+ @model_name ||= to_s.underscore
70
+ model_name ? @model_name = model_name.to_s : @model_name
71
+ end
72
+
67
73
  #
68
74
  # @return [String] the name of the model class.
69
75
  #
@@ -129,7 +135,7 @@ module Metro
129
135
  #
130
136
  def create(model_name,options={})
131
137
  # @TODO: this is another path that parallels the ModelFactory
132
- model_class = Metro::Model.model(model_name).constantize
138
+ model_class = Metro::Models.find(model_name)
133
139
  mc = model_class.new options
134
140
  mc.scene = scene
135
141
  mc.window = window
@@ -211,37 +217,20 @@ module Metro
211
217
  #
212
218
  # Captures all classes that subclass Model.
213
219
  #
214
- # @see #self.models_hash
215
- #
216
- def self.inherited(model)
217
- models_hash[model.to_s] = model.to_s
218
- models_hash[model.to_s.downcase] = model.to_s
219
- models_hash[model.to_s.underscore] = model.to_s
220
+ def self.inherited(base)
221
+ models << base.to_s
222
+ Models.add(base)
220
223
  end
221
224
 
222
225
  #
223
- # Convert the specified model name into the class of the model.
226
+ # All subclasses of Model, this should be all the defined
224
227
  #
225
- # @return the Model class given the specified model name.
226
- def self.model(name)
227
- models_hash[name]
228
- end
229
-
230
- def self.models_hash
231
- @models_hash ||= HashWithIndifferentAccess.new("Metro::UI::Generic")
228
+ def self.models
229
+ @models ||= []
232
230
  end
233
231
 
234
232
  end
235
233
  end
236
234
 
237
- require_relative 'ui/generic'
238
- require_relative 'ui/label'
239
- require_relative 'ui/menu'
240
- require_relative 'ui/image'
241
- require_relative 'ui/rectangle'
242
- require_relative 'ui/grid_drawer'
243
- require_relative 'ui/border'
244
- require_relative 'ui/model_label'
245
- require_relative 'ui/model_labeler'
246
- require_relative 'ui/fps'
235
+ require_relative 'ui/ui'
247
236
  require_relative 'audio/song'
@@ -26,7 +26,7 @@ module Metro
26
26
  end
27
27
 
28
28
  def class_for_actor(model_name)
29
- Model.model(model_name).constantize
29
+ Models.find(model_name)
30
30
  end
31
31
  end
32
32
  end
@@ -0,0 +1,62 @@
1
+ module Metro
2
+
3
+
4
+ module Models
5
+ extend self
6
+
7
+ #
8
+ # Add a model, and all it's subclasses, to the list of available models.
9
+ #
10
+ # A model has several names added so that it accessible in many ways:
11
+ #
12
+ # * Model Class Name
13
+ # * Model Name
14
+ # * Model Name with slashes replaced with `::` separator
15
+ #
16
+ def add(model)
17
+ all_models_for(model).each do |model|
18
+ models_hash[model.to_s] = model.to_s
19
+ name_with_slashes = model.model_name
20
+ models_hash[name_with_slashes] = model.to_s
21
+ name_with_colons = name_with_slashes.gsub('/','::')
22
+ models_hash[name_with_colons] = model.to_s
23
+ end
24
+ end
25
+
26
+ #
27
+ # @param [String] name the name of the model that you want to return.
28
+ #
29
+ # @return [String] the name of the model class
30
+ #
31
+ def find(name)
32
+ models_hash[name].constantize
33
+ end
34
+
35
+ #
36
+ # @return [Array<String>] all the names supported by the models hash.
37
+ #
38
+ def list
39
+ models_hash.keys
40
+ end
41
+
42
+ #
43
+ # @return [Hash] a hash of the available models. The keys are the various
44
+ # supported names, with the values being the names of the model classes.
45
+ def models_hash
46
+ @models_hash ||= HashWithIndifferentAccess.new("Metro::UI::Generic")
47
+ end
48
+
49
+ #
50
+ # @param [Class,Array<Class>] models a model or array of models.
51
+ # @return [Array] an array that contains the model itself and all of the
52
+ # models that are sub-classes of this model on down.
53
+ #
54
+ def all_models_for(models)
55
+ Array(models).map do |model_class_name|
56
+ model = model_class_name.constantize
57
+ [ model ] + all_models_for(models.models)
58
+ end.flatten.compact
59
+ end
60
+
61
+ end
62
+ end
@@ -81,7 +81,7 @@ module Metro
81
81
  end
82
82
 
83
83
  def default_point
84
- (options[:default] and options[:default].is_a? Point) ? options[:default] : Point.zero
84
+ Point.parse(options[:default])
85
85
  end
86
86
 
87
87
  end
@@ -0,0 +1,85 @@
1
+ module Metro
2
+ module UI
3
+
4
+ #
5
+ # A sprite is a Metro model that is specially designed to draw and manage
6
+ # an animation. A sprite maintains an animation, location information, and
7
+ # rotation.
8
+ #
9
+ class AnimatedSprite < Model
10
+
11
+ # @attribute
12
+ # The animation that will be drawn for the sprite
13
+ property :animation
14
+
15
+ # @attribute
16
+ # The point at which the sprite should be drawn
17
+ property :position
18
+
19
+ # @attribute
20
+ # This is the color of the spirte. The color usually remains white, and
21
+ # the color property is implemented by the `alpha` value is the one thing
22
+ # that is altered to fade in and fade out the sprite.
23
+ property :color
24
+
25
+ # @attribute
26
+ # The scale at which to draw the sprite. This is default scale of 1.
27
+ property :scale
28
+
29
+ # @attribute
30
+ # The center, horizontal position, as expressed in a ratio, of the image.
31
+ property :center_x, type: :numeric, default: 0.0
32
+
33
+ # @attribute
34
+ # The center, vertical position, as expressed in a ratio, of the image.
35
+ property :center_y, type: :numeric, default: 0.0
36
+
37
+ # @attribute
38
+ # The angle at which the sprite should be drawn. This is by default 0.
39
+ property :angle
40
+
41
+ # @attribute
42
+ # The height and width of the sprite is based on the image of the sprite.
43
+ property :dimensions do
44
+ Dimensions.of current_image.width, current_image.height
45
+ end
46
+
47
+ # @return [RectangleBounds] the bounds of the sprite.
48
+ def bounds
49
+ Bounds.new left: left, right: right, top: top, bottom: bottom
50
+ end
51
+
52
+ # @return [Float] the left-most x position of the sprite
53
+ def left
54
+ x - width * center_x
55
+ end
56
+
57
+ # @return [Float] the right-most x position of the sprite
58
+ def right
59
+ left + width * x_factor
60
+ end
61
+
62
+ # @return [Float] the top-most y position of the sprite
63
+ def top
64
+ y - height * center_y
65
+ end
66
+
67
+ # @return [Float] the bottom-most y position of the sprite
68
+ def bottom
69
+ top + height * y_factor
70
+ end
71
+
72
+ # @return [Gosu::Image] the current image in the animation sequence.
73
+ def current_image
74
+ animation.image
75
+ end
76
+
77
+ #
78
+ # By default the sprite will draw the current image of the animation.
79
+ #
80
+ def draw
81
+ current_image.draw_rot x, y, z_order, angle, center_x, center_y, x_factor, y_factor, color
82
+ end
83
+ end
84
+ end
85
+ end
@@ -5,7 +5,7 @@ module Metro
5
5
  # Draws a rectanglar border around the specififed position and dimensions
6
6
  # with the width provided. This is an unfilled rectangle.
7
7
  #
8
- class Border < Metro::Model
8
+ class Border < Model
9
9
 
10
10
  # @attribute
11
11
  # The starting position of the border.
@@ -35,32 +35,58 @@ module Metro
35
35
  end
36
36
 
37
37
  def draw_top
38
- window.draw_quad(x + border,y,color,
39
- width + x,y,color,
40
- x + width,y + border,color,
41
- x + border,y + border,color,z_order)
38
+ draw_line left_with_border, top, right, top_with_border
42
39
  end
43
40
 
44
41
  def draw_left
45
- window.draw_quad(x,y,color,
46
- border + x,y,color,
47
- x + border,y + border + height,color,
48
- x,y + border + height,color,z_order)
42
+ draw_line left, top, left_with_border, bottom_with_border
49
43
  end
50
44
 
51
45
  def draw_right
52
- window.draw_quad(x + width,y,color,
53
- x + width + border,y,color,
54
- x + width + border,y + border + height,color,
55
- x + width,y + border + height,color,z_order)
56
-
46
+ draw_line right, top, right_with_border, bottom_with_border
57
47
  end
58
48
 
59
49
  def draw_bottom
60
- window.draw_quad(x + border,y + height,color,
61
- width + x,y + height,color,
62
- x + width,y + border + height,color,
63
- x + border,y + border + height,color,z_order)
50
+ draw_line left_with_border, bottom, right,bottom_with_border
51
+ end
52
+
53
+ def draw_line(start_x,start_y,finish_x,finish_y)
54
+ window.draw_quad start_x, start_y, color,
55
+ finish_x, start_y, color,
56
+ finish_x, finish_y, color,
57
+ start_x, finish_y, color, z_order
58
+ end
59
+
60
+ def left
61
+ x
62
+ end
63
+
64
+ def left_with_border
65
+ x + border
66
+ end
67
+
68
+ def right
69
+ x + width
70
+ end
71
+
72
+ def right_with_border
73
+ right + border
74
+ end
75
+
76
+ def top
77
+ y
78
+ end
79
+
80
+ def top_with_border
81
+ top + border
82
+ end
83
+
84
+ def bottom
85
+ y + height
86
+ end
87
+
88
+ def bottom_with_border
89
+ bottom + border
64
90
  end
65
91
 
66
92
  end