gosling 1.0.0

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.
@@ -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