gamebox 0.1.1 → 0.2.1

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 (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
@@ -4,7 +4,7 @@ require 'actor_view'
4
4
  describe 'A new actor view' do
5
5
 
6
6
  it 'should be layered 0/1 by default' do
7
- @test_me = ActorView.new :stage, Actor.new({})
7
+ @test_me = ActorView.new :stage, Actor.new({}), :wrapped_screen
8
8
  @test_me.layer.should == 0
9
9
  @test_me.parallax.should == 1
10
10
  end
@@ -0,0 +1,264 @@
1
+ require File.join(File.dirname(__FILE__),'helper')
2
+ require 'arbiter'
3
+
4
+ class Arb
5
+ include Arbiter
6
+ end
7
+
8
+ describe 'Arbiter' do
9
+
10
+ before do
11
+ @arbiter = Arb.new
12
+ end
13
+
14
+ it 'should construct' do
15
+ @arbiter.should_not be_nil
16
+ end
17
+
18
+ describe '#center_x' do
19
+ it 'should return the center x for circle'
20
+ it 'should return the center x for aabb'
21
+ it 'should return the center x for polygon'
22
+ end
23
+
24
+ describe '#center_y' do
25
+ it 'should return the center y for circle'
26
+ it 'should return the center y for aabb'
27
+ it 'should return the center y for polygon'
28
+ end
29
+
30
+ describe '#collide?' do
31
+ it 'should call the correct circle circle collision method' do
32
+ a = stub(:collidable_shape => :circle)
33
+ b = stub(:collidable_shape => :circle)
34
+ @arbiter.should_receive(:collide_circle_circle?).with(a,b).and_return(true)
35
+
36
+ @arbiter.collide?(a,b).should be_true
37
+ end
38
+
39
+ it 'should call the correct circle polygon collision method' do
40
+ a = stub(:collidable_shape => :circle)
41
+ b = stub(:collidable_shape => :polygon)
42
+ @arbiter.should_receive(:collide_circle_polygon?).with(a,b).and_return(true)
43
+
44
+ @arbiter.collide?(a,b).should be_true
45
+ end
46
+
47
+ it 'should call the correct polygon circle collision method' do
48
+ a = stub(:collidable_shape => :polygon)
49
+ b = stub(:collidable_shape => :circle)
50
+ @arbiter.should_receive(:collide_circle_polygon?).with(b,a).and_return(true)
51
+
52
+ @arbiter.collide?(a,b).should be_true
53
+ end
54
+ end
55
+
56
+ describe '#collide_circle_circle?' do
57
+ it 'should collide overlapping circles' do
58
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :circle)
59
+ b = stub(:center_x => 0, :center_y => 10, :radius => 3, :collidable_shape => :circle)
60
+ @arbiter.collide_circle_circle?(a, b).should be_true
61
+ end
62
+
63
+ it 'should collide a circle in a circle' do
64
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :circle)
65
+ b = stub(:center_x => 10, :center_y => 10, :radius => 30, :collidable_shape => :circle)
66
+ @arbiter.collide_circle_circle?(a, b).should be_true
67
+ end
68
+
69
+ it 'should not collide non-overlapping circles' do
70
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :circle)
71
+ b = stub(:center_x => 100, :center_y => 100, :radius => 30, :collidable_shape => :circle)
72
+ @arbiter.collide_circle_circle?(a, b).should be_false
73
+ end
74
+ end
75
+
76
+ describe '#collide_polygon_polygon?' do
77
+ it 'should not collide non-overlapping polys based on radius' do
78
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :polygon)
79
+ b = stub(:center_x => 61, :center_y => 0, :radius => 30, :collidable_shape => :polygon)
80
+ @arbiter.collide_polygon_polygon?(a,b).should be_false
81
+ end
82
+
83
+ it 'should not collide non-overlapping polys based on points' do
84
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :polygon,
85
+ :cw_world_points => [
86
+ [0,0],[0,30], [0,30]
87
+ ],
88
+ :cw_world_lines => [
89
+ [0,0],[0,30],
90
+ [0,30],[30,0],
91
+ [30,0],[0,0]
92
+ ],
93
+ :cw_world_edge_normals => [
94
+ [-30,0],
95
+ [30,30],
96
+ [0,-30]
97
+ ]
98
+
99
+ )
100
+ b = stub(:center_x => 60, :center_y => 0, :radius => 30, :collidable_shape => :polygon,
101
+ :cw_world_points => [
102
+ [60,0],[60,30], [90,0]
103
+ ],
104
+ :cw_world_lines => [
105
+ [60,0],[60,30],
106
+ [60,30],[90,0],
107
+ [90,0],[60,0]
108
+ ],
109
+ :cw_world_edge_normals => [
110
+ [-30,0],
111
+ [30,30],
112
+ [0,-30]
113
+ ]
114
+ )
115
+ @arbiter.collide_polygon_polygon?(a,b).should be_false
116
+ end
117
+
118
+ it 'should collide non-overlapping polys based on points' do
119
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :polygon,
120
+ :cw_world_points => [
121
+ [0,0],[0,30],[30,0]
122
+ ],
123
+ :cw_world_lines => [
124
+ [0,0],[0,30],
125
+ [0,30],[30,0],
126
+ [30,0],[0,0]
127
+ ],
128
+ :cw_world_edge_normals => [
129
+ [30,0],
130
+ [30,30],
131
+ [0,-30]
132
+ ]
133
+ )
134
+ b = stub(:center_x => 29, :center_y => 0, :radius => 30, :collidable_shape => :polygon,
135
+ :cw_world_points => [
136
+ [29,0],[29,30],[59,0]
137
+ ],
138
+ :cw_world_lines => [
139
+ [29,0],[29,30],
140
+ [29,30],[59,0],
141
+ [59,0],[29,0]
142
+ ],
143
+ :cw_world_edge_normals => [
144
+ [-30,0],
145
+ [30,30],
146
+ [0,-30]
147
+ ]
148
+ )
149
+ @arbiter.collide_polygon_polygon?(a,b).should be_true
150
+ end
151
+
152
+ it 'should collide completely overlapping polys based on points' do
153
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :polygon,
154
+ :cw_world_points => [
155
+ [0,0],[0,30],[30,0]
156
+ ],
157
+ :cw_world_lines => [
158
+ [0,0],[0,30],
159
+ [0,30],[30,0],
160
+ [30,0],[0,0]
161
+ ],
162
+ :cw_world_edge_normals => [
163
+ [30,0],
164
+ [30,30],
165
+ [0,-30]
166
+ ]
167
+ )
168
+ b = stub(:center_x => 2, :center_y => 0, :radius => 10, :collidable_shape => :polygon,
169
+ :cw_world_points => [[10,0],[10,20],[20,0]],
170
+ :cw_world_lines => [
171
+ [10,0],[10,20],
172
+ [10,20],[20,0],
173
+ [20,0],[10,0]
174
+ ],
175
+ :cw_world_edge_normals => [
176
+ [-20,0],
177
+ [-10,-20],
178
+ [0,-10]
179
+ ]
180
+ )
181
+ @arbiter.collide_polygon_polygon?(a,b).should be_true
182
+ end
183
+ end
184
+
185
+ describe '#collide_circle_polygon?' do
186
+ it 'should collide overlapping circle and polygon' do
187
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :circle)
188
+ b = stub(:center_x => 2, :center_y => 0, :radius => 10, :collidable_shape => :polygon,
189
+ :cw_world_points => [[10,0],[10,20],[20,0]],
190
+ :cw_world_lines => [
191
+ [10,0],[10,20],
192
+ [10,20],[20,0],
193
+ [20,0],[10,0]
194
+ ],
195
+ :cw_world_edge_normals => [
196
+ [-20,0],
197
+ [-10,-20],
198
+ [0,-10]
199
+ ]
200
+ )
201
+ @arbiter.collide_circle_polygon?(a, b).should be_true
202
+ end
203
+
204
+ it 'should not collide overlapping circle and polygon' do
205
+ a = stub(:center_x => 0, :center_y => 0, :radius => 30, :collidable_shape => :circle)
206
+ b = stub(:center_x => 200, :center_y => 0, :radius => 10, :collidable_shape => :polygon,
207
+ :cw_world_points => [[10,0],[10,20],[20,0]],
208
+ :cw_world_lines => [
209
+ [208,0],[208,20],
210
+ [208,20],[218,0],
211
+ [218,0],[208,0]
212
+ ],
213
+ :cw_world_edge_normals => [
214
+ [-20,0],
215
+ [-10,-20],
216
+ [0,-10]
217
+ ]
218
+ )
219
+ @arbiter.collide_circle_polygon?(a, b).should be_false
220
+ end
221
+ end
222
+
223
+ describe '#collide_aabb_aabb' do
224
+ it 'should collide overlapping boxes' do
225
+ a = stub(:center_x => 0, :center_y => 0, :width => 30, :height => 20,
226
+ :collidable_shape => :aabb, :radius => 10,
227
+ :cw_world_points => [
228
+ [-15,10],[15,10],
229
+ [15,-10], [-15,10]
230
+ ],
231
+ :cw_world_lines => [
232
+ [[-15,10],[15,10]],
233
+ [[15,10],[15,-10]],
234
+ [[15,-10],[-15,10]],
235
+ [[-15,10],[-15,10]]
236
+ ],
237
+ :cw_world_edge_normals => [[1,0],[0,1]])
238
+ b = stub(:center_x => 5, :center_y => 5, :width => 10, :height => 2,
239
+ :collidable_shape => :aabb, :radius => 10,
240
+ :cw_world_points => [
241
+ [0,6],[10,6],
242
+ [10,4], [0,6]
243
+ ],
244
+ :cw_world_lines => [
245
+ [[0,6],[10,6]],
246
+ [[10,6],[10,4]],
247
+ [[10,4],[0,6]],
248
+ [[0,6],[0,6]]
249
+ ],
250
+ :cw_world_edge_normals => [[1,0],[0,1]])
251
+
252
+ @arbiter.collide_aabb_aabb?(a,b).should be_true
253
+ end
254
+ end
255
+
256
+ describe '#collide_aabb_circle' do
257
+ it 'should collide overlapping box and circle'
258
+ end
259
+
260
+ describe "#find_collisions" do
261
+ it "runs callbacks w/ unique collisions"
262
+ end
263
+
264
+ end
@@ -2,10 +2,27 @@ require File.join(File.dirname(__FILE__),'helper')
2
2
  require 'behavior'
3
3
 
4
4
  describe 'A new behavior' do
5
+ before do
6
+ @actor = stub
7
+ @target = Behavior.new @actor
8
+ end
9
+
10
+ it 'should auto-require behaviors that it depends on'
11
+ it 'should relegate properly' do
12
+ @target.should_receive(:foo).and_return(:bar)
13
+ @target.relegates :foo
14
+
15
+ @actor.foo.should == :bar
16
+ end
5
17
 
6
- it 'should auto-require behaviors that it depends on' do
7
- actor = mock()
18
+ it 'should un-relegate properly' do
19
+ @target.should_receive(:foo).and_return(:bar)
20
+ @target.relegates :foo
21
+ @actor.foo.should == :bar
22
+
23
+ @target.removed
8
24
 
25
+ @actor.respond_to?(:foo).should be_false
9
26
  end
10
27
 
11
28
  end
@@ -4,12 +4,112 @@ require 'collidable'
4
4
  describe 'A new collidable behavior' do
5
5
  before do
6
6
  @stage = mock(:register_collidable => nil)
7
- opts = {:actor_type => :actor, :stage=>@stage, :input=>"input", :resources=> :rm}
8
- @actor = Actor.new opts
9
- @collidable = Collidable.new @actor
7
+ @actor_opts = {:actor_type => :actor, :stage=>@stage, :input=>"input", :resources=> :rm}
8
+ @actor = Actor.new @actor_opts
10
9
  end
11
10
 
12
- it 'should define methods on actor' do
13
- @actor.respond_to?(:shape).should be_true
11
+
12
+ describe "circle shape" do
13
+ before do
14
+ @behavior_opts = {:shape => :circle}
15
+ @collidable = Collidable.new @actor, @behavior_opts
16
+ end
17
+
18
+ it 'should recalculate_collidable_cache on update' do
19
+ @collidable.shape.should_receive(:recalculate_collidable_cache)
20
+ @collidable.update 4
21
+ end
22
+
23
+ it 'should relegate methods on actor' do
24
+ @collidable.should_receive(:width).and_return(44)
25
+ @actor.width.should == 44
26
+ @collidable.should_receive(:height).and_return(45)
27
+ @actor.height.should == 45
28
+
29
+ @collidable.should_receive(:collidable_shape).and_return(:circlez)
30
+ @actor.collidable_shape.should == :circlez
31
+ end
32
+
33
+ it 'should calculate center point for circle' do
34
+ @actor.x = 3
35
+ @actor.y = 6
36
+ @collidable = Collidable.new @actor, :shape => :circle, :radius => 20
37
+ @collidable.center_x.should be_close(23, 0.001)
38
+ @collidable.center_y.should be_close(26, 0.001)
39
+ end
14
40
  end
41
+
42
+ describe "polygon shape" do
43
+ it 'should calculate center point for polygon' do
44
+ @collidable = Collidable.new @actor, :shape => :polygon, :points => [[0,0],[10,7],[20,10]]
45
+ @collidable.center_x.should be_close(10, 0.001)
46
+ @collidable.center_y.should be_close(5, 0.001)
47
+ end
48
+
49
+ it 'should translate points to world coords for poly' do
50
+ @actor.x = 10
51
+ @actor.y = 5
52
+ @collidable = Collidable.new @actor, :shape => :polygon, :points => [[0,0],[10,7],[20,10]]
53
+ @collidable.cw_world_points.should == [[10,5],[20,12],[30,15]]
54
+ end
55
+
56
+ it 'should translate lines to world coords lines' do
57
+ @collidable = Collidable.new @actor, :shape => :polygon, :points => [[0,0],[10,7],[20,10]]
58
+
59
+ @collidable.cw_world_lines.should == [
60
+ [[0,0],[10,7]],
61
+ [[10,7],[20,10]],
62
+ [[20,10],[0,0]]
63
+ ]
64
+ end
65
+
66
+ it 'should translate world lines to edge normals' do
67
+ @collidable = Collidable.new @actor, :shape => :polygon,
68
+ :points => [[0,0],[10,7],[20,10]]
69
+
70
+ @collidable.cw_world_edge_normals.should == [
71
+ [-7,10], [-3,10], [10,-20]
72
+ ]
73
+ end
74
+
75
+ it 'should cache calcs until reset' do
76
+ @collidable = Collidable.new @actor, :shape => :polygon,
77
+ :points => [[0,0],[10,7],[20,10]]
78
+ # prime the cache
79
+ @collidable.cw_world_points.should == [[0,0],[10,7],[20,10]]
80
+ @collidable.cw_world_lines.should == [
81
+ [[0,0],[10,7]],
82
+ [[10,7],[20,10]],
83
+ [[20,10],[0,0]]
84
+ ]
85
+ @collidable.cw_world_edge_normals.should == [
86
+ [-7,10], [-3,10], [10,-20]
87
+ ]
88
+
89
+ @actor.x = 10
90
+ @actor.y = 5
91
+ @collidable.cw_world_points.should == [[0,0],[10,7],[20,10]]
92
+ @collidable.cw_world_lines.should == [
93
+ [[0,0],[10,7]],
94
+ [[10,7],[20,10]],
95
+ [[20,10],[0,0]]
96
+ ]
97
+ @collidable.cw_world_edge_normals.should == [
98
+ [-7,10], [-3,10], [10,-20]
99
+ ]
100
+
101
+ @collidable.clear_collidable_cache
102
+ @collidable.cw_world_points.should == [[10,5],[20,12],[30,15]]
103
+ @collidable.cw_world_lines.should == [
104
+ [[10,5],[20,12]],
105
+ [[20,12],[30,15]],
106
+ [[30,15],[10,5]]
107
+ ]
108
+ @collidable.cw_world_edge_normals.should == [
109
+ [-7,10], [-3,10], [10,-20]
110
+ ]
111
+
112
+ end
113
+ end
114
+
15
115
  end
@@ -2,7 +2,7 @@ here = File.dirname(__FILE__)
2
2
  gamebox_root = File.expand_path(File.join(here, '..', 'lib'))
3
3
 
4
4
  #$LOAD_PATH.unshift File.expand_path(gamebox_root, 'gamebox')
5
- require 'rubygems'
5
+ require File.expand_path(File.join(here, '..', 'load_paths'))
6
6
  require 'spec'
7
7
 
8
8
  # TODO this lives in both gamebox.rb and here... seems strange
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require File.join(File.dirname(__FILE__),'helper')
2
2
  require 'label'
3
3
 
4
4
  describe 'a new Label' do
@@ -3,7 +3,7 @@ require 'resource_manager'
3
3
 
4
4
  describe 'A new resource manager' do
5
5
  before do
6
- @res_man = ResourceManager.new
6
+ @res_man = ResourceManager.new :wrapped_screen => stub(:screen => :fake_gosu)
7
7
  end
8
8
 
9
9
  it 'should load an actor image' do
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require File.join(File.dirname(__FILE__),'helper')
2
2
  require 'spatial_hash'
3
3
 
4
4
  describe 'a new SpacialHash' do