gosling 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ describe Gosling::Circle do
2
+ before(:all) do
3
+ @window = Gosu::Window.new(640, 480, false)
4
+ @circle = Gosling::Circle.new(@window)
5
+ end
6
+
7
+ it 'has a radius' do
8
+ expect(@circle.radius).to be_kind_of(Numeric)
9
+ @circle.radius = 13
10
+ expect(@circle.radius).to be == 13
11
+ end
12
+
13
+ it 'radius must be 0 or more' do
14
+ expect { @circle.radius = 0 }.not_to raise_error
15
+ expect { @circle.radius = -13 }.to raise_error(ArgumentError)
16
+ end
17
+
18
+ describe '#get_point_at_angle' do
19
+ it 'accepts an angle in radians' do
20
+ expect { @circle.get_point_at_angle(Math::PI) }.not_to raise_error
21
+ expect { @circle.get_point_at_angle(-1) }.not_to raise_error
22
+ expect { @circle.get_point_at_angle(0) }.not_to raise_error
23
+ expect { @circle.get_point_at_angle(1) }.not_to raise_error
24
+
25
+ expect { @circle.get_point_at_angle('PI') }.to raise_error(ArgumentError)
26
+ expect { @circle.get_point_at_angle(:foo) }.to raise_error(ArgumentError)
27
+ end
28
+
29
+ it 'returns a size three vector' do
30
+ result = @circle.get_point_at_angle(Math::PI)
31
+ expect(result).to be_instance_of(Vector)
32
+ expect(result.size).to be == 3
33
+ end
34
+
35
+ it 'returns a point on this circle in local-space' do
36
+ @circle.radius = 7
37
+
38
+ angles = (0...16).map { |x| Math::PI * x / 8 }
39
+ unit_vectors = angles.map { |a| Vector[Math.cos(a), Math.sin(a), 0] }
40
+
41
+ angles.each_index do |i|
42
+ angle = angles[i]
43
+ unit_vector = unit_vectors[i]
44
+ expect(@circle.get_point_at_angle(angle)).to be == unit_vector * @circle.radius
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,1183 @@
1
+ require 'set'
2
+
3
+ def clean_shape(shape)
4
+ shape.x = 0
5
+ shape.y = 0
6
+ shape.center_x = 0
7
+ shape.center_y = 0
8
+ shape.scale_x = 1
9
+ shape.scale_y = 1
10
+ shape.rotation = 0
11
+ end
12
+
13
+ def clean_rect(rect)
14
+ rect.x = 0
15
+ rect.y = 0
16
+ rect.center_x = 5
17
+ rect.center_y = 5
18
+ rect.scale_x = 1
19
+ rect.scale_y = 1
20
+ rect.rotation = 0
21
+ end
22
+
23
+ def clean_sprite(sprite)
24
+ sprite.x = 0
25
+ sprite.y = 0
26
+ sprite.center_x = 8
27
+ sprite.center_y = 8
28
+ sprite.scale_x = 1
29
+ sprite.scale_y = 1
30
+ sprite.rotation = 0
31
+ end
32
+
33
+ def create_inheritance_chain(ancestry)
34
+ (1...ancestry.length).each do |i|
35
+ ancestry[i-1].add_child(ancestry[i])
36
+ end
37
+ end
38
+
39
+ def break_inheritance_chain(ancestry)
40
+ ancestry.each do |actor|
41
+ actor.parent.remove_child(actor) if actor.parent
42
+ end
43
+ end
44
+
45
+ describe Gosling::Collision do
46
+ before(:all) do
47
+ @window = Gosu::Window.new(640, 480, false)
48
+ @local_path = File.dirname(__FILE__)
49
+ @image = Gosling::ImageLibrary.get(File.join(@local_path, 'images/nil.png'))
50
+
51
+ @actor1 = Gosling::Actor.new(@window)
52
+
53
+ @actor2 = Gosling::Actor.new(@window)
54
+
55
+ @circle1 = Gosling::Circle.new(@window)
56
+ @circle1.radius = 5
57
+
58
+ @circle2 = Gosling::Circle.new(@window)
59
+ @circle2.radius = 5
60
+
61
+ @polygon1 = Gosling::Polygon.new(@window)
62
+ @polygon1.set_vertices([
63
+ Vector[ 0, 5, 0],
64
+ Vector[ 5, -5, 0],
65
+ Vector[-5, -5, 0]
66
+ ])
67
+
68
+ @polygon2 = Gosling::Polygon.new(@window)
69
+ @polygon2.set_vertices([
70
+ Vector[ 0, -5, 0],
71
+ Vector[ 5, 5, 0],
72
+ Vector[-5, 5, 0]
73
+ ])
74
+
75
+ @rect1 = Gosling::Rect.new(@window)
76
+ @rect1.width = 10
77
+ @rect1.height = 10
78
+ @rect1.center_x = 5
79
+ @rect1.center_y = 5
80
+
81
+ @rect2 = Gosling::Rect.new(@window)
82
+ @rect2.width = 10
83
+ @rect2.height = 10
84
+ @rect2.center_x = 5
85
+ @rect2.center_y = 5
86
+ @rect2.rotation = Math::PI / 4
87
+
88
+ @sprite1 = Gosling::Sprite.new(@window)
89
+ @sprite1.set_image(@image)
90
+ @sprite1.center_x = 8
91
+ @sprite1.center_y = 8
92
+
93
+ @sprite2 = Gosling::Sprite.new(@window)
94
+ @sprite2.set_image(@image)
95
+ @sprite2.center_x = 8
96
+ @sprite2.center_y = 8
97
+
98
+ @center_actor = Gosling::Actor.new(@window)
99
+ @center_actor.center_x = 5
100
+ @center_actor.center_y = 5
101
+
102
+ @scale_actor = Gosling::Actor.new(@window)
103
+ @scale_actor.scale_x = 3.5
104
+ @scale_actor.scale_y = 2.5
105
+
106
+ @rotate_actor = Gosling::Actor.new(@window)
107
+ @rotate_actor.rotation = Math::PI * -0.5
108
+
109
+ @translate_actor = Gosling::Actor.new(@window)
110
+ @translate_actor.x = 128
111
+ @translate_actor.y = 256
112
+ end
113
+
114
+ describe '#test' do
115
+ context 'any actor vs. itself' do
116
+ it 'never collides' do
117
+ [@actor1, @circle1, @polygon1, @rect1, @sprite1].each do |actor|
118
+ expect(Gosling::Collision.test(actor, actor)).to be false
119
+ end
120
+ end
121
+ end
122
+
123
+ context 'actor vs. actor' do
124
+ it 'never collides' do
125
+ expect(Gosling::Collision.test(@actor1, @actor2)).to be false
126
+ end
127
+ end
128
+
129
+ context 'actor vs. circle' do
130
+ it 'never collides' do
131
+ expect(Gosling::Collision.test(@actor1, @circle1)).to be false
132
+ end
133
+ end
134
+
135
+ context 'actor vs. polygon' do
136
+ it 'never collides' do
137
+ expect(Gosling::Collision.test(@actor1, @polygon1)).to be false
138
+ end
139
+ end
140
+
141
+ context 'actor vs. rect' do
142
+ it 'never collides' do
143
+ expect(Gosling::Collision.test(@actor1, @rect1)).to be false
144
+ end
145
+ end
146
+
147
+ context 'actor vs. sprite' do
148
+ it 'never collides' do
149
+ expect(Gosling::Collision.test(@actor1, @sprite1)).to be false
150
+ end
151
+ end
152
+
153
+ context 'circle vs. circle' do
154
+ it 'collides if the shapes are close enough' do
155
+ clean_shape(@circle1)
156
+ @circle1.x = 0
157
+ @circle1.y = 0
158
+
159
+ clean_shape(@circle2)
160
+ @circle2.x = 5
161
+ @circle2.y = 5
162
+
163
+ expect(Gosling::Collision.test(@circle1, @circle2)).to be true
164
+ end
165
+
166
+ it 'does not collide if the shapes are far apart' do
167
+ clean_shape(@circle1)
168
+ @circle1.x = 0
169
+ @circle1.y = 0
170
+
171
+ clean_shape(@circle2)
172
+ @circle2.x = 10
173
+ @circle2.y = 5
174
+
175
+ expect(Gosling::Collision.test(@circle1, @circle2)).to be false
176
+ end
177
+ end
178
+
179
+ context 'circle vs. polygon' do
180
+ it 'collides if the shapes are close enough' do
181
+ clean_shape(@circle1)
182
+ @circle1.x = 0
183
+ @circle1.y = 0
184
+
185
+ clean_shape(@polygon1)
186
+ @polygon1.x = 5
187
+ @polygon1.y = 5
188
+
189
+ expect(Gosling::Collision.test(@circle1, @polygon1)).to be true
190
+ end
191
+
192
+ it 'does not collide if the shapes are far apart' do
193
+ clean_shape(@circle1)
194
+ @circle1.x = 0
195
+ @circle1.y = 0
196
+
197
+ clean_shape(@polygon1)
198
+ @polygon1.x = 10
199
+ @polygon1.y = 10
200
+
201
+ expect(Gosling::Collision.test(@circle1, @polygon1)).to be false
202
+ end
203
+ end
204
+
205
+ context 'circle vs. rect' do
206
+ it 'collides if the shapes are close enough' do
207
+ clean_shape(@circle1)
208
+ @circle1.x = 0
209
+ @circle1.y = 0
210
+
211
+ clean_rect(@rect1)
212
+ @rect1.x = 5
213
+ @rect1.y = 5
214
+
215
+ expect(Gosling::Collision.test(@circle1, @rect1)).to be true
216
+ end
217
+
218
+ it 'does not collide if the shapes are far apart' do
219
+ clean_shape(@circle1)
220
+ @circle1.x = 0
221
+ @circle1.y = 0
222
+
223
+ clean_rect(@rect1)
224
+ @rect1.x = 10
225
+ @rect1.y = 10
226
+
227
+ expect(Gosling::Collision.test(@circle1, @rect1)).to be false
228
+ end
229
+ end
230
+
231
+ context 'circle vs. sprite' do
232
+ it 'collides if the shapes are close enough' do
233
+ clean_shape(@circle1)
234
+ @circle1.x = 0
235
+ @circle1.y = 0
236
+
237
+ clean_sprite(@sprite1)
238
+ @sprite1.x = 8
239
+ @sprite1.y = 8
240
+
241
+ expect(Gosling::Collision.test(@circle1, @sprite1)).to be true
242
+ end
243
+
244
+ it 'does not collide if the shapes are far apart' do
245
+ clean_shape(@circle1)
246
+ @circle1.x = 0
247
+ @circle1.y = 0
248
+
249
+ clean_sprite(@sprite1)
250
+ @sprite1.x = 16
251
+ @sprite1.y = 16
252
+
253
+ expect(Gosling::Collision.test(@circle1, @sprite1)).to be false
254
+ end
255
+ end
256
+
257
+ context 'polygon vs. polygon' do
258
+ it 'collides if the shapes are close enough' do
259
+ clean_shape(@polygon1)
260
+ @polygon1.x = 0
261
+ @polygon1.y = 0
262
+
263
+ clean_shape(@polygon2)
264
+ @polygon2.x = 0
265
+ @polygon2.y = 5
266
+
267
+ expect(Gosling::Collision.test(@polygon1, @polygon2)).to be true
268
+ end
269
+
270
+ it 'does not collide if the shapes are far apart' do
271
+ clean_shape(@polygon1)
272
+ @polygon1.x = 0
273
+ @polygon1.y = 0
274
+
275
+ clean_shape(@polygon2)
276
+ @polygon2.x = 5
277
+ @polygon2.y = 5
278
+
279
+ expect(Gosling::Collision.test(@polygon1, @polygon2)).to be false
280
+ end
281
+ end
282
+
283
+ context 'polygon vs. rect' do
284
+ it 'collides if the shapes are close enough' do
285
+ clean_shape(@polygon1)
286
+ @polygon1.x = 0
287
+ @polygon1.y = 0
288
+
289
+ clean_rect(@rect1)
290
+ @rect1.x = 5
291
+ @rect1.y = 5
292
+
293
+ expect(Gosling::Collision.test(@polygon1, @rect1)).to be true
294
+ end
295
+
296
+ it 'does not collide if the shapes are far apart' do
297
+ clean_shape(@polygon1)
298
+ @polygon1.x = 0
299
+ @polygon1.y = 0
300
+
301
+ clean_rect(@rect1)
302
+ @rect1.x = 10
303
+ @rect1.y = 5
304
+
305
+ expect(Gosling::Collision.test(@polygon1, @rect1)).to be false
306
+ end
307
+ end
308
+
309
+ context 'polygon vs. sprite' do
310
+ it 'collides if the shapes are close enough' do
311
+ clean_shape(@polygon1)
312
+ @polygon1.x = 0
313
+ @polygon1.y = 0
314
+
315
+ clean_sprite(@sprite1)
316
+ @sprite1.x = 8
317
+ @sprite1.y = 8
318
+
319
+ expect(Gosling::Collision.test(@polygon1, @sprite1)).to be true
320
+ end
321
+
322
+ it 'does not collide if the shapes are far apart' do
323
+ clean_shape(@polygon1)
324
+ @polygon1.x = 0
325
+ @polygon1.y = 0
326
+
327
+ clean_sprite(@sprite1)
328
+ @sprite1.x = 13
329
+ @sprite1.y = 8
330
+
331
+ expect(Gosling::Collision.test(@polygon1, @sprite1)).to be false
332
+ end
333
+ end
334
+
335
+ context 'rect vs. rect' do
336
+ it 'collides if the shapes are close enough' do
337
+ clean_rect(@rect1)
338
+ @rect1.x = 0
339
+ @rect1.y = 0
340
+
341
+ clean_rect(@rect2)
342
+ @rect2.x = 5
343
+ @rect2.y = 5
344
+
345
+ expect(Gosling::Collision.test(@rect1, @rect2)).to be true
346
+ end
347
+
348
+ it 'does not collide if the shapes are far apart' do
349
+ clean_rect(@rect1)
350
+ @rect1.x = 0
351
+ @rect1.y = 0
352
+
353
+ clean_shape(@rect2)
354
+ @rect2.x = 11
355
+ @rect2.y = 5
356
+
357
+ expect(Gosling::Collision.test(@rect1, @rect2)).to be false
358
+ end
359
+ end
360
+
361
+ context 'rect vs. sprite' do
362
+ it 'collides if the shapes are close enough' do
363
+ clean_rect(@rect1)
364
+ @rect1.x = 0
365
+ @rect1.y = 0
366
+
367
+ clean_sprite(@sprite1)
368
+ @sprite1.x = 8
369
+ @sprite1.y = 8
370
+
371
+ expect(Gosling::Collision.test(@rect1, @sprite1)).to be true
372
+ end
373
+
374
+ it 'does not collide if the shapes are far apart' do
375
+ clean_rect(@rect1)
376
+ @rect1.x = 0
377
+ @rect1.y = 0
378
+
379
+ clean_sprite(@sprite1)
380
+ @sprite1.x = 16
381
+ @sprite1.y = 8
382
+
383
+ expect(Gosling::Collision.test(@rect1, @sprite1)).to be false
384
+ end
385
+ end
386
+
387
+ context 'sprite vs. sprite' do
388
+ it 'collides if the shapes are close enough' do
389
+ clean_sprite(@sprite1)
390
+ @sprite1.x = 0
391
+ @sprite1.y = 0
392
+
393
+ clean_sprite(@sprite2)
394
+ @sprite2.x = 8
395
+ @sprite2.y = 8
396
+
397
+ expect(Gosling::Collision.test(@sprite1, @sprite2)).to be true
398
+ end
399
+
400
+ it 'does not collide if the shapes are far apart' do
401
+ clean_sprite(@sprite1)
402
+ @sprite1.x = 0
403
+ @sprite1.y = 0
404
+
405
+ clean_sprite(@sprite2)
406
+ @sprite2.x = 17
407
+ @sprite2.y = 8
408
+
409
+ expect(Gosling::Collision.test(@sprite1, @sprite2)).to be false
410
+ end
411
+ end
412
+ end
413
+
414
+ describe '#is_point_in_shape?' do
415
+ it 'expects a point and an actor' do
416
+ expect { Gosling::Collision.is_point_in_shape?(Vector[0, 0, 0], @actor1) }.not_to raise_error
417
+
418
+ expect { Gosling::Collision.is_point_in_shape?(@actor1, Vector[0, 0, 0]) }.to raise_error(ArgumentError)
419
+ expect { Gosling::Collision.is_point_in_shape?(@actor1, :foo) }.to raise_error(ArgumentError)
420
+ expect { Gosling::Collision.is_point_in_shape?(:bar, Vector[0, 0, 0]) }.to raise_error(ArgumentError)
421
+ expect { Gosling::Collision.is_point_in_shape?() }.to raise_error(ArgumentError)
422
+ end
423
+
424
+ context 'point vs. actor' do
425
+ it 'never collides' do
426
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 0, 0], @actor1)).to be false
427
+ end
428
+ end
429
+
430
+ context 'point vs. circle' do
431
+ it 'returns true if point is in shape' do
432
+ clean_shape(@circle1)
433
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 0, 0], @circle1)).to be true
434
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, 0, 0], @circle1)).to be true
435
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, 0, 0], @circle1)).to be true
436
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 4, 0], @circle1)).to be true
437
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -4, 0], @circle1)).to be true
438
+ expect(Gosling::Collision.is_point_in_shape?(Vector[5, 0, 0], @circle1)).to be true
439
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-5, 0, 0], @circle1)).to be true
440
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 5, 0], @circle1)).to be true
441
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -5, 0], @circle1)).to be true
442
+ end
443
+
444
+ it 'returns false if point is not in shape' do
445
+ clean_shape(@circle1)
446
+ expect(Gosling::Collision.is_point_in_shape?(Vector[6, 0, 0], @circle1)).to be false
447
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-6, 0, 0], @circle1)).to be false
448
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 6, 0], @circle1)).to be false
449
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -6, 0], @circle1)).to be false
450
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, 4, 0], @circle1)).to be false
451
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, 4, 0], @circle1)).to be false
452
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, -4, 0], @circle1)).to be false
453
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, -4, 0], @circle1)).to be false
454
+ end
455
+ end
456
+
457
+ context 'point vs. polygon' do
458
+ it 'returns true if point is in shape' do
459
+ clean_shape(@polygon1)
460
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 0, 0], @polygon1)).to be true
461
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 4, 0], @polygon1)).to be true
462
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -4, 0], @polygon1)).to be true
463
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, -4, 0], @polygon1)).to be true
464
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, -4, 0], @polygon1)).to be true
465
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 5, 0], @polygon1)).to be true
466
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -5, 0], @polygon1)).to be true
467
+ expect(Gosling::Collision.is_point_in_shape?(Vector[5, -5, 0], @polygon1)).to be true
468
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-5, -5, 0], @polygon1)).to be true
469
+ end
470
+
471
+ it 'returns false if point is not in shape' do
472
+ clean_shape(@polygon1)
473
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 6, 0], @polygon1)).to be false
474
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -6, 0], @polygon1)).to be false
475
+ expect(Gosling::Collision.is_point_in_shape?(Vector[6, -6, 0], @polygon1)).to be false
476
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-6, -6, 0], @polygon1)).to be false
477
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, 4, 0], @polygon1)).to be false
478
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, 4, 0], @polygon1)).to be false
479
+ end
480
+ end
481
+
482
+ context 'point vs. rect' do
483
+ it 'returns true if point is in shape' do
484
+ clean_rect(@rect1)
485
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 0, 0], @rect1)).to be true
486
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, -4, 0], @rect1)).to be true
487
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -4, 0], @rect1)).to be true
488
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, -4, 0], @rect1)).to be true
489
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, 0, 0], @rect1)).to be true
490
+ expect(Gosling::Collision.is_point_in_shape?(Vector[4, 4, 0], @rect1)).to be true
491
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 4, 0], @rect1)).to be true
492
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, 4, 0], @rect1)).to be true
493
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-4, 0, 0], @rect1)).to be true
494
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-5, -5, 0], @rect1)).to be true
495
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -5, 0], @rect1)).to be true
496
+ expect(Gosling::Collision.is_point_in_shape?(Vector[5, -5, 0], @rect1)).to be true
497
+ expect(Gosling::Collision.is_point_in_shape?(Vector[5, 0, 0], @rect1)).to be true
498
+ expect(Gosling::Collision.is_point_in_shape?(Vector[5, 5, 0], @rect1)).to be true
499
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 5, 0], @rect1)).to be true
500
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-5, 5, 0], @rect1)).to be true
501
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-5, 0, 0], @rect1)).to be true
502
+ end
503
+
504
+ it 'returns false if point is not in shape' do
505
+ clean_rect(@rect1)
506
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-6, -6, 0], @rect1)).to be false
507
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -6, 0], @rect1)).to be false
508
+ expect(Gosling::Collision.is_point_in_shape?(Vector[6, -6, 0], @rect1)).to be false
509
+ expect(Gosling::Collision.is_point_in_shape?(Vector[6, 0, 0], @rect1)).to be false
510
+ expect(Gosling::Collision.is_point_in_shape?(Vector[6, 6, 0], @rect1)).to be false
511
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 6, 0], @rect1)).to be false
512
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-6, 6, 0], @rect1)).to be false
513
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-6, 0, 0], @rect1)).to be false
514
+ end
515
+ end
516
+
517
+ context 'point vs. sprite' do
518
+ it 'returns true if point is in shape' do
519
+ clean_sprite(@sprite1)
520
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 0, 0], @sprite1)).to be true
521
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-7, -7, 0], @sprite1)).to be true
522
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -7, 0], @sprite1)).to be true
523
+ expect(Gosling::Collision.is_point_in_shape?(Vector[7, -7, 0], @sprite1)).to be true
524
+ expect(Gosling::Collision.is_point_in_shape?(Vector[7, 0, 0], @sprite1)).to be true
525
+ expect(Gosling::Collision.is_point_in_shape?(Vector[7, 7, 0], @sprite1)).to be true
526
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 7, 0], @sprite1)).to be true
527
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-7, 7, 0], @sprite1)).to be true
528
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-7, 0, 0], @sprite1)).to be true
529
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-8, -8, 0], @sprite1)).to be true
530
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -8, 0], @sprite1)).to be true
531
+ expect(Gosling::Collision.is_point_in_shape?(Vector[8, -8, 0], @sprite1)).to be true
532
+ expect(Gosling::Collision.is_point_in_shape?(Vector[8, 0, 0], @sprite1)).to be true
533
+ expect(Gosling::Collision.is_point_in_shape?(Vector[8, 8, 0], @sprite1)).to be true
534
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 8, 0], @sprite1)).to be true
535
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-8, 8, 0], @sprite1)).to be true
536
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-8, 0, 0], @sprite1)).to be true
537
+ end
538
+
539
+ it 'returns false if point is not in shape' do
540
+ clean_sprite(@sprite1)
541
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-9, -9, 0], @sprite1)).to be false
542
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, -9, 0], @sprite1)).to be false
543
+ expect(Gosling::Collision.is_point_in_shape?(Vector[9, -9, 0], @sprite1)).to be false
544
+ expect(Gosling::Collision.is_point_in_shape?(Vector[9, 0, 0], @sprite1)).to be false
545
+ expect(Gosling::Collision.is_point_in_shape?(Vector[9, 9, 0], @sprite1)).to be false
546
+ expect(Gosling::Collision.is_point_in_shape?(Vector[0, 9, 0], @sprite1)).to be false
547
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-9, 9, 0], @sprite1)).to be false
548
+ expect(Gosling::Collision.is_point_in_shape?(Vector[-9, 0, 0], @sprite1)).to be false
549
+ end
550
+ end
551
+ end
552
+
553
+ describe '#get_normal' do
554
+ it 'expects a 3d vector' do
555
+ expect { Gosling::Collision.get_normal(Vector[1, 0, 0]) }.not_to raise_error
556
+ expect { Gosling::Collision.get_normal(Vector[1, 0, 1, 0]) }.to raise_error(ArgumentError)
557
+ expect { Gosling::Collision.get_normal(Vector[1, 0]) }.to raise_error(ArgumentError)
558
+ expect { Gosling::Collision.get_normal(:foo) }.to raise_error(ArgumentError)
559
+ expect { Gosling::Collision.get_normal(nil) }.to raise_error(ArgumentError)
560
+ end
561
+
562
+ it 'returns a 3d vector' do
563
+ result = Gosling::Collision.get_normal(Vector[1, 0, 0])
564
+ expect(result).to be_instance_of(Vector)
565
+ expect(result.size).to be == 3
566
+ end
567
+
568
+ it 'z value of returned vector is always 0' do
569
+ [
570
+ Vector[1, 1, 0],
571
+ Vector[-1, -1, -1],
572
+ Vector[-22, -22, 0],
573
+ Vector[-11, 13, 34],
574
+ Vector[37, -4, -15],
575
+ Vector[34, 39, -16],
576
+ Vector[-48, 23, -32],
577
+ Vector[24, -39, 42],
578
+ Vector[49, 44, -15],
579
+ Vector[27, 23, 42],
580
+ Vector[33, -25, -20],
581
+ Vector[-46, -18, 48],
582
+ ].each do |v|
583
+ expect(Gosling::Collision.get_normal(v)[2]).to be == 0
584
+ end
585
+ end
586
+
587
+ it 'raises an error when given a zero length vector' do
588
+ expect { Gosling::Collision.get_normal(Vector[0, 0, 0]) }.to raise_error(ArgumentError)
589
+ end
590
+
591
+ it 'returns a vector that is +/- 90 degrees from the original' do
592
+ [
593
+ Vector[1, 1, 0],
594
+ Vector[-1, -1, -1],
595
+ Vector[-22, -22, 0],
596
+ Vector[-11, 13, 34],
597
+ Vector[37, -4, -15],
598
+ Vector[34, 39, -16],
599
+ Vector[-48, 23, -32],
600
+ Vector[24, -39, 42],
601
+ Vector[49, 44, -15],
602
+ Vector[27, 23, 42],
603
+ Vector[33, -25, -20],
604
+ Vector[-46, -18, 48],
605
+ ].each do |v|
606
+ norm_v = Gosling::Collision.get_normal(v)
607
+ radians = Math.acos(v.inner_product(norm_v) / (v.magnitude * norm_v.magnitude))
608
+ expect(radians.abs).to be == Math::PI / 2
609
+ end
610
+ end
611
+ end
612
+
613
+ describe '#get_polygon_separation_axes' do
614
+ it 'expects an array of length 3 vectors' do
615
+ good_vector_array = [
616
+ Vector[3, 1, 0],
617
+ Vector[4, 2, 0],
618
+ Vector[5, 3, 0],
619
+ Vector[1, 4, 0],
620
+ Vector[2, 5, 0]
621
+ ]
622
+ bad_vector_array = [
623
+ Vector[9, 11],
624
+ Vector[7, 12, 0],
625
+ Vector[5, 13, 1, 0],
626
+ Vector[3, 14],
627
+ Vector[1, 15]
628
+ ]
629
+ p = Gosling::Polygon.new(@window)
630
+ expect { Gosling::Collision.get_polygon_separation_axes(good_vector_array) }.not_to raise_error
631
+ expect { Gosling::Collision.get_polygon_separation_axes(bad_vector_array) }.to raise_error(ArgumentError)
632
+ expect { Gosling::Collision.get_polygon_separation_axes(p.get_vertices) }.not_to raise_error
633
+ expect { Gosling::Collision.get_polygon_separation_axes(p) }.to raise_error(ArgumentError)
634
+ expect { Gosling::Collision.get_polygon_separation_axes(:foo) }.to raise_error(ArgumentError)
635
+ end
636
+
637
+ it 'returns an array of 3d vectors' do
638
+ vertices = [
639
+ Vector[3, 1, 0],
640
+ Vector[4, 2, 0],
641
+ Vector[5, 3, 0],
642
+ Vector[1, 4, 0],
643
+ Vector[2, 5, 0]
644
+ ]
645
+ result = Gosling::Collision.get_polygon_separation_axes(vertices)
646
+ expect(result).to be_instance_of(Array)
647
+ expect(result.reject { |v| v.is_a?(Vector) && v.size == 3 }).to be_empty
648
+ end
649
+
650
+ it 'skips length zero sides' do
651
+ vertices = [
652
+ Vector[1, 1, 0],
653
+ Vector[1, 1, 0],
654
+ Vector[1, 2, 0],
655
+ Vector[2, 2, 0],
656
+ Vector[2, 2, 0]
657
+ ]
658
+ result = Gosling::Collision.get_polygon_separation_axes(vertices)
659
+ expect(result.length).to be == 3
660
+ end
661
+
662
+ it 'returns correct values' do
663
+ vertices = [
664
+ Vector[ 2, 1, 0],
665
+ Vector[ 1, -1, 0],
666
+ Vector[ 0, -2, 0],
667
+ Vector[-1, -1, 0],
668
+ Vector[-1, 2, 0]
669
+ ]
670
+ result = Gosling::Collision.get_polygon_separation_axes(vertices)
671
+ expect(result.length).to be == 5
672
+ expect(result[0]).to be == Vector[ 2, -1, 0].normalize
673
+ expect(result[1]).to be == Vector[ 1, -1, 0].normalize
674
+ expect(result[2]).to be == Vector[-1, -1, 0].normalize
675
+ expect(result[3]).to be == Vector[-3, 0, 0].normalize
676
+ expect(result[4]).to be == Vector[ 1, 3, 0].normalize
677
+ end
678
+ end
679
+
680
+ describe '#get_circle_separation_axis' do
681
+ it 'expects two shape arguments' do
682
+ expect { Gosling::Collision.get_circle_separation_axis(@circle1, @circle2) }.not_to raise_error
683
+ expect { Gosling::Collision.get_circle_separation_axis(@circle1, @polygon1) }.not_to raise_error
684
+ expect { Gosling::Collision.get_circle_separation_axis(@rect1, @circle2) }.not_to raise_error
685
+
686
+ expect { Gosling::Collision.get_circle_separation_axis(:foo, @circle2) }.to raise_error(ArgumentError)
687
+ expect { Gosling::Collision.get_circle_separation_axis(@circle1, @circle2, @circle1) }.to raise_error(ArgumentError)
688
+ expect { Gosling::Collision.get_circle_separation_axis(@circle1) }.to raise_error(ArgumentError)
689
+ expect { Gosling::Collision.get_circle_separation_axis() }.to raise_error(ArgumentError)
690
+ expect { Gosling::Collision.get_circle_separation_axis(:foo) }.to raise_error(ArgumentError)
691
+ end
692
+
693
+ it 'returns a 3d vector' do
694
+ clean_shape(@circle1)
695
+ @circle1.x = 0
696
+ @circle1.y = 0
697
+
698
+ clean_shape(@circle2)
699
+ @circle2.x = 10
700
+ @circle2.y = -5
701
+
702
+ result = Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
703
+ expect(result).to be_instance_of(Vector)
704
+ expect(result.size).to be == 3
705
+ end
706
+
707
+ it "returns nil if distance beween shape centers is 0" do
708
+ clean_shape(@circle1)
709
+ @circle1.x = 0
710
+ @circle1.y = 0
711
+
712
+ clean_shape(@circle2)
713
+ @circle2.x = 0
714
+ @circle2.y = 0
715
+
716
+ result = Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
717
+ expect(result).to be nil
718
+ end
719
+
720
+ it 'returns a correct unit vector' do
721
+ clean_shape(@circle1)
722
+ @circle1.x = 5
723
+ @circle1.y = -10
724
+
725
+ clean_shape(@circle2)
726
+ @circle2.x = 10
727
+ @circle2.y = -5
728
+
729
+ result = Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
730
+ expect(result).to be == Vector[1, 1, 0].normalize
731
+ end
732
+ end
733
+
734
+ describe '#get_separation_axes' do
735
+ it 'expects two shapes' do
736
+ expect { Gosling::Collision.get_separation_axes(@circle1, @circle2) }.not_to raise_error
737
+ expect { Gosling::Collision.get_separation_axes(@circle1, @polygon2) }.not_to raise_error
738
+ expect { Gosling::Collision.get_separation_axes(@polygon1, @polygon2) }.not_to raise_error
739
+ expect { Gosling::Collision.get_separation_axes(@polygon1, @rect2) }.not_to raise_error
740
+ expect { Gosling::Collision.get_separation_axes(@sprite1, @polygon2) }.not_to raise_error
741
+
742
+ expect { Gosling::Collision.get_separation_axes(@actor1, @circle2) }.to raise_error(ArgumentError)
743
+ expect { Gosling::Collision.get_separation_axes(@circle1, @circle2, @polygon2) }.to raise_error(ArgumentError)
744
+ expect { Gosling::Collision.get_separation_axes(@circle1, 1) }.to raise_error(ArgumentError)
745
+ expect { Gosling::Collision.get_separation_axes(@polygon1, :foo) }.to raise_error(ArgumentError)
746
+ expect { Gosling::Collision.get_separation_axes(:foo) }.to raise_error(ArgumentError)
747
+ expect { Gosling::Collision.get_separation_axes() }.to raise_error(ArgumentError)
748
+ end
749
+
750
+ it 'returns an array of 3d vectors' do
751
+ result = Gosling::Collision.get_separation_axes(@polygon1, @polygon2)
752
+ expect(result).to be_instance_of(Array)
753
+ expect(result.reject { |v| v.is_a?(Vector) && v.size == 3 }).to be_empty
754
+ end
755
+
756
+ it 'returns only unit vectors' do
757
+ result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
758
+ expect(result).to be_instance_of(Array)
759
+ expect(result.reject { |v| v.is_a?(Vector) && v.magnitude == 1 }).to be_empty
760
+ end
761
+
762
+ it 'returns only right-facing (positive x direction) vectors' do
763
+ result = Gosling::Collision.get_separation_axes(@rect2, @polygon1)
764
+ expect(result).to be_instance_of(Array)
765
+ expect(result.reject { |v| v.is_a?(Vector) && v[0] >= 0 }).to be_empty
766
+ end
767
+
768
+ it 'returns only unique vectors' do
769
+ result = Gosling::Collision.get_separation_axes(@rect2, @polygon2)
770
+ expect(result).to be_instance_of(Array)
771
+ expect(result.uniq.length).to be == result.length
772
+ end
773
+
774
+ it 'is commutative' do
775
+ result1 = Gosling::Collision.get_separation_axes(@rect2, @polygon2)
776
+ result2 = Gosling::Collision.get_separation_axes(@polygon2, @rect2)
777
+ expect(result1.to_set).to be == result2.to_set
778
+ end
779
+
780
+ it 'respects centering' do
781
+ clean_shape(@polygon1)
782
+ @polygon1.center_x = 10
783
+ @polygon1.center_y = 2
784
+
785
+ clean_shape(@circle1)
786
+
787
+ result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
788
+ expect(result).to be == [
789
+ Vector[10, 5, 0].normalize,
790
+ Vector[0, -10, 0].normalize,
791
+ Vector[10, -5, 0].normalize
792
+ ]
793
+ end
794
+
795
+ it 'respects scaling' do
796
+ clean_shape(@polygon1)
797
+ @polygon1.scale_x = 3
798
+ @polygon1.scale_y = 2
799
+
800
+ clean_shape(@circle1)
801
+
802
+ result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
803
+ expect(result).to be == [
804
+ Vector[20, 15, 0].normalize,
805
+ Vector[0, -30, 0].normalize,
806
+ Vector[20, -15, 0].normalize
807
+ ]
808
+ end
809
+
810
+ it 'respects rotation' do
811
+ clean_shape(@polygon1)
812
+ @polygon1.rotation = Math::PI / 2
813
+ result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
814
+
815
+ clean_shape(@circle1)
816
+
817
+ expect(result).to be == [
818
+ Vector[5, -10, 0].normalize,
819
+ Vector[10, 0, 0].normalize,
820
+ Vector[5, 10, 0].normalize
821
+ ]
822
+ end
823
+
824
+ it 'respects translation' do
825
+ clean_shape(@polygon1)
826
+ @polygon1.x = -50
827
+ @polygon1.y = 10
828
+
829
+ clean_shape(@circle1)
830
+
831
+ result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
832
+ expect(result).to be == [
833
+ Vector[10, 5, 0].normalize,
834
+ Vector[0, -10, 0].normalize,
835
+ Vector[10, -5, 0].normalize,
836
+ Vector[50, -10, 0].normalize
837
+ ]
838
+ end
839
+
840
+ context 'with two polygons' do
841
+ it 'returns an array with no more axes than total vertices, and no less than two' do
842
+ [
843
+ [@polygon1, @polygon2],
844
+ [@polygon1, @rect1],
845
+ [@polygon1, @rect2],
846
+ [@polygon1, @sprite1],
847
+ [@polygon1, @sprite2],
848
+ [@polygon2, @rect1],
849
+ [@polygon2, @rect2],
850
+ [@polygon2, @sprite1],
851
+ [@polygon2, @sprite2],
852
+ [@rect1, @rect2],
853
+ [@rect1, @sprite1],
854
+ [@rect1, @sprite2],
855
+ [@rect2, @sprite1],
856
+ [@rect2, @sprite2],
857
+ [@sprite1, @sprite2]
858
+ ].each do |shapes|
859
+ result = Gosling::Collision.get_separation_axes(*shapes)
860
+ vertex_count = 0
861
+ shapes.each { |s| vertex_count += s.get_vertices.length }
862
+ expect(result.length).to be_between(2, vertex_count).inclusive
863
+ end
864
+ end
865
+ end
866
+
867
+ context 'with two circles' do
868
+ context 'when both circles have the same center' do
869
+ it 'returns an empty array' do
870
+ @circle1.x = 0
871
+ @circle1.y = 0
872
+ @circle2.x = 0
873
+ @circle2.y = 0
874
+ result = Gosling::Collision.get_separation_axes(@circle1, @circle2)
875
+ expect(result).to be_instance_of(Array)
876
+ expect(result).to be_empty
877
+ end
878
+ end
879
+
880
+ it 'returns an array with one axis' do
881
+ @circle1.x = 1
882
+ @circle1.y = 0
883
+ @circle2.x = 17
884
+ @circle2.y = -5
885
+ result = Gosling::Collision.get_separation_axes(@circle1, @circle2)
886
+ expect(result).to be_instance_of(Array)
887
+ expect(result.length).to be == 1
888
+ end
889
+ end
890
+
891
+ context 'with a polygon and a circle' do
892
+ it 'returns an array with no more axes than total vertices plus one, and no less than two' do
893
+ [
894
+ [@circle1, @polygon1],
895
+ [@circle2, @polygon2],
896
+ [@circle1, @rect1],
897
+ [@circle2, @rect2],
898
+ [@circle1, @sprite1],
899
+ [@circle2, @sprite2]
900
+ ].each do |shapes|
901
+ result = Gosling::Collision.get_separation_axes(*shapes)
902
+ vertex_count = shapes[1].get_vertices.length
903
+ expect(result.length).to be_between(2, vertex_count + 1).inclusive
904
+ end
905
+ end
906
+ end
907
+ end
908
+
909
+ describe '#project_onto_axis' do
910
+ it 'expects a shape and a 3d unit vector' do
911
+ axis = Vector[1, 1, 0]
912
+
913
+ expect { Gosling::Collision.project_onto_axis(@sprite1, axis) }.not_to raise_error
914
+ expect { Gosling::Collision.project_onto_axis(@rect1, axis) }.not_to raise_error
915
+ expect { Gosling::Collision.project_onto_axis(@circle1, axis) }.not_to raise_error
916
+ expect { Gosling::Collision.project_onto_axis(@polygon1, axis) }.not_to raise_error
917
+
918
+ expect { Gosling::Collision.project_onto_axis(:foo, axis) }.to raise_error(ArgumentError)
919
+ expect { Gosling::Collision.project_onto_axis(@sprite1, Vector[1, 1, 0, 2]) }.to raise_error(ExceptionForMatrix::ErrDimensionMismatch)
920
+ expect { Gosling::Collision.project_onto_axis(@rect1, Vector[1, 1]) }.to raise_error(ExceptionForMatrix::ErrDimensionMismatch)
921
+ expect { Gosling::Collision.project_onto_axis(@polygon1, :foo) }.to raise_error(ArgumentError)
922
+ expect { Gosling::Collision.project_onto_axis(@circle1, @circle1, axis) }.to raise_error(ArgumentError)
923
+ expect { Gosling::Collision.project_onto_axis() }.to raise_error(ArgumentError)
924
+ end
925
+
926
+ it 'returns an array of two numbers' do
927
+ axis = Vector[1, 1, 0]
928
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
929
+ expect(result).to be_instance_of(Array)
930
+ expect(result.length).to be == 2
931
+ expect(result.reject { |x| x.is_a?(Numeric) }).to be_empty
932
+ end
933
+
934
+ context 'with a circle' do
935
+ it 'returns expected values' do
936
+ clean_shape(@circle1)
937
+ @circle1.x = 0
938
+ @circle1.y = 0
939
+ @circle1.radius = 5
940
+
941
+ axis = Vector[-1, 1, 0].normalize
942
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
943
+ expect(result).to be == [-5, 5]
944
+
945
+ clean_shape(@circle1)
946
+ @circle1.x = 5
947
+ @circle1.y = 0
948
+ @circle1.radius = 5
949
+
950
+ axis = Vector[1, 0, 0].normalize
951
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
952
+ expect(result).to be == [0, 10]
953
+ end
954
+
955
+ it 'respects centering' do
956
+ clean_shape(@circle1)
957
+ @circle1.center_x = 3
958
+ @circle1.center_y = 6
959
+
960
+ axis = Vector[1, 0, 0].normalize
961
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
962
+ expect(result).to be == [-8, 2]
963
+
964
+ axis = Vector[0, 1, 0].normalize
965
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
966
+ expect(result).to be == [-11, -1]
967
+ end
968
+
969
+ it 'respects scaling' do
970
+ clean_shape(@circle1)
971
+ @circle1.scale_x = 2
972
+ @circle1.scale_y = 0.5
973
+
974
+ axis = Vector[1, 0, 0].normalize
975
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
976
+ expect(result).to be == [-10, 10]
977
+
978
+ axis = Vector[0, 1, 0].normalize
979
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
980
+ expect(result).to be == [-2.5, 2.5]
981
+ end
982
+
983
+ it 'respects rotation' do
984
+ clean_shape(@circle1)
985
+ @circle1.rotation = Math::PI
986
+
987
+ axis = Vector[1, 0, 0].normalize
988
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
989
+ expect(result).to be == [-5, 5]
990
+ end
991
+
992
+ it 'respects translation' do
993
+ clean_shape(@circle1)
994
+ @circle1.x = -12
995
+ @circle1.y = 23
996
+
997
+ axis = Vector[1, 0, 0].normalize
998
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
999
+ expect(result).to be == [-17, -7]
1000
+
1001
+ axis = Vector[0, 1, 0].normalize
1002
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
1003
+ expect(result).to be == [18, 28]
1004
+ end
1005
+
1006
+ it 'respects its entire ancestry of transforms' do
1007
+ circle = Gosling::Circle.new(@window)
1008
+ clean_shape(circle)
1009
+ circle.radius = 10
1010
+
1011
+ create_inheritance_chain([@center_actor, @scale_actor, @rotate_actor, @translate_actor, circle])
1012
+
1013
+ axis = Vector[1, 0, 0].normalize
1014
+ result = Gosling::Collision.project_onto_axis(circle, axis)
1015
+ expect(result).to be == [-936.0, -866.0]
1016
+
1017
+ axis = Vector[0, 1, 0].normalize
1018
+ result = Gosling::Collision.project_onto_axis(circle, axis)
1019
+ expect(result).to be == [290.0, 340.0]
1020
+
1021
+ axis = Vector[1, 1, 0].normalize
1022
+ result = Gosling::Collision.project_onto_axis(circle, axis)
1023
+ expect(result).to be == [-443.13439655375436, -385.5947509968793]
1024
+
1025
+ break_inheritance_chain([@center_actor, @scale_actor, @rotate_actor, @translate_actor, circle])
1026
+ end
1027
+ end
1028
+
1029
+ context 'with a polygon' do
1030
+ it 'returns expected values' do
1031
+ axis = Vector[1, 0, 0].normalize
1032
+ clean_shape(@polygon2)
1033
+ @polygon2.x = 0
1034
+ @polygon2.y = 0
1035
+ result = Gosling::Collision.project_onto_axis(@polygon2, axis)
1036
+ expect(result).to be == [-5, 5]
1037
+
1038
+ axis = Vector[0, 1, 0].normalize
1039
+ clean_shape(@polygon1)
1040
+ @polygon1.x = 0
1041
+ @polygon1.y = 5
1042
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1043
+ expect(result).to be == [0, 10]
1044
+
1045
+ axis = Vector[1, -1, 0].normalize
1046
+ clean_shape(@polygon1)
1047
+ @polygon1.x = 0
1048
+ @polygon1.y = 0
1049
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1050
+ expect(result[0]).to be_within(0.00000001).of(-Math.sqrt(25 * 0.5))
1051
+ expect(result[1]).to be_within(0.00000001).of(Math.sqrt(50))
1052
+ end
1053
+
1054
+ it 'respects centering' do
1055
+ clean_shape(@polygon1)
1056
+ @polygon1.center_x = 5
1057
+ @polygon1.center_y = -1
1058
+
1059
+ axis = Vector[1, 0, 0].normalize
1060
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1061
+ expect(result).to be == [-10, 0]
1062
+
1063
+ axis = Vector[0, 1, 0].normalize
1064
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1065
+ expect(result).to be == [-4, 6]
1066
+ end
1067
+
1068
+ it 'respects scaling' do
1069
+ clean_shape(@polygon1)
1070
+ @polygon1.scale_x = 3
1071
+ @polygon1.scale_y = 2
1072
+
1073
+ axis = Vector[1, 0, 0].normalize
1074
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1075
+ expect(result).to be == [-15, 15]
1076
+
1077
+ axis = Vector[0, 1, 0].normalize
1078
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1079
+ expect(result).to be == [-10, 10]
1080
+ end
1081
+
1082
+ it 'respects rotation' do
1083
+ clean_shape(@polygon1)
1084
+ @polygon1.rotation = Math::PI / 4
1085
+
1086
+ axis = Vector[1, 0, 0].normalize
1087
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1088
+ expect(result).to be == [-7.0710678118654755, 3.5355339059327373]
1089
+
1090
+ axis = Vector[0, 1, 0].normalize
1091
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1092
+ expect(result).to be == [-7.0710678118654755, 3.5355339059327378]
1093
+ end
1094
+
1095
+ it 'respects translation' do
1096
+ clean_shape(@polygon1)
1097
+ @polygon1.x = -7
1098
+ @polygon1.y = 13
1099
+
1100
+ axis = Vector[1, 0, 0].normalize
1101
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1102
+ expect(result).to be == [-12, -2]
1103
+
1104
+ axis = Vector[0, 1, 0].normalize
1105
+ result = Gosling::Collision.project_onto_axis(@polygon1, axis)
1106
+ expect(result).to be == [8, 18]
1107
+ end
1108
+
1109
+ it 'respects its entire ancestry of transforms' do
1110
+ polygon = Gosling::Polygon.new(@window)
1111
+ clean_shape(polygon)
1112
+ polygon.set_vertices(@polygon1.get_vertices)
1113
+
1114
+ create_inheritance_chain([@center_actor, @scale_actor, @rotate_actor, @translate_actor, polygon])
1115
+
1116
+ axis = Vector[1, 0, 0].normalize
1117
+ result = Gosling::Collision.project_onto_axis(polygon, axis)
1118
+ expect(result).to be == [-918.5, -883.5]
1119
+
1120
+ axis = Vector[0, 1, 0].normalize
1121
+ result = Gosling::Collision.project_onto_axis(polygon, axis)
1122
+ expect(result).to be == [302.5, 327.5]
1123
+
1124
+ axis = Vector[1, 1, 0].normalize
1125
+ result = Gosling::Collision.project_onto_axis(polygon, axis)
1126
+ expect(result).to be == [-426.7389424460814, -393.1513703397204]
1127
+
1128
+ break_inheritance_chain([@center_actor, @scale_actor, @rotate_actor, @translate_actor, polygon])
1129
+ end
1130
+ end
1131
+ end
1132
+
1133
+ describe '#projections_overlap?' do
1134
+ it 'accepts two length 2 arrays with numbers' do
1135
+ expect { Gosling::Collision.projections_overlap?([0, 0], [0, 0]) }.not_to raise_error
1136
+ expect { Gosling::Collision.projections_overlap?([1, 2], [3, -4]) }.not_to raise_error
1137
+
1138
+ expect { Gosling::Collision.projections_overlap?([1, 2, 3], [4, 5, 6]) }.to raise_error(ArgumentError)
1139
+ expect { Gosling::Collision.projections_overlap?([1], [4]) }.to raise_error(ArgumentError)
1140
+ expect { Gosling::Collision.projections_overlap?([1, 2], [3, -4], [5, 6]) }.to raise_error(ArgumentError)
1141
+ expect { Gosling::Collision.projections_overlap?([1, 2]) }.to raise_error(ArgumentError)
1142
+ expect { Gosling::Collision.projections_overlap?([1, 2], :foo) }.to raise_error(ArgumentError)
1143
+ expect { Gosling::Collision.projections_overlap?(nil, [1, 2]) }.to raise_error(ArgumentError)
1144
+ end
1145
+
1146
+ context 'when a and b do not overlap' do
1147
+ it 'returns false' do
1148
+ expect(Gosling::Collision.projections_overlap?([0, 10], [20, 30])).to be false
1149
+ expect(Gosling::Collision.projections_overlap?([-20, -30], [0, 10])).to be false
1150
+ end
1151
+ end
1152
+
1153
+ context 'when a contains b' do
1154
+ it 'returns true' do
1155
+ expect(Gosling::Collision.projections_overlap?([0, 40], [20, 30])).to be true
1156
+ expect(Gosling::Collision.projections_overlap?([-40, 0], [-25, -15])).to be true
1157
+ expect(Gosling::Collision.projections_overlap?([-2, 0], [-1, 0])).to be true
1158
+ end
1159
+ end
1160
+
1161
+ context 'when b contains a' do
1162
+ it 'returns true' do
1163
+ expect(Gosling::Collision.projections_overlap?([5, 10], [0, 50])).to be true
1164
+ expect(Gosling::Collision.projections_overlap?([-10, 10], [-25, 25])).to be true
1165
+ expect(Gosling::Collision.projections_overlap?([5, 6], [5, 10])).to be true
1166
+ end
1167
+ end
1168
+
1169
+ context 'when a overlaps b' do
1170
+ it 'returns true' do
1171
+ expect(Gosling::Collision.projections_overlap?([-10, 10], [0, 20])).to be true
1172
+ expect(Gosling::Collision.projections_overlap?([-1000, 0], [-1, 314159])).to be true
1173
+ end
1174
+ end
1175
+
1176
+ context 'when a touches b' do
1177
+ it 'returns true' do
1178
+ expect(Gosling::Collision.projections_overlap?([-10, 0], [0, 10])).to be true
1179
+ expect(Gosling::Collision.projections_overlap?([-5, 30], [-17, -5])).to be true
1180
+ end
1181
+ end
1182
+ end
1183
+ end