metro 0.1.5 → 0.1.6

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