metro 0.2.1 → 0.2.2

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 (45) hide show
  1. data/README.md +2 -0
  2. data/changelog.md +10 -0
  3. data/lib/assets/missing.mp3 +0 -0
  4. data/lib/assets/missing.wav +0 -0
  5. data/lib/gosu_ext/image.rb +4 -0
  6. data/lib/gosu_ext/sample.rb +18 -0
  7. data/lib/gosu_ext/song.rb +18 -0
  8. data/lib/metro.rb +2 -0
  9. data/lib/metro/animation/easing/ease_in.rb +15 -0
  10. data/lib/metro/animation/easing/easing.rb +51 -0
  11. data/lib/metro/animation/easing/linear.rb +15 -0
  12. data/lib/metro/animation/has_animations.rb +17 -0
  13. data/lib/metro/animation/implicit_animation.rb +5 -24
  14. data/lib/metro/models/draws.rb +10 -1
  15. data/lib/metro/models/model.rb +117 -89
  16. data/lib/metro/models/models/image.rb +8 -9
  17. data/lib/metro/models/models/label.rb +4 -8
  18. data/lib/metro/models/models/menu.rb +7 -9
  19. data/lib/metro/models/models/rectangle.rb +7 -12
  20. data/lib/metro/models/models/song.rb +33 -0
  21. data/lib/metro/models/properties/dimensions_property.rb +18 -1
  22. data/lib/metro/models/properties/image_property.rb +2 -2
  23. data/lib/metro/models/properties/position_property.rb +6 -0
  24. data/lib/metro/models/properties/property.rb +129 -23
  25. data/lib/metro/models/properties/sample_property.rb +97 -0
  26. data/lib/metro/models/properties/song_property.rb +113 -0
  27. data/lib/metro/scene.rb +2 -11
  28. data/lib/metro/scenes.rb +14 -7
  29. data/lib/metro/transitions/fade_transition_scene.rb +8 -1
  30. data/lib/metro/units/bounds.rb +8 -0
  31. data/lib/metro/units/dimensions.rb +23 -5
  32. data/lib/metro/units/point.rb +26 -1
  33. data/lib/metro/units/rectangle_bounds.rb +52 -0
  34. data/lib/metro/units/scale.rb +16 -0
  35. data/lib/metro/units/units.rb +3 -1
  36. data/lib/metro/version.rb +1 -1
  37. data/lib/metro/window.rb +7 -0
  38. data/lib/templates/game/README.md.tt +20 -1
  39. data/spec/metro/models/models/label_spec.rb +4 -4
  40. data/spec/metro/models/properties/dimensions_spec.rb +29 -0
  41. data/spec/metro/models/properties/position_property_spec.rb +5 -5
  42. data/spec/spec_helper.rb +3 -1
  43. metadata +22 -9
  44. data/lib/metro/animation/easing.rb +0 -31
  45. data/lib/metro/models/rectangle_bounds.rb +0 -28
@@ -0,0 +1,113 @@
1
+ module Metro
2
+ class Model
3
+
4
+ #
5
+ # A song property maintains a Gosu::Song.
6
+ #
7
+ # A song is stored in the properties as the path in the assets folder and is converted into
8
+ # a Gosu::Song when it is retrieved within the system. When retrieving a song the Song
9
+ # Property will attempt to use a song that already exists that meets that criteria.
10
+ #
11
+ # The songs are cached within the song property to help performance by reducing the unncessary
12
+ # creation of similar song.
13
+ #
14
+ # @example Defining a song property
15
+ #
16
+ # class Song < Metro::Model
17
+ # property :song
18
+ # end
19
+ #
20
+ # @example Defining a song property providing a default
21
+ #
22
+ # class Song < Metro::Model
23
+ # property :song, path: 'happy-song.wav'
24
+ # end
25
+ #
26
+ # @example Using a song property with a different property name
27
+ #
28
+ # class Song < Metro::Model
29
+ # property :intro, type: :song, path: 'intro-song.wav'
30
+ # end
31
+ #
32
+ class SongProperty < Metro::Model::Property
33
+
34
+ # By default, getting an unsupported value will return the default song
35
+ get do |value|
36
+ default_song
37
+ end
38
+
39
+ # By default, setting an unsupported value will save the default song
40
+ set do |value|
41
+ default_song_name
42
+ end
43
+
44
+ # Generate a song from the specified string filepath
45
+ get String do |filename|
46
+ self.class.song_for path: filename, window: model.window
47
+ end
48
+
49
+ # The assumption here is that the string is a song filepath
50
+ set String do |filename|
51
+ filename
52
+ end
53
+
54
+ # Setting the song value with a Metro::Song will save the string filepath
55
+ set Metro::Song do |song|
56
+ song.path
57
+ end
58
+
59
+ #
60
+ # @return the default song for the song property. This is based on the default
61
+ # song name.
62
+ #
63
+ def default_song
64
+ self.class.song_for path: default_song_name, window: model.window
65
+ end
66
+
67
+ #
68
+ # @return a string song name that is default. If the property was not created with
69
+ # a default value the the default song is the missing song found in Metro.
70
+ #
71
+ def default_song_name
72
+ options[:path] || metro_asset_path('missing.mp3')
73
+ end
74
+
75
+ #
76
+ # Returns a Metro::Song. This is composed of the metadata provided and a Gosu::Song.
77
+ #
78
+ # Songs are cached within the property to increase performance.
79
+ #
80
+ # @param [Hash] options the path, window, and other parameters necessary to generate
81
+ # a song.
82
+ #
83
+ def self.song_for(options)
84
+ options.symbolize_keys!
85
+ relative_path = options[:path]
86
+ window = options[:window]
87
+
88
+ absolute_path = path = options[:path]
89
+ absolute_path = asset_path(absolute_path) unless absolute_path.start_with? "/"
90
+
91
+ gosu_song = songs[relative_path]
92
+
93
+ unless gosu_song
94
+ gosu_song = create_song(window,absolute_path)
95
+ songs[relative_path] = gosu_song
96
+ end
97
+
98
+ Metro::Song.new gosu_song, relative_path
99
+ end
100
+
101
+ def self.songs
102
+ @songs ||= {}
103
+ end
104
+
105
+ private
106
+
107
+ def self.create_song(window,filename)
108
+ Gosu::Song.new(window, filename)
109
+ end
110
+
111
+ end
112
+ end
113
+ end
data/lib/metro/scene.rb CHANGED
@@ -250,6 +250,7 @@ module Metro
250
250
  def register_actor(actor_factory)
251
251
  registering_actor = actor(actor_factory.name)
252
252
  registering_actor.window = window
253
+ registering_actor.show
253
254
 
254
255
  drawers.push(registering_actor)
255
256
  updaters.push(registering_actor)
@@ -338,6 +339,7 @@ module Metro
338
339
  #
339
340
  def self.inherited(base)
340
341
  scenes << base.to_s
342
+ Scenes.add_scene(base)
341
343
  end
342
344
 
343
345
  #
@@ -358,17 +360,6 @@ module Metro
358
360
  updaters.push(updater)
359
361
  end
360
362
 
361
- #
362
- # A simplier syntax to enqueue an animation. At the moment this animation is going
363
- # to be an implicit animation.
364
- #
365
- def animate(actor_or_actor_name,options,&block)
366
- options[:actor] = actor(actor_or_actor_name)
367
- options[:context] = self
368
- animation_group = SceneAnimation.build options, &block
369
- enqueue animation_group
370
- end
371
-
372
363
  #
373
364
  # The class defined updaters which will be converted to instance updaters when the scene
374
365
  # has started.
data/lib/metro/scenes.rb CHANGED
@@ -27,6 +27,16 @@ module Metro
27
27
  module Scenes
28
28
  extend self
29
29
 
30
+ #
31
+ # Add a scene to the hash of scenes with the scene name of the scene as the key
32
+ # to retrieving this scene.
33
+ #
34
+ # @param [Scene] scene the scene to be added to the hash of Scenes.
35
+ #
36
+ def add_scene(scene)
37
+ all_scenes_for(scene).each { |scene| scenes_hash[scene.scene_name] = scene.to_s }
38
+ end
39
+
30
40
  #
31
41
  # Finds the scene based on the specified scene name.
32
42
  #
@@ -101,7 +111,7 @@ module Metro
101
111
  # as well as the class name constants to allow for the scenes to be found.
102
112
  #
103
113
  def scenes_hash
104
- @scenes_hash ||= build_map_of_scenes(Scene.scenes)
114
+ @scenes_hash ||= hash_with_missing_scene_default
105
115
  end
106
116
 
107
117
  #
@@ -114,22 +124,19 @@ module Metro
114
124
  # @see #scenes_hash
115
125
  #
116
126
  def build_map_of_scenes(scenes)
117
- hash = hash_with_missing_scene_default
118
- all_scenes_for(scenes).inject(hash) do |hash,scene|
119
- hash[scene.scene_name] = scene.to_s
120
- hash
121
- end
122
127
  end
123
128
 
124
129
  #
125
130
  # Create a hash that will return a setup missing scene by default.
126
131
  #
127
132
  def hash_with_missing_scene_default
128
- ActiveSupport::HashWithIndifferentAccess.new do |hash,key|
133
+ hash = HashWithIndifferentAccess.new do |hash,key|
129
134
  missing_scene = scene_class(hash[:missing_scene])
130
135
  missing_scene.missing_scene = key.to_sym
131
136
  missing_scene
132
137
  end
138
+ hash[:missing_scene] = "Metro::MissingScene"
139
+ hash
133
140
  end
134
141
 
135
142
  #
@@ -10,7 +10,14 @@ module Metro
10
10
  def show
11
11
  rectangle.color = starting_color
12
12
 
13
- animate :rectangle, to: { color: final_color }, interval: interval do
13
+ color = final_color
14
+
15
+ animate :rectangle, to: { red: color.red,
16
+ green: color.green,
17
+ blue: color.blue,
18
+ alpha: color.alpha },
19
+ interval: interval do
20
+
14
21
  transition_to next_scene
15
22
  end
16
23
  end
@@ -0,0 +1,8 @@
1
+ module Metro
2
+ module Units
3
+
4
+ # Rectangle Bounds are common enough to be considered simply Bounds.
5
+ Bounds = RectangleBounds
6
+
7
+ end
8
+ end
@@ -1,17 +1,35 @@
1
1
  module Metro
2
2
  module Units
3
+
4
+ #
5
+ # Represents an object that contains both the width and height.
6
+ #
3
7
  class Dimensions < Struct.new(:width,:height)
4
8
 
9
+ #
10
+ # Create a dimensions objects with zero width and zero height.
11
+ #
5
12
  def self.none
6
- new 0.0, 0.0
13
+ of 0.0, 0.0
7
14
  end
8
15
 
9
- def self.of(width,height)
10
- new width.to_f, height.to_f
16
+ #
17
+ # Parse a string representation of a dimensions object. The
18
+ # supported formated is a comma-delimited string that contains
19
+ # two attributes width and height.
20
+ #
21
+ def self.parse(string)
22
+ of *string.split(",",2).map(&:to_f)
11
23
  end
12
24
 
13
- def self.parse(string)
14
- to *string.split(",",2).map(&:to_f)
25
+
26
+ #
27
+ # An alternate way of creating a dimensions object which
28
+ # will enforce that the values added are converted to floating
29
+ # point numbers.
30
+ #
31
+ def self.of(width,height)
32
+ new width.to_f, height.to_f
15
33
  end
16
34
 
17
35
  def to_s
@@ -1,18 +1,37 @@
1
1
  module Metro
2
2
  module Units
3
+
4
+ #
5
+ # Represents and object that contains the x, y, and z position.
6
+ #
3
7
  class Point < Struct.new(:x,:y,:z)
8
+
9
+ #
10
+ # Generate a point at 0,0,0.
11
+ #
4
12
  def self.zero
5
13
  new 0.0, 0.0, 0.0
6
14
  end
7
15
 
16
+ #
17
+ # An alternate way of creating a point. Creation here converts
18
+ # all inputs to floating point and assumes that the z-value is
19
+ # zero (as this is a 2D universe).
20
+ #
8
21
  def self.at(x,y,z=0.0)
9
22
  new x.to_f, y.to_f, z.to_f
10
23
  end
11
24
 
25
+ #
26
+ # Parse a string representation of a point object. The
27
+ # supported formated is a comma-delimited string that contains
28
+ # either "x,y" or "x,y,z".
29
+ #
12
30
  def self.parse(string)
13
31
  at *string.split(",",3).map(&:to_f)
14
32
  end
15
33
 
34
+ # As this is a 2D world, the Z is often refered to as a the z-ordering
16
35
  alias_method :z_order, :z
17
36
  alias_method :z_order=, :z=
18
37
 
@@ -20,9 +39,15 @@ module Metro
20
39
  "#{x},#{y},#{z}"
21
40
  end
22
41
 
42
+ #
43
+ # Add the point to another point-like structure. Anything that also has
44
+ # the methods x, y, and z.
45
+ #
46
+ # @return a new point which is the sum of the point and the provided value.
47
+ #
23
48
  def +(value)
24
49
  raise "Unabled to add point to #{value} #{value.class}" if [ :x, :y, :z ].find { |method| ! value.respond_to?(method) }
25
- self.class.new((x + value.x),(y + value.y),(z + value.z))
50
+ self.class.at((x + value.x),(y + value.y),(z + value.z))
26
51
  end
27
52
 
28
53
  end
@@ -0,0 +1,52 @@
1
+ module Metro
2
+ module Units
3
+
4
+ #
5
+ # An object that represents a rectanglar bounds.
6
+ #
7
+ class RectangleBounds < Struct.new(:min_x,:min_y,:max_x,:max_y)
8
+
9
+ # Allow the ability to refer to the min, max values with their
10
+ # other alternate names.
11
+
12
+ alias_method :left, :min_x
13
+ alias_method :left=, :min_x=
14
+ alias_method :right, :max_x
15
+ alias_method :right=, :max_x=
16
+ alias_method :top, :min_y
17
+ alias_method :top=, :min_y=
18
+ alias_method :bottom, :max_y
19
+ alias_method :bottom=, :max_y=
20
+
21
+ #
22
+ # Create a bounds with bounds.
23
+ #
24
+ def initialize(params = {})
25
+ self.min_x = params[:x] || params[:min_x]
26
+ self.min_y = params[:y] || params[:min_y]
27
+ self.max_x = (params[:max_x] || (min_x + params[:width]))
28
+ self.max_y = (params[:max_y] || (min_y + params[:height]))
29
+ end
30
+
31
+ #
32
+ # Does this bounds contain the following point?
33
+ #
34
+ def contains?(x,y)
35
+ x > min_x and x < max_x and y > min_y and y < max_y
36
+ end
37
+
38
+ #
39
+ # Does this rectanglular bounds intersect with another rectanglular bounds?
40
+ #
41
+ def intersect?(b)
42
+ not(b.min_x > max_x or b.max_x < min_x or b.min_y > max_y or b.max_y < min_y)
43
+ end
44
+
45
+ def to_s
46
+ "(#{min_x},#{min_y}) to (#{max_x},#{max_y})"
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -1,15 +1,31 @@
1
1
  module Metro
2
2
  module Units
3
+
4
+ #
5
+ # Represents an object that contains the x scale factor, and y scale factor.
6
+ #
3
7
  class Scale < Struct.new(:x_factor,:y_factor)
4
8
 
9
+ #
10
+ # Create a scale that is 1:1.
11
+ #
5
12
  def self.one
6
13
  new 1.0, 1.0
7
14
  end
8
15
 
16
+ #
17
+ # An alternative way to create a scale which will automatically convert
18
+ # the inputs into floating numbers.
19
+ #
9
20
  def self.to(x,y)
10
21
  new x.to_f, y.to_f
11
22
  end
12
23
 
24
+ #
25
+ # Parse a string representation of a scale object. The
26
+ # supported formated is a comma-delimited string that contains
27
+ # two attributes x-factor and y-factor.
28
+ #
13
29
  def self.parse(string)
14
30
  to *string.split(",",2).map(&:to_f)
15
31
  end
@@ -1,3 +1,5 @@
1
1
  require_relative 'point'
2
2
  require_relative 'dimensions'
3
- require_relative 'scale'
3
+ require_relative 'scale'
4
+ require_relative 'rectangle_bounds'
5
+ require_relative 'bounds'
data/lib/metro/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Metro
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  WEBSITE = "https://github.com/burtlo/metro"
4
4
  CONTACT_EMAILS = ["franklin.webber@gmail.com"]
5
5
 
data/lib/metro/window.rb CHANGED
@@ -60,6 +60,13 @@ module Metro
60
60
  scene.button_down(id)
61
61
  end
62
62
 
63
+ #
64
+ # @return the dimensions of the current window.
65
+ #
66
+ def dimensions
67
+ Metro::Units::Dimensions.of width, height
68
+ end
69
+
63
70
  #
64
71
  # Define an acessor that enables/disables the use of a cursor
65
72
  # within the window. The value should be truthy/falsy.
@@ -7,4 +7,23 @@ are creating. This file's intention is to allow a user to
7
7
  refer to this for more information related to the game or
8
8
  possibly any notes or caveats about the game.
9
9
 
10
- ## Contact
10
+ ## Contact
11
+
12
+
13
+ ## Resources
14
+
15
+ #### Art
16
+
17
+ * [Lost Garden](http://www.lostgarden.com/2007/05/dancs-miraculously-flexible-game.html)
18
+
19
+ #### Books
20
+
21
+ * [Rules of Play](http://www.amazon.com/dp/0262240459)
22
+ * [Game Programming Gems 8](http://www.amazon.com/dp/1584507020)
23
+ * [Game Feel](http://www.amazon.com/dp/0123743281)
24
+ * [Game Coding Complete](http://www.amazon.com/dp/1584506806)
25
+ * [Game Design Workshop](http://www.amazon.com/dp/0240809742)
26
+ * [Challenges For Game Designers](http://www.amazon.com/dp/158450580X)
27
+ * [The Art of Game Design: A book of lenses](http://www.amazon.com/dp/0123694965)
28
+ * [A Theory of Fun](http://www.theoryoffun.com)
29
+ * [Andrew Rollings and Ernest Adams on Game Design](http://www.amazon.com/dp/1592730019)