metro 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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