gamebox 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +9 -0
  3. data/History.txt +5 -0
  4. data/README.txt +4 -3
  5. data/Rakefile +12 -4
  6. data/TODO.txt +1 -5
  7. data/VERSION +1 -1
  8. data/docs/getting_started.rdoc +2 -2
  9. data/gamebox.gemspec +26 -10
  10. data/lib/gamebox/actor.rb +10 -3
  11. data/lib/gamebox/actor_factory.rb +2 -2
  12. data/lib/gamebox/actor_view.rb +14 -11
  13. data/lib/gamebox/actors/collidable_debugger.rb +35 -0
  14. data/lib/gamebox/actors/curtain.rb +2 -2
  15. data/lib/gamebox/actors/logo.rb +0 -6
  16. data/lib/gamebox/actors/score.rb +2 -5
  17. data/lib/gamebox/actors/spatial_debugger.rb +47 -0
  18. data/lib/gamebox/actors/svg_actor.rb +4 -6
  19. data/lib/gamebox/arbiter.rb +108 -15
  20. data/lib/gamebox/behavior.rb +29 -1
  21. data/lib/gamebox/behaviors/animated.rb +14 -23
  22. data/lib/gamebox/behaviors/audible.rb +1 -12
  23. data/lib/gamebox/behaviors/collidable.rb +29 -22
  24. data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +61 -0
  25. data/lib/gamebox/behaviors/collidable/circle_collidable.rb +17 -0
  26. data/lib/gamebox/behaviors/collidable/collidable_shape.rb +35 -0
  27. data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +85 -0
  28. data/lib/gamebox/behaviors/graphical.rb +13 -10
  29. data/lib/gamebox/behaviors/layered.rb +6 -20
  30. data/lib/gamebox/behaviors/physical.rb +116 -93
  31. data/lib/gamebox/class_finder.rb +6 -2
  32. data/lib/gamebox/config_manager.rb +24 -4
  33. data/lib/gamebox/data/config/objects.yml +5 -3
  34. data/lib/gamebox/ftor.rb +372 -0
  35. data/lib/gamebox/gamebox_application.rb +2 -8
  36. data/lib/gamebox/hooked_gosu_window.rb +30 -0
  37. data/lib/gamebox/input_manager.rb +78 -79
  38. data/lib/gamebox/lib/code_statistics.rb +1 -1
  39. data/lib/gamebox/lib/numbers_ext.rb +1 -1
  40. data/lib/gamebox/lib/rect.rb +612 -0
  41. data/lib/gamebox/physical_stage.rb +12 -2
  42. data/lib/gamebox/physics.rb +14 -3
  43. data/lib/gamebox/resource_manager.rb +28 -65
  44. data/lib/gamebox/sound_manager.rb +7 -13
  45. data/lib/gamebox/spatial_hash.rb +60 -14
  46. data/lib/gamebox/spatial_stagehand.rb +19 -0
  47. data/lib/gamebox/stage.rb +16 -1
  48. data/lib/gamebox/stage_manager.rb +1 -1
  49. data/lib/gamebox/svg_document.rb +1 -0
  50. data/lib/gamebox/tasks/gamebox_tasks.rb +23 -11
  51. data/lib/gamebox/templates/template_app/.gitignore +1 -0
  52. data/lib/gamebox/templates/template_app/Gemfile +1 -1
  53. data/lib/gamebox/templates/template_app/Rakefile +6 -21
  54. data/lib/gamebox/templates/template_app/config/environment.rb +14 -0
  55. data/lib/gamebox/templates/template_app/config/game.yml +2 -1
  56. data/lib/gamebox/templates/template_app/script/generate +0 -3
  57. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -11
  58. data/lib/gamebox/templates/template_app/src/game.rb +0 -1
  59. data/lib/gamebox/templates/template_app/src/my_actor.rb +2 -2
  60. data/lib/gamebox/version.rb +1 -1
  61. data/lib/gamebox/views/graphical_actor_view.rb +15 -9
  62. data/lib/gamebox/wrapped_screen.rb +114 -7
  63. data/load_paths.rb +20 -0
  64. data/script/perf_spatial_hash.rb +73 -0
  65. data/spec/actor_view_spec.rb +1 -1
  66. data/spec/arbiter_spec.rb +264 -0
  67. data/spec/behavior_spec.rb +19 -2
  68. data/spec/collidable_spec.rb +105 -5
  69. data/spec/helper.rb +1 -1
  70. data/spec/label_spec.rb +1 -1
  71. data/spec/resource_manager_spec.rb +1 -1
  72. data/spec/spatial_hash_spec.rb +1 -1
  73. metadata +52 -10
  74. data/lib/gamebox/lib/surface_ext.rb +0 -76
@@ -7,17 +7,21 @@ module ClassFinder
7
7
 
8
8
  begin
9
9
  klass = Object.const_get(klass_name)
10
- rescue NameError
10
+ rescue NameError => ex
11
11
  # not there yet
12
+ log(:warn, ex)
12
13
  begin
13
14
  require "#{name}"
14
15
  rescue LoadError => ex
15
16
  # maybe its included somewhere else
17
+ log(:warn, ex)
16
18
  ensure
17
19
  begin
18
20
  klass = Object.const_get(klass_name)
19
- rescue
21
+ rescue Exception => ex
20
22
  # leave this alone.. maybe there isnt a NameView
23
+ log(:warn, ex)
24
+
21
25
  end
22
26
  end
23
27
  end
@@ -1,15 +1,14 @@
1
1
  class ConfigManager
2
2
 
3
3
  attr_accessor :settings
4
- constructor :resource_manager
5
4
  GAME_SETTINGS_FILE = "game"
6
5
 
7
- def setup
8
- @settings = @resource_manager.load_config(GAME_SETTINGS_FILE)
6
+ def initialize
7
+ @settings = load_config(GAME_SETTINGS_FILE)
9
8
  end
10
9
 
11
10
  def save
12
- @resource_manager.save_settings(GAME_SETTINGS_FILE, @settings)
11
+ save_settings(GAME_SETTINGS_FILE, @settings)
13
12
  end
14
13
 
15
14
  def [](key)
@@ -19,4 +18,25 @@ class ConfigManager
19
18
  def []=(key,val)
20
19
  @settings[key] = val
21
20
  end
21
+
22
+ # TODO make this path include that app name?
23
+ def load_config(name)
24
+ conf = YAML::load_file(CONFIG_PATH + name + ".yml")
25
+ user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
26
+ if File.exist? user_file
27
+ user_conf = YAML::load_file user_file
28
+ conf = conf.merge user_conf
29
+ end
30
+ conf
31
+ end
32
+
33
+ def save_settings(name, settings)
34
+ user_gamebox_dir = "#{ENV['HOME']}/.gamebox"
35
+ FileUtils.mkdir_p user_gamebox_dir
36
+ user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
37
+ File.open user_file, "w" do |f|
38
+ f.write settings.to_yaml
39
+ end
40
+ end
41
+
22
42
  end
@@ -5,6 +5,8 @@ game:
5
5
  - sound_manager
6
6
  - stage_manager
7
7
  resource_manager:
8
+ compose:
9
+ - wrapped_screen
8
10
  stage_manager:
9
11
  compose:
10
12
  - input_manager
@@ -18,13 +20,13 @@ sound_manager:
18
20
  - config_manager
19
21
  input_manager:
20
22
  compose:
23
+ - wrapped_screen
21
24
  - config_manager
22
25
  wrapped_screen:
23
26
  compose:
24
27
  - config_manager
28
+ config_manager:
25
29
  actor_factory:
26
30
  compose:
27
31
  - input_manager
28
- config_manager:
29
- compose:
30
- - resource_manager
32
+ - wrapped_screen
@@ -0,0 +1,372 @@
1
+ # Ftor ("Fake vecTOR"), a vector-like class for 2D position/movement.
2
+ #--
3
+ # Rubygame -- Ruby code and bindings to SDL to facilitate game creation
4
+ # Copyright (C) 2004-2007 John Croisant
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #++
20
+
21
+
22
+ # *NOTE*: Ftor is DEPRECATED and will be removed in Rubygame 3.0!
23
+ # A mostly-compatible vector class will be provided at or before
24
+ # that time.
25
+ #
26
+ # *NOTE*: you must require 'rubygame/ftor' manually to gain access to
27
+ # Rubygame::Ftor. It is not imported with Rubygame by default!
28
+ #
29
+ # Ftor ("Fake vecTOR"), a vector-like class for 2D position/movement.
30
+ #
31
+ # (NB: See #angle for an important note about why angles appear to be the
32
+ # opposite of what you may expect.)
33
+ #
34
+ # Ftor is useful for storing 2D coordinates (x,y) as well as
35
+ # vector quantities such as velocity and acceleration (representationally,
36
+ # points and vectors are equivalent.) Although Ftors are always represented
37
+ # internally as Cartesian coordinates (x, y), it is possible to deal with an
38
+ # Ftor as polar coordinates (#angle, #magnitude) instead.
39
+ # See #new_am and #set_am!, for example.
40
+ #
41
+ # Ftor is a "fake" vector because it has certain convenient properties which
42
+ # differ from "true" vectors (i.e. vectors in a strict mathematical sense).
43
+ #
44
+ # Unlike vectors, Ftors may be multiplied or divided to another Ftor. This is
45
+ # equivalent to multiplying or dividing each component by the corresponding
46
+ # component in the second Ftor. If you like, you can think of this feature as
47
+ # scaling each component of the Ftor by a separate factor:
48
+ #
49
+ # Ftor(a,b) * Ftor(c,d) = Ftor(a*c, b*d)
50
+ #
51
+ # Of course, Ftors also have the usual vector behavior for addition/subraction
52
+ # between two Ftors, and multiplication/division of an Ftor by a scalar:
53
+ #
54
+ # Ftor(a,b) + Ftor(c,d) = Ftor(a+c, b+d)
55
+ # Ftor(a,b) * n = Ftor(a*n, b*n)
56
+ #
57
+ # Additionally, Ftor contains functions for manipulating itself.
58
+ # You can both get and set such properties as #angle, #magnitude, #unit,
59
+ # and #normal, and the Ftor will change in-place as needed. For example,
60
+ # if you set #angle=, the vector will change to have the new angle,
61
+ # but keeps the same magnitude as before.
62
+ #
63
+ # Ftor attempts to save processing time (at the expense of memory) by
64
+ # storing secondary properties (angle, magnitude, etc.) whenever they are
65
+ # calculated,so that they need not be calculated repeatedly. If the vector
66
+ # changes, the properties will be calculated again the next time they
67
+ # are needed.
68
+ # (In future versions, it may be possible to disable this feature for
69
+ # certain Ftors, for example if they will change very often, to save memory.)
70
+ #
71
+ class Ftor
72
+ PI = Math::PI
73
+ HALF_PI = PI*0.5
74
+ THREE_HALF_PI = PI*1.5
75
+ TWO_PI = PI*2
76
+
77
+ # Create a new Ftor by specifying its x and y components. See also #new_am
78
+ # and #new_from_to.
79
+ def initialize(x,y)
80
+ @x, @y = x, y
81
+ end
82
+
83
+ # Create a new Ftor by specifying its #angle (in radians) and #magnitude.
84
+ # See also #new.
85
+ def self.new_am(a,m)
86
+ v = self.new(1,0)
87
+ v.a, v.m = a, m
88
+ return v
89
+ end
90
+
91
+ # Returns a new Ftor which represents the difference in position of two
92
+ # points +p1+ and +p2+. (+p1+ and +p2+ can be Ftors, size-2 Arrays, or
93
+ # anything else which has two numerical components and responds to #[].)
94
+ #
95
+ # In other words, assuming +v+ is the Ftor returned by this function:
96
+ # p1 + v = p2
97
+ def self.new_from_to(p1,p2)
98
+ return self.new(p2[0]-p1[0],p2[1]-p1[1])
99
+ end
100
+
101
+ attr_reader :x # The x component of the Ftor.
102
+ # Set the x component of the Ftor.
103
+ def x=(value)
104
+ @x = value
105
+ _clear()
106
+ end
107
+
108
+ attr_reader :y # The y component of the Ftor.
109
+ # Set the y component of the Ftor.
110
+ def y=(value)
111
+ @y = value
112
+ _clear()
113
+ end
114
+
115
+ # Modify the x and y components of the Ftor in-place
116
+ def set!(x,y)
117
+ @x, @y = x,y
118
+ _clear()
119
+ end
120
+
121
+ # Modify the #angle (in radians) and #magnitude of the Ftor in-place
122
+ def set_am!(a,m)
123
+ self.angle, self.magnitude = a, m
124
+ end
125
+
126
+ # Same as #to_s, but this Ftor's #object_id is also displayed.
127
+ def inspect
128
+ "#<#{self.class}:#{object_id}: %f, %f>"%[@x,@y]
129
+ end
130
+
131
+ # Display this Ftor in the format: "#<Ftor: [x, y]>". x and y are displayed
132
+ # as floats at full precision. See also #pp.
133
+ def to_s
134
+ "#<#{self.class}: [%f, %f]>"%[@x,@y]
135
+ end
136
+
137
+ # "Pretty print". Same as #to_s, but components are displayed as rounded
138
+ # floats to 3 decimal places, for easy viewing.
139
+ def pretty
140
+ "#<#{self.class}: [%0.3f, %0.3f]>"%[@x,@y]
141
+ end
142
+
143
+ # Same as #to_s_am, but this Ftor's #object_id is also displayed.
144
+ def inspect_am
145
+ "#<#{self.class}:AM:#{object_id}: %f, %f>"%[angle(),magnitude()]
146
+ end
147
+
148
+ # Display this Ftor in the format: "#<Ftor:AM: [angle, magnitude]>".
149
+ # angle and magnitude are displayed as floats at full precision.
150
+ # See also #to_s and #pp_am.
151
+ def to_s_am
152
+ "#<#{self.class}:AM: [%f, %f]>"%[angle(),magnitude()]
153
+ end
154
+
155
+ # "Pretty print" with angle and magnitude.
156
+ # Same as #to_s_am, but components are displayed as rounded floats to 3
157
+ # decimal places, for easy viewing.
158
+ def pretty_am
159
+ "#<#{self.class}:AM: [%0.3f, %0.3f]>"%[angle(),magnitude()]
160
+ end
161
+
162
+ # Returns an Array of this Ftor's components, [x,y].
163
+ def to_a
164
+ [@x,@y]
165
+ end
166
+ alias :to_ary :to_a
167
+
168
+ # Return the +i+th component of this Ftor, as if it were the Array
169
+ # returned by #to_a.
170
+ def [](i)
171
+ [@x,@y][i]
172
+ end
173
+
174
+ # True if this Ftor is equal to +other+, when both have been converted to
175
+ # Arrays via #to_a. In other words, a component-by-component equality check.
176
+ def ==(other)
177
+ to_a() == other.to_a
178
+ end
179
+
180
+ # The reverse of this Ftor. I.e., all components are negated. See also
181
+ # #reverse!.
182
+ def -@
183
+ self.class.new(-@x,-@y)
184
+ end
185
+
186
+ # Like #-@, but reverses this Ftor in-place.
187
+ def reverse!
188
+ set!(-@x,-@y)
189
+ end
190
+
191
+ # Perform vector addition with this Ftor and +other+, adding them on a
192
+ # component-by-component basis, like so:
193
+ # Ftor(a,b) + Ftor(c,d) = Ftor(a+c, b+d)
194
+ def +(other)
195
+ return self.class.new(@x+other[0],@y+other[1])
196
+ end
197
+
198
+ # Like #+, but performs subtraction instead of addition.
199
+ def -(other)
200
+ return self.class.new(@x-other[0],@y-other[1])
201
+ end
202
+
203
+ # Perform multiplication of this Ftor by the scalar +other+, like so:
204
+ # Ftor(a,b) * n = Ftor(a*n, b*n)
205
+ #
206
+ # However, if this causes TypeError, attempt to extract indices 0 and 1
207
+ # with +other+'s #[] operator, and multiply them into the corresponding
208
+ # components of this Ftor, like so:
209
+ # Ftor(a,b) * Ftor(c,d) = Ftor(a*c, b*d)
210
+ # Ftor(a,b) * [c,d] = Ftor(a*c, b*d)
211
+ def *(other)
212
+ return self.class.new(@x*other,@y*other)
213
+ rescue TypeError
214
+ return self.class.new(@x*other[0],@y*other[1])
215
+ end
216
+
217
+ # Like #*, but performs division instead of multiplication.
218
+ def /(other)
219
+ x, y = @x.to_f, @y.to_f
220
+ return self.class.new(x/other,y/other)
221
+ rescue TypeError
222
+ return self.class.new(x/other[0],y/other[1])
223
+ end
224
+
225
+ # Return the angle (radians) this Ftor forms with the positive X axis.
226
+ # This is the same as the Ftor's angle in a polar coordinate system.
227
+ #
228
+ # *IMPORTANT*: Because the positive Y axis on the Rubygame::Screen points
229
+ # *downwards*, an angle in the range 0..PI will appear to point *downwards*,
230
+ # rather than upwards!
231
+ # This also means that positive rotation will appear *clockwise*, and
232
+ # negative rotation will appear *counterclockwise*!
233
+ # This is the opposite of what you would expect in geometry class!
234
+ def angle
235
+ @angle or @angle = Math.atan2(@y,@x)
236
+ end
237
+
238
+ # Set the angle (radians) of this Ftor from the positive X axis.
239
+ # Magnitude is preserved.
240
+ def angle=(a)
241
+ m = magnitude()
242
+ set!( Math.cos(a)*m, Math.sin(a)*m )
243
+ end
244
+
245
+ alias :a :angle
246
+ alias :a= :angle= ;
247
+
248
+ # Returns the magnitude of the Ftor, i.e. its length from tail to head.
249
+ # This is the same as the Ftor's magnitude in a polar coordinate system.
250
+ def magnitude
251
+ @magnitude or @magnitude = Math.hypot(@x,@y)
252
+ end
253
+
254
+ # Modifies the #magnitude of the Ftor, preserving its #angle.
255
+ #
256
+ # In other words, the Ftor will point in the same direction, but it will
257
+ # be a different length from tail to head.
258
+ def magnitude=(m)
259
+ new = unit() * m
260
+ set!(new.x, new.y)
261
+ end
262
+
263
+ alias :m :magnitude
264
+ alias :m= :magnitude= ;
265
+
266
+ # Return a new unit Ftor which is perpendicular to this Ftor (rotated by
267
+ # pi/2 radians, to be specific).
268
+ def normal
269
+ @normal or @normal = unit().rotate(HALF_PI)
270
+ end
271
+
272
+ # Rotate this Ftor in-place, so that it is perpendicular to +other+.
273
+ # This Ftor will be at an angle of -pi/2 to +other+.
274
+ def normal=(other)
275
+ set!( *(self.class.new(*other).unit().rotate(-HALF_PI) * magnitude()) )
276
+ end
277
+
278
+ alias :n :normal
279
+ alias :n= :normal= ;
280
+
281
+ # Return the unit vector of the Ftor, i.e. an Ftor with the same direction,
282
+ # but a #magnitude of 1. (This is sometimes called a "normalized" vector,
283
+ # not to be confused with a vector's #normal.)
284
+ def unit
285
+ m = magnitude().to_f
286
+ @unit or @unit = Ftor.new(@x/m, @y/m)
287
+ end
288
+
289
+ # Rotates this Ftor in-place, so that its #unit vector matches the unit
290
+ # vector of the given Ftor.
291
+ #
292
+ # In other words, changes the #angle of this Ftor to be the same as the angle
293
+ # of the given Ftor, but this Ftor's #magnitude does not change.
294
+ #--
295
+ # TODO: investigate efficiency of using `self.angle = other.angle` instead
296
+ #++
297
+ def unit=(other)
298
+ set!( *(self.class.new(*other).unit() * magnitude()) )
299
+ end
300
+
301
+ alias :u :unit
302
+ alias :u= :unit=
303
+ alias :align! :unit=;
304
+
305
+ # Return the dot product (aka inner product) of this Ftor and +other+.
306
+ # The dot product of two vectors +v1+ and +v2+ is:
307
+ # v1.x * v2.x + v1.y * v2.y
308
+ def dot(other)
309
+ @x*other[0] + @y*other[1]
310
+ end
311
+
312
+ # Return the #dot product of #unit vectors of this Ftor and +other+.
313
+ def udot(other)
314
+ unit().dot(self.class.new(*other).unit)
315
+ end
316
+
317
+ #Return the difference in angles (radians) between this Ftor and +other+.
318
+ def angle_with(other)
319
+ Math.acos( self.udot(other) )
320
+ end
321
+
322
+ # Rotate this Ftor in-place by +angle+ (radians). This is the same as
323
+ # adding +angle+ to this Ftor's #angle.
324
+ #
325
+ #--
326
+ # , with one important difference:
327
+ # This method will be much more efficient when rotating at a right angle,
328
+ # i.e.rotating by any multiple of PI/2 radians from -2*PI to 2*PI radians.
329
+ #
330
+ # For convenience, and to ensure exactitude, several numerical constants
331
+ # have been defined for multiples of PI/2:
332
+ # * Ftor::PI:: (same as Math::PI)
333
+ # * Ftor::HALF_PI:: PI * 0.5 (or PI/2)
334
+ # * Ftor::THREE_HALF_PI:: PI * 1.5 (or 3*PI/2)
335
+ # * Ftor::TWO_PI:: PI * 2
336
+ #++
337
+ #
338
+ # *IMPORTANT*: Positive rotation will appear *clockwise*, and negative
339
+ # rotation will appear *counterclockwise*! See #angle for the reason.
340
+ def rotate!(angle)
341
+ # case(angle)
342
+ # when HALF_PI, -THREE_HALF_PI
343
+ # self.set!(@y,-@x)
344
+ # when THREE_HALF_PI, -HALF_PI
345
+ # self.set!(-@y,@x)
346
+ # when PI, -PI
347
+ # self.set!(@y,-@x)
348
+ # when 0, TWO_PI, -TWO_PI
349
+ # self.set!(@y,-@x)
350
+ # else
351
+ self.a += angle
352
+ # end
353
+ return self
354
+ end
355
+
356
+ # Like #rotate!, but returns a duplicate instead of rotating this Ftor
357
+ # in-place.
358
+ def rotate(radians)
359
+ self.dup.rotate!(radians)
360
+ end
361
+
362
+ # Clears stored values for #angle, #magnitude, #normal, and #unit,
363
+ # so that they will be recalculated the next time they are needed.
364
+ # Intended for internal use, but might be useful in other situations.
365
+ def _clear
366
+ @angle = nil
367
+ @magnitude = nil
368
+ @normal = nil
369
+ @unit = nil
370
+ return self
371
+ end
372
+ end