gamebox 0.4.0.rc5 → 0.4.0.rc11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/README.md +205 -127
  2. data/bin/gamebox +49 -3
  3. data/bin/gb +87 -0
  4. data/gamebox.gemspec +4 -3
  5. data/lib/gamebox.rb +1 -1
  6. data/lib/gamebox/actors/collidable_debugger.rb +4 -4
  7. data/lib/gamebox/actors/icon.rb +7 -0
  8. data/lib/gamebox/actors/label.rb +41 -42
  9. data/lib/gamebox/behaviors/animated.rb +6 -0
  10. data/lib/gamebox/behaviors/audible.rb +1 -2
  11. data/lib/gamebox/behaviors/collidable.rb +1 -1
  12. data/lib/gamebox/behaviors/graphical.rb +8 -4
  13. data/lib/gamebox/behaviors/physical.rb +6 -1
  14. data/lib/gamebox/behaviors/positioned.rb +4 -11
  15. data/lib/gamebox/behaviors/projectile.rb +8 -0
  16. data/lib/gamebox/behaviors/visible.rb +3 -3
  17. data/lib/gamebox/core/aabb_tree.rb +1 -1
  18. data/lib/gamebox/core/actor.rb +37 -50
  19. data/lib/gamebox/core/actor_definition.rb +41 -0
  20. data/lib/gamebox/core/actor_view.rb +6 -21
  21. data/lib/gamebox/core/actor_view_definition.rb +19 -0
  22. data/lib/gamebox/core/actor_view_factory.rb +9 -3
  23. data/lib/gamebox/core/behavior.rb +8 -27
  24. data/lib/gamebox/core/behavior_definition.rb +24 -0
  25. data/lib/gamebox/core/config_manager.rb +45 -30
  26. data/lib/gamebox/core/configuration.rb +5 -0
  27. data/lib/gamebox/core/core.rb +4 -0
  28. data/lib/gamebox/core/debug_helpers.rb +46 -0
  29. data/lib/gamebox/core/director.rb +32 -5
  30. data/lib/gamebox/core/event_symbols.rb +214 -0
  31. data/lib/gamebox/core/game.rb +1 -1
  32. data/lib/gamebox/core/input_manager.rb +1 -4
  33. data/lib/gamebox/core/input_mapper.rb +85 -0
  34. data/lib/gamebox/core/physics.rb +7 -3
  35. data/lib/gamebox/core/physics_manager.rb +5 -1
  36. data/lib/gamebox/core/renderer.rb +72 -0
  37. data/lib/gamebox/core/stage.rb +25 -81
  38. data/lib/gamebox/core/stage_definition.rb +60 -0
  39. data/lib/gamebox/core/stage_factory.rb +56 -0
  40. data/lib/gamebox/core/stage_manager.rb +5 -11
  41. data/lib/gamebox/core/timer_manager.rb +6 -2
  42. data/lib/gamebox/core/viewport.rb +12 -5
  43. data/lib/gamebox/core/wrapped_screen.rb +8 -5
  44. data/lib/gamebox/gamebox_application.rb +21 -19
  45. data/lib/gamebox/lib/array_ext.rb +9 -0
  46. data/lib/gamebox/lib/observable_attributes.rb +24 -0
  47. data/lib/gamebox/lib/vector2.rb +432 -0
  48. data/lib/gamebox/post_setup_handlers/file_watcher.rb +37 -0
  49. data/lib/gamebox/post_setup_handlers/gamebox_debug_helpers.rb +13 -0
  50. data/lib/gamebox/post_setup_handlers/pry_remote_server.rb +29 -0
  51. data/lib/gamebox/spec/helper.rb +165 -17
  52. data/lib/gamebox/tasks/gamebox_tasks.rake +27 -12
  53. data/lib/gamebox/version.rb +1 -1
  54. data/lib/gamebox/views/graphical_actor_view.rb +4 -5
  55. data/script/perf_aabb.rb +13 -8
  56. data/spec/acceptance/animation_spec.rb +1 -3
  57. data/spec/acceptance/basic_actor_lifecycle_spec.rb +1 -1
  58. data/spec/acceptance/fps_actor_spec.rb +8 -12
  59. data/spec/acceptance/input_mapper_spec.rb +17 -24
  60. data/spec/acceptance/update_ordering_spec.rb +64 -0
  61. data/spec/actors/label_spec.rb +90 -5
  62. data/spec/behaviors/animated_spec.rb +1 -1
  63. data/spec/behaviors/collidable_spec.rb +7 -15
  64. data/spec/behaviors/positioned_spec.rb +12 -5
  65. data/spec/core/actor_spec.rb +31 -3
  66. data/spec/core/actor_view_spec.rb +1 -1
  67. data/spec/core/behavior_spec.rb +3 -0
  68. data/spec/core/configuration_spec.rb +49 -2
  69. data/spec/core/input_mapper_spec.rb +7 -0
  70. data/spec/core/renderer_spec.rb +89 -0
  71. data/spec/core/stage_definition_spec.rb +41 -0
  72. data/spec/core/stage_manager_spec.rb +11 -11
  73. data/spec/core/stage_spec.rb +38 -78
  74. data/spec/core/viewport_spec.rb +5 -2
  75. data/spec/core/wrapped_screen_spec.rb +18 -12
  76. data/spec/views/graphical_actor_view_spec.rb +33 -62
  77. data/templates/actor_template.erb +11 -0
  78. data/templates/app/README.md +1 -0
  79. data/templates/app/src/actors/{player.rb → player_actor.rb} +3 -1
  80. data/templates/app/src/behaviors/.gitkeep +0 -0
  81. data/templates/app/src/stages/demo_stage.rb +14 -0
  82. data/templates/behavior_template.erb +13 -0
  83. data/templates/stage_template.erb +13 -0
  84. metadata +60 -21
  85. data/component_generators/actor_generator.rb +0 -17
  86. data/lib/gamebox/actors/emitter.rb +0 -12
  87. data/lib/gamebox/behaviors/emitting.rb +0 -48
  88. data/lib/gamebox/behaviors/input_mapper.rb +0 -11
  89. data/lib/gamebox/lib/ftor.rb +0 -372
  90. data/spec/actors/emitter_spec.rb +0 -5
  91. data/templates/app/NEXT_STEPS.txt +0 -1
  92. data/templates/app/README.rdoc +0 -24
  93. data/templates/app/src/demo_stage.rb +0 -7
@@ -1,17 +0,0 @@
1
- # class GameboxGenerator < RubiGen::Base
2
- # def manifest
3
- # record do |m|
4
- # # Root directory and all subdirectories.
5
- # m.directory ''
6
- # BASEDIRS.each { |path| m.directory path }
7
- # binding.pry
8
- # m.template 'actor.erb', "src/actors/#{name}.rb",
9
- # m.template 'actor_spec.erb', "spec/actors/#{name}_spec.rb",
10
- # end
11
- # end
12
- # BASEDIRS = %w(
13
- # src/actors
14
- # spec/actors
15
- # )
16
- # end
17
- #
@@ -1,12 +0,0 @@
1
- # actor used for particle emissions
2
- Actor.define :emitter do
3
- # options:
4
- # delay: ms to wait between creating more particles
5
- # particle_actor: actor to spawn as particle
6
- # particle_opts: opts to be passed to the spawned particle
7
- # ttl: ms to live (optional, will live forever if omitted)
8
- # spawn_variance: dist in pixels to spawn away from emitter (default -10..10)
9
- # location_tween: tween object that will be used to move the emitter (optional)
10
- # follow: actor to follow (optional)
11
- has_behavior :emitting
12
- end
@@ -1,48 +0,0 @@
1
- Behavior.define :emitting do
2
- # options:
3
- # delay: ms to wait between creating more particles
4
- # particle_actor: actor to spawn as particle
5
- # particle_opts: opts to be passed to the spawned particle
6
- # ttl: ms to live (optional, will live forever if omitted)
7
- # spawn_variance: dist in pixels to spawn away from emitter (default -10..10)
8
- # location_tween: tween object that will be used to move the emitter (optional)
9
- # follow: actor to follow (optional)
10
- requires :stage
11
- setup do
12
- # TODO which opts do we want from actor and which from behavior?
13
- opts = actor.opts
14
- variance = opts[:spawn_variance] || (-10..10)
15
-
16
- spawn_timer = "#{self.object_id}_spawn"
17
- self.when :remove_me do
18
- stage.remove_timer spawn_timer
19
- end
20
- stage.add_timer spawn_timer, opts[:delay] do
21
- spawn_x = self.x + variance.sample
22
- spawn_y = self.y + variance.sample
23
-
24
- stage.spawn opts[:particle_actor], {x: spawn_x, y: spawn_y}.merge(opts[:particle_opts])
25
- end
26
- ttl = opts[:ttl]
27
- if ttl
28
- suicide_timer = "#{self.object_id}_ttl"
29
- stage.add_timer suicide_timer, ttl do
30
- stage.remove_timer suicide_timer
31
- actor.remove
32
- end
33
- end
34
-
35
- target = opts[:follow]
36
- if target
37
- self.x = target.x
38
- self.y = target.y
39
- target.when :x_changed do
40
- self.x = target.x
41
- end
42
- target.when :y_changed do
43
- self.y = target.y
44
- end
45
- end
46
-
47
- end
48
- end
@@ -1,11 +0,0 @@
1
- define_behavior :input_mapper do
2
- requires :input_manager
3
-
4
- setup do
5
- opts.each do |keys, attr_name|
6
- actor.has_attribute attr_name, false
7
- input_manager.while_pressed keys, actor, attr_name
8
- end
9
- end
10
- end
11
-
@@ -1,372 +0,0 @@
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