metro 0.2.1 → 0.2.2

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