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,7 +1,7 @@
1
1
  module Metro
2
2
  module UI
3
3
 
4
- class FPS < Metro::Model
4
+ class FPS < Model
5
5
 
6
6
  property :placement, type: :text, default: 'top'
7
7
  property :color, default: "rgba(255,255,255,1.0)"
@@ -35,9 +35,30 @@ module Metro
35
35
  private
36
36
 
37
37
  def cannot_draw_message
38
- [ "Unable to draw #{name} in #{scene}", "",
39
- " The actor named '#{name}' does not specify a suitable model so it could not be drawn in the scene.",
40
- "", " " + properties.to_s, "" ].join("\n")
38
+ %{Unable to draw #{name} in #{scene}
39
+
40
+ The actor named '#{name}' does not specify a suitable model so it could not be drawn in the scene.
41
+
42
+ #{properties}
43
+
44
+ Did you mean to use one of the following models:
45
+
46
+ Models defined in #{Game.name}:
47
+
48
+ #{user_defined_models.join(', ')}
49
+
50
+ Models defined in Metro:
51
+
52
+ #{metro_models.join(', ')}
53
+ }
54
+ end
55
+
56
+ def metro_models
57
+ Models.list.find_all {|m| m =~ /metro(::|\/).+(::|\/).+/i }
58
+ end
59
+
60
+ def user_defined_models
61
+ Models.list - metro_models
41
62
  end
42
63
 
43
64
  end
@@ -7,7 +7,7 @@ module Metro
7
7
  # The model label is used by the model labeler which is a facet of the
8
8
  # edit scene
9
9
  #
10
- class ModelLabel < Metro::Model
10
+ class ModelLabel < Model
11
11
 
12
12
  # Stores the model that is currently being labeled.
13
13
  attr_accessor :target
@@ -9,7 +9,7 @@ module Metro
9
9
  # the bounding boxes and labeles around all the actors within the scene
10
10
  # being edited.
11
11
  #
12
- class ModelLabeler < Metro::Model
12
+ class ModelLabeler < Model
13
13
 
14
14
  # @attribute
15
15
  # The color use for the border surrounding each actor and the background
@@ -58,7 +58,7 @@ module Metro
58
58
  label = labels[drawer.name]
59
59
 
60
60
  unless label
61
- label = create "metro::ui::modellabel", target: drawer
61
+ label = create "metro::ui::model_label", target: drawer
62
62
  labels[drawer.name] = label
63
63
  end
64
64
 
@@ -12,7 +12,7 @@ module Metro
12
12
  # color: "rgba(255,0,0,1.0)", dimensions: "200,200"
13
13
  # end
14
14
  #
15
- class Rectangle < ::Metro::Model
15
+ class Rectangle < Model
16
16
 
17
17
  # @attribute
18
18
  # The position of the upper-left corner of the rectangle
@@ -0,0 +1,79 @@
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 image. A sprite maintains an image, location information, and rotation.
7
+ #
8
+ class Sprite < Model
9
+
10
+ # @attribute
11
+ # The image that will be drawn for the sprite
12
+ property :image
13
+
14
+ # @attribute
15
+ # The point at which the sprite should be drawn
16
+ property :position
17
+
18
+ # @attribute
19
+ # This is the color of the spirte. The color usually remains white, and
20
+ # the color property is implemented by the `alpha` value is the one thing
21
+ # that is altered to fade in and fade out the sprite.
22
+ property :color
23
+
24
+ # @attribute
25
+ # The scale at which to draw the sprite. This is default scale of 1.
26
+ property :scale
27
+
28
+ # @attribute
29
+ # The center, horizontal position, as expressed in a ratio, of the image.
30
+ property :center_x, type: :numeric, default: 0.5
31
+
32
+ # @attribute
33
+ # The center, vertical position, as expressed in a ratio, of the image.
34
+ property :center_y, type: :numeric, default: 0.5
35
+
36
+ # @attribute
37
+ # The angle at which the sprite should be drawn. This is by default 0.
38
+ property :angle
39
+
40
+ # @attribute
41
+ # The height and width of the sprite is based on the image of the sprite.
42
+ property :dimensions do
43
+ image.dimensions
44
+ end
45
+
46
+ # @return [RectangleBounds] the bounds of the sprite.
47
+ def bounds
48
+ Bounds.new left: left, right: right, top: top, bottom: bottom
49
+ end
50
+
51
+ # @return [Float] the left-most x position of the sprite
52
+ def left
53
+ x - width * center_x
54
+ end
55
+
56
+ # @return [Float] the right-most x position of the sprite
57
+ def right
58
+ left + width * x_factor
59
+ end
60
+
61
+ # @return [Float] the top-most y position of the sprite
62
+ def top
63
+ y - height * center_y
64
+ end
65
+
66
+ # @return [Float] the bottom-most y position of the sprite
67
+ def bottom
68
+ top + height * y_factor
69
+ end
70
+
71
+ #
72
+ # By default the sprite will draw the image defined for it.
73
+ #
74
+ def draw
75
+ image.draw_rot x, y, z_order, angle, center_x, center_y, x_factor, y_factor, color
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'generic'
2
+ require_relative 'label'
3
+ require_relative 'menu'
4
+ require_relative 'image'
5
+ require_relative 'rectangle'
6
+ require_relative 'grid_drawer'
7
+ require_relative 'border'
8
+ require_relative 'model_label'
9
+ require_relative 'model_labeler'
10
+ require_relative 'fps'
11
+ require_relative 'sprite'
12
+ require_relative 'animated_sprite'
@@ -1,9 +1,5 @@
1
1
  require_relative 'views/scene_view'
2
-
3
- require_relative 'events/has_events'
4
- require_relative 'events/event_relay'
5
- require_relative 'events/unknown_sender'
6
-
2
+ require_relative 'events/events'
7
3
  require_relative 'models/draws'
8
4
 
9
5
  require_relative 'animation/has_animations'
@@ -19,7 +15,6 @@ module Metro
19
15
  # @see #show
20
16
  # @see #update
21
17
  # @see #draw
22
- # @see #events
23
18
  #
24
19
  # A fair number of private methods within Scene are prefaced with an underscore.
25
20
  # These methods often call non-underscored methods within those methods. This allows
@@ -102,16 +97,12 @@ module Metro
102
97
  end
103
98
 
104
99
  #
105
- # Post a custom notification event. This will trigger any objects that are listening
106
- # for custom events.
100
+ # Post a custom notification event. This will trigger an event for all the
101
+ # objects that are registered for notification with the current state.
107
102
  #
108
103
  def notification(event,sender=nil)
109
-
110
104
  sender = sender || UnknownSender
111
-
112
- event_relays.each do |relay|
113
- relay.fire_events_for_notification(event,sender)
114
- end
105
+ state.fire_events_for_notification(event,sender)
115
106
  end
116
107
 
117
108
  #
@@ -203,7 +194,8 @@ module Metro
203
194
  def window=(window)
204
195
  @window = window
205
196
 
206
- event_relays.clear
197
+ state.window = window
198
+ state.clear
207
199
 
208
200
  register_events!
209
201
  register_actors!
@@ -335,11 +327,9 @@ module Metro
335
327
  #
336
328
  # Captures all classes that subclass Scene.
337
329
  #
338
- # @see #self.scenes
339
- #
340
330
  def self.inherited(base)
341
331
  scenes << base.to_s
342
- Scenes.add_scene(base)
332
+ Scenes.add(base)
343
333
  end
344
334
 
345
335
  #
@@ -455,58 +445,20 @@ module Metro
455
445
  # be mapped to the specified target.
456
446
  #
457
447
  def register_events_for_target(target,events)
458
- target_relay = EventRelay.new(target,window)
459
-
460
- events.each do |target_event|
461
- target_relay.send target_event.event, *target_event.buttons, &target_event.block
462
- end
463
-
464
- event_relays.push(target_relay)
448
+ state.add_events_for_target(target,events)
465
449
  end
466
450
 
467
451
  #
468
- # The events object that is configured through the {#events} method, which stores
469
- # all the gamepad and keyboard events defined. By default a scene has an event
470
- # relay defined. Additional relays can be defined based on the components added.
452
+ # The event state manager is configured through the {#events} method, which
453
+ # stores all the gamepad and keyboard events defined. By default a scene is
454
+ # placed in the default state and events that are added to this basic state.
471
455
  #
472
456
  # @see Events
473
- # @see #add_event_relay
474
457
  #
475
- def event_relays
476
- @event_relays ||= []
458
+ def state
459
+ @event_state_manager ||= EventStateManager.new
477
460
  end
478
461
 
479
- #
480
- # This method is called during a scene update and will fire all the events
481
- # that have been defined for all held buttons for all defined event relays.
482
- #
483
- def fire_events_for_held_buttons
484
- event_relays.each do |relay|
485
- relay.fire_events_for_held_buttons
486
- end
487
- end
488
-
489
- #
490
- # This method is called before a scene update and passes the button up events
491
- # to each of the defined event relays.
492
- #
493
- def button_up(id)
494
- event_relays.each do |relay|
495
- relay.fire_button_up(id)
496
- end
497
- end
498
-
499
- #
500
- # This method is called before a scene update and passes the button down events
501
- # to each of the defined event relays.
502
- #
503
- def button_down(id)
504
- event_relays.each do |relay|
505
- relay.fire_button_down(id)
506
- end
507
- end
508
-
509
-
510
462
  #
511
463
  # A Scene represented as a hash currently only contains the drawers
512
464
  #
@@ -33,7 +33,7 @@ module Metro
33
33
  #
34
34
  # @param [Scene] scene the scene to be added to the hash of Scenes.
35
35
  #
36
- def add_scene(scene)
36
+ def add(scene)
37
37
  all_scenes_for(scene).each { |scene| scenes_hash[scene.scene_name] = scene.to_s }
38
38
  end
39
39
 
@@ -44,7 +44,14 @@ module Metro
44
44
  # @return the Scene class that is found matching the specified scene name.
45
45
  #
46
46
  def find(scene_name)
47
- scene_class( scenes_hash[scene_name] )
47
+ scenes_hash[scene_name].constantize
48
+ end
49
+
50
+ #
51
+ # @return [Array<String>] all the names supported by the scenes hash.
52
+ #
53
+ def list
54
+ scenes_hash.keys
48
55
  end
49
56
 
50
57
  #
@@ -119,7 +126,7 @@ module Metro
119
126
  #
120
127
  def hash_with_missing_scene_default
121
128
  hash = HashWithIndifferentAccess.new do |hash,key|
122
- missing_scene = scene_class(hash[:missing_scene])
129
+ missing_scene = hash[:missing_scene].constantize
123
130
  missing_scene.missing_scene = key.to_sym
124
131
  missing_scene
125
132
  end
@@ -136,20 +143,11 @@ module Metro
136
143
  #
137
144
  def all_scenes_for(scenes)
138
145
  Array(scenes).map do |scene_class_name|
139
- scene = scene_class(scene_class_name)
146
+ scene = scene_class_name.constantize
140
147
  [ scene ] + all_scenes_for(scene.scenes)
141
148
  end.flatten.compact
142
149
  end
143
150
 
144
- #
145
- # @param [String,Symbol] class_name the name of the class that you want the class
146
- #
147
- # @return the class with the given class name
148
- #
149
- def scene_class(class_or_class_name)
150
- class_or_class_name.class == Class ? class_or_class_name : class_or_class_name.constantize
151
- end
152
-
153
151
  end
154
152
  end
155
153
 
@@ -28,8 +28,8 @@ module Metro
28
28
  # easier to dup scenes.
29
29
  #
30
30
  self.class.drawings.clear
31
- self.class.draw :overlay, model: "metro::ui::griddrawer"
32
- self.class.draw :labeler, model: "metro::ui::modellabeler"
31
+ self.class.draw :overlay, model: "metro::ui::grid_drawer"
32
+ self.class.draw :labeler, model: "metro::ui::model_labeler"
33
33
  add_actors_to_scene
34
34
  after_initialize
35
35
  end
@@ -0,0 +1,74 @@
1
+ module Metro
2
+ module Units
3
+ module CalculationValidations
4
+
5
+ #
6
+ # @param [Object] value the other object that needs to be validated.
7
+ #
8
+ def check_calculation_requirements(value)
9
+ if calculation_requirements.find { |method| ! value.respond_to?(method) }
10
+ raise "Unable to perform operation with #{value} #{value.class} It is missing a property #{calculation_requirements.join(",")}"
11
+ end
12
+ end
13
+
14
+ #
15
+ # @return [Array] an array of methods that are required to be on the
16
+ # object for it to be correctly calculated.
17
+ #
18
+ # @note this method is intended to be defined in the including class. This
19
+ # method is included here when one has not been provided.
20
+ def calculation_requirements
21
+ []
22
+ end
23
+
24
+ #
25
+ # Add this object to another object.
26
+ #
27
+ # @return a new object that is the sum of the two objects
28
+ #
29
+ def +(value)
30
+ self.class.new *calculate(value,:+)
31
+ end
32
+
33
+ #
34
+ # Subtract the other object from this object.
35
+ #
36
+ # @return a new object that is the difference of the original object
37
+ # and the value specified.
38
+ #
39
+ def -(value)
40
+ self.class.new *calculate(value,:-)
41
+ end
42
+
43
+ #
44
+ # Multiply this object and another object.
45
+ #
46
+ # @return a new object that is the product of the two objects.
47
+ #
48
+ def *(value)
49
+ self.class.new *calculate(value,:*)
50
+ end
51
+
52
+ #
53
+ # This generic method will perform the calculation defined by the
54
+ # operation for all the calculation requirements defined.
55
+ #
56
+ # @param [value] value this is the other value that is being added,
57
+ # subtracted, etc. to the current object.
58
+ # @param [Symbol] operation this is the mathematical operation that
59
+ # is being performed between all the calc requirements of the current
60
+ # object and other value.
61
+ #
62
+ # @return [Array] an array of reults from the calculations of all the
63
+ # requirements.
64
+ #
65
+ def calculate(value,operation)
66
+ check_calculation_requirements(value)
67
+ calculation_requirements.map do |requirement|
68
+ send(requirement).send(operation,value.send(requirement))
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -5,6 +5,7 @@ module Metro
5
5
  # Represents an object that contains both the width and height.
6
6
  #
7
7
  class Dimensions < Struct.new(:width,:height)
8
+ include CalculationValidations
8
9
 
9
10
  #
10
11
  # Create a dimensions objects with zero width and zero height.
@@ -37,30 +38,21 @@ module Metro
37
38
  end
38
39
 
39
40
  #
40
- # Add the dimensions to another dimensions-like structure. A
41
- # dimensions like structure is anything that responds to width and height.
41
+ # Compare the dimension to another dimensions-like structure.
42
42
  #
43
- # @return a new dimensions which is the sum of the two dimensions
43
+ # @return [Fixnum] -1 if the dimensions is smaller than the other dimension,
44
+ # 0 if the dimensions are exactly the same, 1 if the dimensions are bigger
45
+ # then the other dimensions.
44
46
  #
45
- def +(value)
46
- raise "Unable to add dimension to #{value} #{value.class}" if [ :width, :height ].find { |method| ! value.respond_to?(method) }
47
- self.class.of (width + value.width.to_f), (height + value.height.to_f)
47
+ def <=>(value)
48
+ check_calculation_requirements(value)
49
+ (width * height) <=> (value.width * value.height)
48
50
  end
49
51
 
50
- #
51
- # Subtract the dimensions-like structure from this dimension. A
52
- # dimensions like structure is anything that responds to width and height.
53
- #
54
- # @return a new dimensions which is the different of the two dimensions
55
- #
56
- def -(value)
57
- raise "Unable to subtract from these dimensions with #{value} #{value.class}" if [ :width, :height ].find { |method| ! value.respond_to?(method) }
58
- self.class.of (width - value.width.to_f), (height - value.height.to_f)
59
- end
52
+ private
60
53
 
61
- def <=>(value)
62
- raise "Unable to subtract from these dimensions with #{value} #{value.class}" if [ :width, :height ].find { |method| ! value.respond_to?(method) }
63
- (width * height) <=> (value.width * value.height)
54
+ def calculation_requirements
55
+ [ :width, :height ]
64
56
  end
65
57
 
66
58
  end