metro 0.1.5 → 0.1.6

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 (63) hide show
  1. data/README.md +19 -0
  2. data/changelog.md +8 -0
  3. data/lib/assets/missing_animation.png +0 -0
  4. data/lib/commands/generate_model.rb +2 -2
  5. data/lib/commands/generate_scene.rb +12 -2
  6. data/lib/commands/generate_view.rb +1 -1
  7. data/lib/gosu_ext/color.rb +1 -1
  8. data/lib/gosu_ext/image.rb +5 -0
  9. data/lib/metro.rb +18 -5
  10. data/lib/metro/animation/animation.rb +31 -0
  11. data/lib/metro/asset_path.rb +9 -0
  12. data/lib/metro/events/event_dictionary.rb +53 -0
  13. data/lib/metro/events/event_factory.rb +5 -3
  14. data/lib/metro/events/has_events.rb +5 -6
  15. data/lib/metro/game.rb +1 -1
  16. data/lib/metro/models/dimensions.rb +21 -0
  17. data/lib/metro/models/model.rb +149 -52
  18. data/lib/metro/models/model_factory.rb +4 -5
  19. data/lib/metro/models/{generic.rb → models/generic.rb} +0 -0
  20. data/lib/metro/models/{grid_drawer.rb → models/grid_drawer.rb} +4 -9
  21. data/lib/metro/models/{image.rb → models/image.rb} +11 -14
  22. data/lib/metro/models/models/label.rb +44 -0
  23. data/lib/metro/models/{menu.rb → models/menu.rb} +23 -18
  24. data/lib/metro/models/{rectangle.rb → models/rectangle.rb} +6 -5
  25. data/lib/metro/models/point.rb +23 -0
  26. data/lib/metro/models/properties/angle.rb +43 -0
  27. data/lib/metro/models/properties/animation.rb +143 -0
  28. data/lib/metro/models/properties/color.rb +113 -0
  29. data/lib/metro/models/properties/dimensions.rb +66 -0
  30. data/lib/metro/models/properties/font.rb +155 -0
  31. data/lib/metro/models/properties/image.rb +101 -0
  32. data/lib/metro/models/properties/numeric.rb +29 -0
  33. data/lib/metro/models/properties/position.rb +84 -0
  34. data/lib/metro/models/properties/property.rb +111 -0
  35. data/lib/metro/models/properties/scale.rb +89 -0
  36. data/lib/metro/models/properties/text.rb +66 -0
  37. data/lib/metro/models/properties/velocity.rb +80 -0
  38. data/lib/metro/models/scale.rb +21 -0
  39. data/lib/metro/scene.rb +19 -1
  40. data/lib/metro/scenes.rb +91 -31
  41. data/lib/metro/transitions/scene_transitions.rb +8 -0
  42. data/lib/metro/version.rb +1 -1
  43. data/lib/metro/views/view.rb +9 -1
  44. data/lib/templates/game/metro.tt +1 -1
  45. data/lib/templates/game/models/game_model.rb +3 -0
  46. data/lib/templates/game/scenes/brand_scene.rb +1 -1
  47. data/lib/templates/game/scenes/brand_to_title_scene.rb +1 -1
  48. data/lib/templates/game/scenes/game_scene.rb +19 -0
  49. data/lib/templates/game/scenes/title_scene.rb +1 -1
  50. data/lib/templates/game/views/brand_to_title.yaml +2 -2
  51. data/lib/templates/game/views/title.yaml +3 -3
  52. data/lib/templates/{model.rb.erb → model.rb.tt} +1 -1
  53. data/lib/templates/{scene.rb.erb → scene.rb.tt} +1 -1
  54. data/lib/templates/view.yaml.tt +6 -0
  55. data/spec/metro/models/models/label_spec.rb +110 -0
  56. data/spec/metro/models/properties/color_spec.rb +85 -0
  57. data/spec/metro/models/properties/font_spec.rb +129 -0
  58. data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
  59. data/spec/metro/models/properties/position_property_spec.rb +90 -0
  60. data/spec/metro/scenes_spec.rb +77 -0
  61. metadata +50 -16
  62. data/lib/metro/models/label.rb +0 -63
  63. data/lib/templates/view.yaml.erb +0 -32
@@ -0,0 +1,66 @@
1
+ module Metro
2
+ class Model
3
+
4
+ #
5
+ # A dimensions property maintains an width and height.
6
+ #
7
+ # A dimensions property also defines a `width` property and a `height`
8
+ # property which allows a more direct interface. Changing these values
9
+ # will update the dimensions the next time that it is drawn.
10
+ #
11
+ # Dimensions is stored in the properties as a string and is converted into
12
+ # a Dimensions when it is retrieved within the system. When retrieving the dimensions.
13
+ #
14
+ # @example Defining a dimensions property
15
+ #
16
+ # class Hero < Metro::Model
17
+ # property :dimensions
18
+ # end
19
+ #
20
+ # @example Defining a dimensions providing a default
21
+ #
22
+ # class Hero < Metro::Model
23
+ # property :dimensions, default: Dimensions.of 100.0, 100.0
24
+ # end
25
+ #
26
+ # @example Using a dimensions property with a different property name
27
+ #
28
+ # class Hero < Metro::Model
29
+ # property :box, type: dimensions, default: Dimensions.of 100.0, 100.0
30
+ # # box_width, box_height
31
+ # end
32
+ #
33
+ class DimensionsProperty < Property
34
+
35
+ define_property :width
36
+
37
+ define_property :height
38
+
39
+ get do |value|
40
+ default_dimensions
41
+ end
42
+
43
+ get String do |value|
44
+ Dimensions.parse(value)
45
+ end
46
+
47
+ set do |value|
48
+ default_dimensions.to_s
49
+ end
50
+
51
+ set String do |value|
52
+ value
53
+ end
54
+
55
+ set Dimensions do |value|
56
+ value.to_s
57
+ end
58
+
59
+ def default_dimensions
60
+ (options[:default] and options[:default].is_a? Dimensions) ? options[:default] : Dimensions.none
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,155 @@
1
+ require_relative 'text'
2
+
3
+ module Metro
4
+ class Model
5
+
6
+ #
7
+ # A font property maintains a Gosu::Font.
8
+ #
9
+ # A font property also defines a `font_size` property and a `font_name` property which allows a
10
+ # more direct interface. Changing these values will update the font the next time that it is drawn.
11
+ #
12
+ # A font is stored in the properties as a hash representation and is converted into
13
+ # a Gosu::Font when it is retrieved within the system. When retrieving a font the Font
14
+ # Property will attempt to use a font that already exists that meets that criteria.
15
+ #
16
+ # The fonts are cached within the font property to help performance by reducing the unncessary
17
+ # creation of similar fonts.
18
+ #
19
+ # @example Defining a font property
20
+ #
21
+ # class Scoreboard < Metro::Model
22
+ # property :font
23
+ #
24
+ # def draw
25
+ # font.draw text, x, y, z_order, x_factor, y_factor, color
26
+ # end
27
+ #
28
+ # end
29
+ #
30
+ # @example Defining a font property providing a default
31
+ #
32
+ # class Hero < Metro::Model
33
+ # property :font, default: { name: 'Comic Sans', size: 80 }
34
+ # end
35
+ #
36
+ # @example Using the `font_size` and `font_name` properties
37
+ #
38
+ # class Hero < Metro::Model
39
+ # property :color, default: "rgba(255,0,0,1.0)"
40
+ #
41
+ # def dignified
42
+ # self.font_size = 45
43
+ # self.font_name = 'Helvetica'
44
+ # end
45
+ # end
46
+ #
47
+ # @example Using a font property with a different property name
48
+ #
49
+ # class Hero < Metro::Model
50
+ # property :alt_font, type: :font, default: "rgba(255,0,255,1.0)"
51
+ #
52
+ # def draw
53
+ # puts "Font: #{alt_font_name}:#{alt_font_size}"
54
+ # alt_font.draw text, x, y, z_order, x_factor, y_factor, color
55
+ # end
56
+ # end
57
+ #
58
+ class FontProperty < Property
59
+
60
+ # Define a paired property which allows the setting of the font size
61
+ define_property :size, prefix: true
62
+ # Define a paired property which allows the setting of the font name
63
+ define_property :name, type: :text, prefix: true
64
+
65
+ # Return the default font when the value is not supported.
66
+ get do
67
+ default_font
68
+ end
69
+
70
+ # Create a font from the specified hash of data.
71
+ #
72
+ # @example Format of Hash
73
+ #
74
+ # { name: 'Times New Roman', size: 33 }
75
+ #
76
+ get Hash do |value|
77
+ self.class.font_for value.merge(window: model.window)
78
+ end
79
+
80
+ # Save a hash of the default font when the value is not supported.
81
+ set do
82
+ { name: default_font_name, size: default_font_size }
83
+ end
84
+
85
+ # Save a hash representation of the font when given a font
86
+ set Gosu::Font do |font|
87
+ { name: font.name, size: font.height }
88
+ end
89
+
90
+ # Save the hash provided. It is assumed to contain the correct font data.
91
+ set Hash do |hash|
92
+ hash.symbolize_keys!
93
+ end
94
+
95
+ #
96
+ # @return the default font to use when a value has not been provided.
97
+ #
98
+ def default_font
99
+ self.class.font_for name: default_font_name,
100
+ size: default_font_size,
101
+ window: model.window
102
+ end
103
+
104
+ #
105
+ # Use the specified default font size or fall back to 40.
106
+ #
107
+ def default_font_size
108
+ (options[:default] and options[:default][:size]) ? options[:default][:size] : 40
109
+ end
110
+
111
+ #
112
+ # Use the specified default font name or fall back to Gosu's default font name.
113
+ #
114
+ def default_font_name
115
+ (options[:default] and options[:default][:name]) ? options[:default][:name] : Gosu::default_font_name
116
+ end
117
+
118
+ #
119
+ # Return a font that matches the specified criteria. Usig the name, size, and window a font will be
120
+ # generated or retrieved from the cache.
121
+ #
122
+ # @param [Hash] value the hash that contains the `name`, `size` and `window` that describe the font.
123
+ #
124
+ def self.font_for(value)
125
+ value.symbolize_keys!
126
+ name = value[:name]
127
+ size = value[:size]
128
+ window = value[:window]
129
+
130
+ font = fonts["#{name}:#{size}:#{window}"]
131
+ unless font
132
+ font = create_font(window,name,size)
133
+ fonts["#{name}:#{size}:#{window}"] = font
134
+ end
135
+
136
+ font
137
+ end
138
+
139
+ #
140
+ # @return the fonts currently cached by the FontProperty.
141
+ #
142
+ def self.fonts
143
+ @fonts ||= {}
144
+ end
145
+
146
+ private
147
+
148
+ def self.create_font(window,name,size)
149
+ Gosu::Font.new window, name, size
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,101 @@
1
+ module Metro
2
+ class Model
3
+
4
+ #
5
+ # A image property maintains a Gosu::Image.
6
+ #
7
+ # An image is stored in the properties as a string to the specified image path and is converted into
8
+ # a Gosu::Image when it is retrieved within the system. When retrieving an image the Image
9
+ # Property will attempt to use a image at that path that already meets that criteria if it has been
10
+ # loaded.
11
+ #
12
+ # The images are cached within the image property to help performance by reducing the unncessary
13
+ # creation of similar images.
14
+ #
15
+ # @example Defining a image property
16
+ #
17
+ # class Player < Metro::Model
18
+ # property :image
19
+ #
20
+ # def draw
21
+ # image.draw x, y, z_order, x_factor, y_factor, color, :add)
22
+ # end
23
+ #
24
+ # end
25
+ #
26
+ # @example Defining an image property providing a default
27
+ #
28
+ # class Player < Metro::Model
29
+ # property :image, default: "player.png"
30
+ # end
31
+ #
32
+ # @example Using an image property with a different property name
33
+ #
34
+ # class Player < Metro::Model
35
+ # property :disconnected_image, type: :image, default: "disconnected_player.png"
36
+ #
37
+ # def draw
38
+ # disconnected_image.draw x, y, z_order, x_factor, y_factor, color, :add)
39
+ # end
40
+ # end
41
+ #
42
+ class ImageProperty < Property
43
+
44
+ # Return the image at the specified path.
45
+ # @note The path should be the relative path within the game.
46
+ get String do |path|
47
+ self.class.image_for_path path: path, window: model.window
48
+ end
49
+
50
+ # Set the image with the specified path.
51
+ # @note The path should be the relative path within the game.
52
+ set String do |path|
53
+ path
54
+ end
55
+
56
+ # Set the image with the given image. A Gosu::Image does not normally
57
+ # store it's path, however, this functionality has been monkey-patched.
58
+ set Gosu::Image do |image|
59
+ image.path
60
+ end
61
+
62
+ #
63
+ # Return an image for the specified path. On first request it will be loaded from
64
+ # the file-system. On subsequent requests it will be pulled from the cache.
65
+ #
66
+ # @param [Hash] options the relative `path` to the image and the window for which it
67
+ # will be displayed.
68
+ #
69
+ def self.image_for_path(options)
70
+ options.symbolize_keys!
71
+ path = options[:path]
72
+ window = options[:window]
73
+
74
+ image = images[path]
75
+ unless image
76
+ image = create_image(window,path,false)
77
+ images[path] = image
78
+ end
79
+
80
+ image
81
+ end
82
+
83
+ def self.images
84
+ @images ||= {}
85
+ end
86
+
87
+ private
88
+
89
+ # @TODO The Gosu::Image creation should automatically perform this operation of saving the path
90
+ # to the image. This should be monkey-patched onto the image so that images created outside
91
+ # of this process will also have a specified path.
92
+ def self.create_image(window,path,tileable)
93
+ image = Gosu::Image.new(window,asset_path(path),tileable)
94
+ image.path = path
95
+ image
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,29 @@
1
+ module Metro
2
+ class Model
3
+
4
+ #
5
+ # The numeric property will simply convert any input into a floating
6
+ # point value. This is the same both on getting and setting.
7
+ #
8
+ class NumericProperty < Property
9
+
10
+ # For all cases the value is converted to floating point when it can
11
+ # otherwise the default number is used.
12
+ get_or_set do |value|
13
+ if value.is_a?(NilClass)
14
+ default_number
15
+ elsif value.respond_to?(:to_f)
16
+ value.to_f
17
+ else
18
+ default_number
19
+ end
20
+ end
21
+
22
+ def default_number
23
+ options[:default].to_f
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,84 @@
1
+ module Metro
2
+ class Model
3
+
4
+ #
5
+ # A position property maintains a 2D Point.
6
+ #
7
+ # A position property also defines an `x` property and a `y` property which allows a
8
+ # more direct interface.
9
+ #
10
+ # A position is stored as a string in the properties and retrieved as a Point object.
11
+ #
12
+ # @example Defining a position property, using the x, y and z_order properties
13
+ #
14
+ # class Enemy < Metro::Model
15
+ # property :position
16
+ #
17
+ # def draw
18
+ # # image.draw position.x, position.y, z_order, x_factor, y_factor, color, :add)
19
+ # image.draw x, y, z_order, x_factor, y_factor, color, :add)
20
+ # end
21
+ # end
22
+ #
23
+ # @example Defining a position property providing a default
24
+ #
25
+ # class Enemy < Metro::Model
26
+ # property :position, default: Point.at(44,66)
27
+ # end
28
+ #
29
+ # @example Using a position property with a different property name
30
+ #
31
+ # class Hero < Metro::Model
32
+ # property :pos, type: :position, default: Point.zero
33
+ #
34
+ # def draw
35
+ # # image.draw pos.x, pos.y, pos.z_order, x_factor, y_factor, color, :add)
36
+ # image.draw pos_x, pos_y, pos_z_order, x_factor, y_factor, color, :add)
37
+ # end
38
+ # end
39
+ #
40
+ class PositionProperty < Property
41
+
42
+ # Define an x position property
43
+ define_property :x
44
+
45
+ # Define a y position property
46
+ define_property :y
47
+
48
+ # Define a z position property which is used for the z order
49
+ define_property :z
50
+ define_property :z_order
51
+
52
+ # When no getters match the specified value return the default point
53
+ get do
54
+ default_point
55
+ end
56
+
57
+ # When getting a string convert it to a point.
58
+ get String do |value|
59
+ Point.parse(value)
60
+ end
61
+
62
+ # When no setters match save the default point.
63
+ set do
64
+ default_point.to_s
65
+ end
66
+
67
+ # When given a string, it is assumed to be a well formated point
68
+ set String do |value|
69
+ Point.parse(value).to_s
70
+ end
71
+
72
+ # When given a point save the the string value of it.
73
+ set Point do |value|
74
+ value.to_s
75
+ end
76
+
77
+ def default_point
78
+ (options[:default] and options[:default].is_a? Point) ? options[:default] : Point.zero
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,111 @@
1
+ module Metro
2
+ class Model
3
+
4
+ class Property
5
+ attr_reader :model, :options
6
+
7
+ def initialize(model,options={})
8
+ @model = model
9
+ @options = options
10
+ end
11
+
12
+ def self.gets
13
+ @gets ||= begin
14
+ hash = Hash.new { |hash,key| hash["NilClass"] }
15
+ hash["NilClass"] = lambda { |value| raise "#{self} is not able to translate the #{value} (#{value.class})" }
16
+ hash
17
+ end
18
+ end
19
+
20
+ def self.get(type=NilClass,&block)
21
+ gets[type.to_s] = block
22
+ end
23
+
24
+ def get(value)
25
+ get_block = self.class.gets[value.class.to_s]
26
+ instance_exec(value,&get_block)
27
+ end
28
+
29
+ def self.sets
30
+ @sets ||= begin
31
+ hash = Hash.new { |hash,key| hash["NilClass"] }
32
+ hash["NilClass"] = lambda { |value| raise "#{self} is not able to translate the #{value} (#{value.class})" }
33
+ hash
34
+ end
35
+ end
36
+
37
+ def self.set(type=NilClass,&block)
38
+ sets[type.to_s] = block
39
+ end
40
+
41
+ def set(value)
42
+ set_block = self.class.sets[value.class.to_s]
43
+ instance_exec(value,&set_block)
44
+ end
45
+
46
+ def self.get_or_set(type=NilClass,&block)
47
+ gets[type.to_s] = block
48
+ sets[type.to_s] = block
49
+ end
50
+
51
+ def self.defined_properties
52
+ @defined_properties ||= []
53
+ end
54
+
55
+ def self.define_property(name,options = {})
56
+ defined_properties.push PropertyDefinition.new name, options
57
+ end
58
+
59
+ def self.inherited(subclass)
60
+ properties << subclass
61
+ end
62
+
63
+ def self.properties
64
+ @properties ||= []
65
+ end
66
+
67
+ def self.property(name)
68
+ properties_hash[name]
69
+ end
70
+
71
+ def self.properties_hash
72
+ @properties_hash ||= begin
73
+ hash = ActiveSupport::HashWithIndifferentAccess.new(NumericProperty)
74
+ # TODO: do not store classes within the structure - this will misbehave on reloading
75
+ properties.each do |prop|
76
+ prop_name = prop.to_s.gsub(/Property$/,'').split("::").last.underscore
77
+ hash[prop_name] = prop
78
+ hash[prop_name.to_sym] = prop
79
+ end
80
+ # puts hash
81
+ hash
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ class PropertyDefinition
90
+
91
+ attr_reader :name, :options
92
+
93
+ def initialize(name,options)
94
+ @name = name
95
+ @options = options
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ require_relative 'angle'
102
+ require_relative 'animation'
103
+ require_relative 'color'
104
+ require_relative 'dimensions'
105
+ require_relative 'font'
106
+ require_relative 'image'
107
+ require_relative 'numeric'
108
+ require_relative 'position'
109
+ require_relative 'scale'
110
+ require_relative 'text'
111
+ require_relative 'velocity'