gosling 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,33 +1,33 @@
1
1
  require 'set'
2
2
 
3
+ def angle_to_vector(angle)
4
+ Snow::Vec3[Math.sin(angle).round(12), Math.cos(angle).round(12), 0]
5
+ end
6
+
7
+ def clean_actor(actor)
8
+ actor.x = 0
9
+ actor.y = 0
10
+ actor.scale_x = 1
11
+ actor.scale_y = 1
12
+ actor.rotation = 0
13
+ end
14
+
3
15
  def clean_shape(shape)
4
- shape.x = 0
5
- shape.y = 0
16
+ clean_actor(shape)
6
17
  shape.center_x = 0
7
18
  shape.center_y = 0
8
- shape.scale_x = 1
9
- shape.scale_y = 1
10
- shape.rotation = 0
11
19
  end
12
20
 
13
21
  def clean_rect(rect)
14
- rect.x = 0
15
- rect.y = 0
22
+ clean_actor(rect)
16
23
  rect.center_x = 5
17
24
  rect.center_y = 5
18
- rect.scale_x = 1
19
- rect.scale_y = 1
20
- rect.rotation = 0
21
25
  end
22
26
 
23
27
  def clean_sprite(sprite)
24
- sprite.x = 0
25
- sprite.y = 0
28
+ clean_actor(sprite)
26
29
  sprite.center_x = 8
27
30
  sprite.center_y = 8
28
- sprite.scale_x = 1
29
- sprite.scale_y = 1
30
- sprite.rotation = 0
31
31
  end
32
32
 
33
33
  def create_inheritance_chain(ancestry)
@@ -42,7 +42,11 @@ def break_inheritance_chain(ancestry)
42
42
  end
43
43
  end
44
44
 
45
+ ANGLE_COUNT = 8 * 4
46
+
45
47
  describe Gosling::Collision do
48
+ FLOAT_TOLERANCE = 0.000001
49
+
46
50
  before(:all) do
47
51
  @window = Gosu::Window.new(640, 480, false)
48
52
  @local_path = File.dirname(__FILE__)
@@ -109,305 +113,459 @@ describe Gosling::Collision do
109
113
  @translate_actor = Gosling::Actor.new(@window)
110
114
  @translate_actor.x = 128
111
115
  @translate_actor.y = 256
116
+
117
+ @angles = (0...ANGLE_COUNT).map { |i| Math::PI * 2 * i / ANGLE_COUNT }
112
118
  end
113
119
 
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
+ context 'any actor vs. itself' do
121
+ it 'never collides' do
122
+ [@actor1, @circle1, @polygon1, @rect1, @sprite1].each do |actor|
123
+ expect(Gosling::Collision.test(actor, actor)).to be false
124
+ result = Gosling::Collision.get_collision_info(actor, actor)
125
+ expect(result[:colliding]).to be false
126
+ expect(result[:overlap]).to be nil
127
+ expect(result[:penetration]).to be nil
120
128
  end
121
129
  end
130
+ end
122
131
 
123
- context 'actor vs. actor' do
124
- it 'never collides' do
125
- expect(Gosling::Collision.test(@actor1, @actor2)).to be false
132
+ context 'actor vs. anything' do
133
+ it 'never collides' do
134
+ pairs = [
135
+ [@actor1, @actor2],
136
+ [@actor1, @circle1],
137
+ [@actor1, @polygon1],
138
+ [@actor1, @rect1],
139
+ [@actor1, @sprite1]
140
+ ]
141
+ pairs.each do |pair|
142
+ expect(Gosling::Collision.test(*pair)).to be false
143
+ result = Gosling::Collision.get_collision_info(*pair)
144
+ expect(result[:colliding]).to be false
145
+ expect(result[:overlap]).to be nil
146
+ expect(result[:penetration]).to be nil
126
147
  end
127
148
  end
149
+ end
128
150
 
129
- context 'actor vs. circle' do
130
- it 'never collides' do
131
- expect(Gosling::Collision.test(@actor1, @circle1)).to be false
132
- end
151
+ context 'circle vs. circle' do
152
+ before do
153
+ clean_shape(@circle1)
154
+ @circle1.x = 0
155
+ @circle1.y = 0
156
+
157
+ clean_shape(@circle2)
158
+ @circle2.x = 5
159
+ @circle2.y = 5
133
160
  end
134
161
 
135
- context 'actor vs. polygon' do
136
- it 'never collides' do
137
- expect(Gosling::Collision.test(@actor1, @polygon1)).to be false
138
- end
162
+ it 'collides if the shapes are close enough' do
163
+ expect(Gosling::Collision.test(@circle1, @circle2)).to be true
164
+ result = Gosling::Collision.get_collision_info(@circle1, @circle2)
165
+ expect(result[:colliding]).to be true
166
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(10 - Math.sqrt(50))
167
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
139
168
  end
140
169
 
141
- context 'actor vs. rect' do
142
- it 'never collides' do
143
- expect(Gosling::Collision.test(@actor1, @rect1)).to be false
170
+ it 'returns a vector that separates the shapes' do
171
+ @angles.each do |r|
172
+ @circle1.x = 5 + Math.sin(r) * 5
173
+ @circle1.y = 5 + Math.cos(r) * 5
174
+ @circle2.x = 5
175
+ @circle2.y = 5
176
+
177
+ result = Gosling::Collision.get_collision_info(@circle1, @circle2)
178
+ @circle2.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
179
+ expect(Gosling::Collision.test(@circle1, @circle2)).to be false
144
180
  end
145
181
  end
146
182
 
147
- context 'actor vs. sprite' do
148
- it 'never collides' do
149
- expect(Gosling::Collision.test(@actor1, @sprite1)).to be false
150
- end
183
+ it 'always returns the vector that displaces shape b away from shape a' do
184
+ @circle1.y = 10
185
+ result = Gosling::Collision.get_collision_info(@circle1, @circle2)
186
+ expect(result[:penetration]).to eq(Snow::Vec3[1, -1, 0].normalize * result[:overlap])
151
187
  end
152
188
 
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
189
+ it 'does not collide if the shapes are far apart' do
190
+ @circle2.x = 10
158
191
 
159
- clean_shape(@circle2)
160
- @circle2.x = 5
161
- @circle2.y = 5
192
+ expect(Gosling::Collision.test(@circle1, @circle2)).to be false
162
193
 
163
- expect(Gosling::Collision.test(@circle1, @circle2)).to be true
164
- end
194
+ result = Gosling::Collision.get_collision_info(@circle1, @circle2)
195
+ expect(result[:colliding]).to be false
196
+ expect(result[:overlap]).to be nil
197
+ expect(result[:penetration]).to be nil
198
+ end
199
+ end
165
200
 
166
- it 'does not collide if the shapes are far apart' do
167
- clean_shape(@circle1)
168
- @circle1.x = 0
169
- @circle1.y = 0
201
+ context 'circle vs. polygon' do
202
+ before do
203
+ clean_shape(@circle1)
204
+ @circle1.x = 0
205
+ @circle1.y = 0
170
206
 
171
- clean_shape(@circle2)
172
- @circle2.x = 10
173
- @circle2.y = 5
207
+ clean_shape(@polygon1)
208
+ @polygon1.x = 5
209
+ @polygon1.y = 5
210
+ end
174
211
 
175
- expect(Gosling::Collision.test(@circle1, @circle2)).to be false
176
- end
212
+ it 'collides if the shapes are close enough' do
213
+ expect(Gosling::Collision.test(@circle1, @polygon1)).to be true
214
+ result = Gosling::Collision.get_collision_info(@circle1, @polygon1)
215
+ expect(result[:colliding]).to be true
216
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
217
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
177
218
  end
178
219
 
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
220
+ it 'returns a vector that separates the shapes' do
221
+ result = Gosling::Collision.get_collision_info(@circle1, @polygon1)
222
+ @polygon1.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
223
+ expect(Gosling::Collision.test(@circle1, @polygon1)).to be false
224
+ end
184
225
 
185
- clean_shape(@polygon1)
186
- @polygon1.x = 5
187
- @polygon1.y = 5
226
+ it 'does not collide if the shapes are far apart' do
227
+ @polygon1.x = 10
228
+ @polygon1.y = 10
188
229
 
189
- expect(Gosling::Collision.test(@circle1, @polygon1)).to be true
190
- end
230
+ expect(Gosling::Collision.test(@circle1, @polygon1)).to be false
231
+ result = Gosling::Collision.get_collision_info(@circle1, @polygon1)
232
+ expect(result[:colliding]).to be false
233
+ expect(result[:overlap]).to be nil
234
+ expect(result[:penetration]).to be nil
235
+ end
236
+ end
191
237
 
192
- it 'does not collide if the shapes are far apart' do
193
- clean_shape(@circle1)
194
- @circle1.x = 0
195
- @circle1.y = 0
238
+ context 'circle vs. rect' do
239
+ before do
240
+ clean_shape(@circle1)
241
+ @circle1.x = 0
242
+ @circle1.y = 0
196
243
 
197
- clean_shape(@polygon1)
198
- @polygon1.x = 10
199
- @polygon1.y = 10
244
+ clean_rect(@rect1)
245
+ @rect1.x = 5
246
+ @rect1.y = 5
247
+ end
200
248
 
201
- expect(Gosling::Collision.test(@circle1, @polygon1)).to be false
202
- end
249
+ it 'collides if the shapes are close enough' do
250
+ expect(Gosling::Collision.test(@circle1, @rect1)).to be true
251
+ result = Gosling::Collision.get_collision_info(@circle1, @rect1)
252
+ expect(result[:colliding]).to be true
253
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
254
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
203
255
  end
204
256
 
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
257
+ it 'returns a vector that separates the shapes' do
258
+ result = Gosling::Collision.get_collision_info(@circle1, @rect1)
259
+ @rect1.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
260
+ expect(Gosling::Collision.test(@circle1, @rect1)).to be false
261
+ end
210
262
 
211
- clean_rect(@rect1)
212
- @rect1.x = 5
213
- @rect1.y = 5
263
+ it 'does not collide if the shapes are far apart' do
264
+ @rect1.x = 10
265
+ @rect1.y = 10
214
266
 
215
- expect(Gosling::Collision.test(@circle1, @rect1)).to be true
216
- end
267
+ expect(Gosling::Collision.test(@circle1, @rect1)).to be false
268
+ result = Gosling::Collision.get_collision_info(@circle1, @rect1)
269
+ expect(result[:colliding]).to be false
270
+ expect(result[:overlap]).to be nil
271
+ expect(result[:penetration]).to be nil
272
+ end
273
+ end
217
274
 
218
- it 'does not collide if the shapes are far apart' do
219
- clean_shape(@circle1)
220
- @circle1.x = 0
221
- @circle1.y = 0
275
+ context 'circle vs. sprite' do
276
+ before do
277
+ clean_shape(@circle1)
278
+ @circle1.x = 0
279
+ @circle1.y = 0
222
280
 
223
- clean_rect(@rect1)
224
- @rect1.x = 10
225
- @rect1.y = 10
281
+ clean_sprite(@sprite1)
282
+ @sprite1.x = 8
283
+ @sprite1.y = 8
284
+ end
226
285
 
227
- expect(Gosling::Collision.test(@circle1, @rect1)).to be false
228
- end
286
+ it 'collides if the shapes are close enough' do
287
+ expect(Gosling::Collision.test(@circle1, @sprite1)).to be true
288
+ result = Gosling::Collision.get_collision_info(@circle1, @sprite1)
289
+ expect(result[:colliding]).to be true
290
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
291
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
229
292
  end
230
293
 
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
294
+ it 'returns a vector that separates the shapes' do
295
+ result = Gosling::Collision.get_collision_info(@circle1, @sprite1)
296
+ @sprite1.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
297
+ expect(Gosling::Collision.test(@circle1, @sprite1)).to be false
298
+ end
236
299
 
237
- clean_sprite(@sprite1)
238
- @sprite1.x = 8
239
- @sprite1.y = 8
300
+ it 'does not collide if the shapes are far apart' do
301
+ @sprite1.x = 16
302
+ @sprite1.y = 16
240
303
 
241
- expect(Gosling::Collision.test(@circle1, @sprite1)).to be true
242
- end
304
+ expect(Gosling::Collision.test(@circle1, @sprite1)).to be false
305
+ result = Gosling::Collision.get_collision_info(@circle1, @sprite1)
306
+ expect(result[:colliding]).to be false
307
+ expect(result[:overlap]).to be nil
308
+ expect(result[:penetration]).to be nil
309
+ end
310
+ end
243
311
 
244
- it 'does not collide if the shapes are far apart' do
245
- clean_shape(@circle1)
246
- @circle1.x = 0
247
- @circle1.y = 0
312
+ context 'polygon vs. polygon' do
313
+ before do
314
+ clean_shape(@polygon1)
315
+ @polygon1.x = 0
316
+ @polygon1.y = 0
248
317
 
249
- clean_sprite(@sprite1)
250
- @sprite1.x = 16
251
- @sprite1.y = 16
318
+ clean_shape(@polygon2)
319
+ @polygon2.x = 0
320
+ @polygon2.y = 5
321
+ end
252
322
 
253
- expect(Gosling::Collision.test(@circle1, @sprite1)).to be false
254
- end
323
+ it 'collides if the shapes are close enough' do
324
+ expect(Gosling::Collision.test(@polygon1, @polygon2)).to be true
325
+ result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
326
+ expect(result[:colliding]).to be true
327
+ axis = Snow::Vec2[-10, -5].normalize
328
+ a = Snow::Vec2[0, 0].dot_product(axis)
329
+ b = Snow::Vec2[0, 5].dot_product(axis)
330
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(a - b)
331
+ expect(result[:penetration]).to eq(Snow::Vec3[2, 1, 0].normalize * result[:overlap])
255
332
  end
256
333
 
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
334
+ it 'returns a vector that separates the shapes' do
335
+ @polygon1.x = 0
336
+ @polygon1.y = 0
262
337
 
263
- clean_shape(@polygon2)
338
+ @angles.each do |r|
264
339
  @polygon2.x = 0
265
340
  @polygon2.y = 5
266
341
 
267
- expect(Gosling::Collision.test(@polygon1, @polygon2)).to be true
342
+ @polygon1.rotation = r
343
+ result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
344
+ @polygon2.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
345
+ expect(Gosling::Collision.test(@polygon1, @polygon2)).to be false
346
+ @polygon1.rotation = 0
347
+
348
+ @polygon2.x = Math.sin(r)
349
+ @polygon2.y = Math.cos(r)
350
+ result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
351
+ @polygon2.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
352
+ expect(Gosling::Collision.test(@polygon1, @polygon2)).to be false
268
353
  end
354
+ end
269
355
 
270
- it 'does not collide if the shapes are far apart' do
271
- clean_shape(@polygon1)
272
- @polygon1.x = 0
273
- @polygon1.y = 0
356
+ it 'always returns the vector that displaces shape b away from shape a' do
357
+ @polygon1.y = 5
358
+ @polygon2.y = 0
359
+ result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
360
+ expect(result[:penetration]).to eq(Snow::Vec3[0, -1, 0].normalize * result[:overlap])
361
+ end
274
362
 
275
- clean_shape(@polygon2)
276
- @polygon2.x = 5
277
- @polygon2.y = 5
363
+ it 'does not collide if the shapes are far apart' do
364
+ @polygon2.x = 5
278
365
 
279
- expect(Gosling::Collision.test(@polygon1, @polygon2)).to be false
280
- end
366
+ expect(Gosling::Collision.test(@polygon1, @polygon2)).to be false
367
+ result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
368
+ expect(result[:colliding]).to be false
369
+ expect(result[:overlap]).to be nil
370
+ expect(result[:penetration]).to be nil
281
371
  end
372
+ end
282
373
 
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
374
+ context 'polygon vs. rect' do
375
+ before do
376
+ clean_shape(@polygon1)
377
+ @polygon1.x = 0
378
+ @polygon1.y = 0
288
379
 
289
- clean_rect(@rect1)
290
- @rect1.x = 5
291
- @rect1.y = 5
380
+ clean_rect(@rect1)
381
+ @rect1.x = 5
382
+ @rect1.y = 5
383
+ end
292
384
 
293
- expect(Gosling::Collision.test(@polygon1, @rect1)).to be true
294
- end
385
+ it 'collides if the shapes are close enough' do
386
+ expect(Gosling::Collision.test(@polygon1, @rect1)).to be true
387
+ result = Gosling::Collision.get_collision_info(@polygon1, @rect1)
388
+ expect(result[:colliding]).to be true
389
+ axis = Snow::Vec2[-10, -5].normalize
390
+ a = Snow::Vec2[0, 0].dot_product(axis)
391
+ b = Snow::Vec2[0, 5].dot_product(axis)
392
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(a - b)
393
+ expect(result[:penetration]).to eq(Snow::Vec3[2, 1, 0].normalize * result[:overlap])
394
+ end
295
395
 
296
- it 'does not collide if the shapes are far apart' do
297
- clean_shape(@polygon1)
298
- @polygon1.x = 0
299
- @polygon1.y = 0
396
+ it 'returns a vector that separates the shapes' do
397
+ result = Gosling::Collision.get_collision_info(@polygon1, @rect1)
398
+ @rect1.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
399
+ expect(Gosling::Collision.test(@polygon1, @rect1)).to be false
400
+ end
300
401
 
301
- clean_rect(@rect1)
302
- @rect1.x = 10
303
- @rect1.y = 5
402
+ it 'does not collide if the shapes are far apart' do
403
+ @rect1.x = 10
304
404
 
305
- expect(Gosling::Collision.test(@polygon1, @rect1)).to be false
306
- end
405
+ expect(Gosling::Collision.test(@polygon1, @rect1)).to be false
406
+ result = Gosling::Collision.get_collision_info(@polygon1, @rect1)
407
+ expect(result[:colliding]).to be false
408
+ expect(result[:overlap]).to be nil
409
+ expect(result[:penetration]).to be nil
307
410
  end
411
+ end
308
412
 
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
413
+ context 'polygon vs. sprite' do
414
+ before do
415
+ clean_shape(@polygon1)
416
+ @polygon1.x = 0
417
+ @polygon1.y = 0
314
418
 
315
- clean_sprite(@sprite1)
316
- @sprite1.x = 8
317
- @sprite1.y = 8
419
+ clean_sprite(@sprite1)
420
+ @sprite1.x = 8
421
+ @sprite1.y = 8
422
+ end
318
423
 
319
- expect(Gosling::Collision.test(@polygon1, @sprite1)).to be true
320
- end
424
+ it 'collides if the shapes are close enough' do
425
+ expect(Gosling::Collision.test(@polygon1, @sprite1)).to be true
426
+ result = Gosling::Collision.get_collision_info(@polygon1, @sprite1)
427
+ expect(result[:colliding]).to be true
428
+ axis = Snow::Vec2[-10, -5].normalize
429
+ a = Snow::Vec2[0, 0].dot_product(axis)
430
+ b = Snow::Vec2[0, 5].dot_product(axis)
431
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(a - b)
432
+ expect(result[:penetration]).to eq(Snow::Vec3[2, 1, 0].normalize * result[:overlap])
433
+ end
321
434
 
322
- it 'does not collide if the shapes are far apart' do
323
- clean_shape(@polygon1)
324
- @polygon1.x = 0
325
- @polygon1.y = 0
435
+ it 'returns a vector that separates the shapes' do
436
+ result = Gosling::Collision.get_collision_info(@polygon1, @sprite1)
437
+ @sprite1.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
438
+ expect(Gosling::Collision.test(@polygon1, @sprite1)).to be false
439
+ end
326
440
 
327
- clean_sprite(@sprite1)
328
- @sprite1.x = 13
329
- @sprite1.y = 8
441
+ it 'does not collide if the shapes are far apart' do
442
+ @sprite1.x = 13
330
443
 
331
- expect(Gosling::Collision.test(@polygon1, @sprite1)).to be false
332
- end
444
+ expect(Gosling::Collision.test(@polygon1, @sprite1)).to be false
445
+ result = Gosling::Collision.get_collision_info(@polygon1, @sprite1)
446
+ expect(result[:colliding]).to be false
447
+ expect(result[:overlap]).to be nil
448
+ expect(result[:penetration]).to be nil
333
449
  end
450
+ end
334
451
 
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
452
+ context 'rect vs. rect' do
453
+ before do
454
+ clean_rect(@rect1)
455
+ @rect1.x = 0
456
+ @rect1.y = 0
340
457
 
341
- clean_rect(@rect2)
342
- @rect2.x = 5
343
- @rect2.y = 5
458
+ clean_rect(@rect2)
459
+ @rect2.x = 5
460
+ @rect2.y = 5
461
+ end
344
462
 
345
- expect(Gosling::Collision.test(@rect1, @rect2)).to be true
463
+ it 'collides if the shapes are close enough' do
464
+ expect(Gosling::Collision.test(@rect1, @rect2)).to be true
465
+ result = Gosling::Collision.get_collision_info(@rect1, @rect2)
466
+ expect(result[:colliding]).to be true
467
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
468
+ if result[:penetration].x == 0
469
+ expect(result[:penetration]).to eq(Snow::Vec3[0, 1, 0].normalize * result[:overlap])
470
+ else
471
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 0, 0].normalize * result[:overlap])
346
472
  end
473
+ end
347
474
 
348
- it 'does not collide if the shapes are far apart' do
349
- clean_rect(@rect1)
350
- @rect1.x = 0
351
- @rect1.y = 0
475
+ it 'returns a vector that separates the shapes' do
476
+ result = Gosling::Collision.get_collision_info(@rect1, @rect2)
477
+ @rect2.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
478
+ expect(Gosling::Collision.test(@rect1, @rect2)).to be false
479
+ end
352
480
 
353
- clean_shape(@rect2)
354
- @rect2.x = 11
355
- @rect2.y = 5
481
+ it 'does not collide if the shapes are far apart' do
482
+ @rect2.x = 11
356
483
 
357
- expect(Gosling::Collision.test(@rect1, @rect2)).to be false
358
- end
484
+ expect(Gosling::Collision.test(@rect1, @rect2)).to be false
485
+ result = Gosling::Collision.get_collision_info(@rect1, @rect2)
486
+ expect(result[:colliding]).to be false
487
+ expect(result[:overlap]).to be nil
488
+ expect(result[:penetration]).to be nil
359
489
  end
490
+ end
360
491
 
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
492
+ context 'rect vs. sprite' do
493
+ before do
494
+ clean_rect(@rect1)
495
+ @rect1.x = 0
496
+ @rect1.y = 0
366
497
 
367
- clean_sprite(@sprite1)
368
- @sprite1.x = 8
369
- @sprite1.y = 8
498
+ clean_sprite(@sprite1)
499
+ @sprite1.x = 8
500
+ @sprite1.y = 8
501
+ end
370
502
 
371
- expect(Gosling::Collision.test(@rect1, @sprite1)).to be true
503
+ it 'collides if the shapes are close enough' do
504
+ expect(Gosling::Collision.test(@rect1, @sprite1)).to be true
505
+ result = Gosling::Collision.get_collision_info(@rect1, @sprite1)
506
+ expect(result[:colliding]).to be true
507
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
508
+ if result[:penetration].x == 0
509
+ expect(result[:penetration]).to eq(Snow::Vec3[0, 1, 0].normalize * result[:overlap])
510
+ else
511
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 0, 0].normalize * result[:overlap])
372
512
  end
513
+ end
373
514
 
374
- it 'does not collide if the shapes are far apart' do
375
- clean_rect(@rect1)
376
- @rect1.x = 0
377
- @rect1.y = 0
515
+ it 'returns a vector that separates the shapes' do
516
+ result = Gosling::Collision.get_collision_info(@rect1, @sprite1)
517
+ @sprite1.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
518
+ expect(Gosling::Collision.test(@rect1, @sprite1)).to be false
519
+ end
378
520
 
379
- clean_sprite(@sprite1)
380
- @sprite1.x = 16
381
- @sprite1.y = 8
521
+ it 'does not collide if the shapes are far apart' do
522
+ @sprite1.x = 16
382
523
 
383
- expect(Gosling::Collision.test(@rect1, @sprite1)).to be false
384
- end
524
+ expect(Gosling::Collision.test(@rect1, @sprite1)).to be false
525
+ result = Gosling::Collision.get_collision_info(@rect1, @sprite1)
526
+ expect(result[:colliding]).to be false
527
+ expect(result[:overlap]).to be nil
528
+ expect(result[:penetration]).to be nil
385
529
  end
530
+ end
386
531
 
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
532
+ context 'sprite vs. sprite' do
533
+ before do
534
+ clean_sprite(@sprite1)
535
+ @sprite1.x = 0
536
+ @sprite1.y = 0
392
537
 
393
- clean_sprite(@sprite2)
394
- @sprite2.x = 8
395
- @sprite2.y = 8
538
+ clean_sprite(@sprite2)
539
+ @sprite2.x = 8
540
+ @sprite2.y = 8
541
+ end
396
542
 
397
- expect(Gosling::Collision.test(@sprite1, @sprite2)).to be true
543
+ it 'collides if the shapes are close enough' do
544
+ expect(Gosling::Collision.test(@sprite1, @sprite2)).to be true
545
+ result = Gosling::Collision.get_collision_info(@sprite1, @sprite2)
546
+ expect(result[:colliding]).to be true
547
+ expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(8)
548
+ if result[:penetration].x == 0
549
+ expect(result[:penetration]).to eq(Snow::Vec3[0, 1, 0].normalize * result[:overlap])
550
+ else
551
+ expect(result[:penetration]).to eq(Snow::Vec3[1, 0, 0].normalize * result[:overlap])
398
552
  end
553
+ end
399
554
 
400
- it 'does not collide if the shapes are far apart' do
401
- clean_sprite(@sprite1)
402
- @sprite1.x = 0
403
- @sprite1.y = 0
555
+ it 'returns a vector that separates the shapes' do
556
+ result = Gosling::Collision.get_collision_info(@sprite1, @sprite2)
557
+ @sprite2.pos += result[:penetration] * (1 + FLOAT_TOLERANCE)
558
+ expect(Gosling::Collision.test(@sprite1, @sprite2)).to be false
559
+ end
404
560
 
405
- clean_sprite(@sprite2)
406
- @sprite2.x = 17
407
- @sprite2.y = 8
561
+ it 'does not collide if the shapes are far apart' do
562
+ @sprite2.x = 17
408
563
 
409
- expect(Gosling::Collision.test(@sprite1, @sprite2)).to be false
410
- end
564
+ expect(Gosling::Collision.test(@sprite1, @sprite2)).to be false
565
+ result = Gosling::Collision.get_collision_info(@sprite1, @sprite2)
566
+ expect(result[:colliding]).to be false
567
+ expect(result[:overlap]).to be nil
568
+ expect(result[:penetration]).to be nil
411
569
  end
412
570
  end
413
571
 
@@ -428,124 +586,172 @@ describe Gosling::Collision do
428
586
  end
429
587
 
430
588
  context 'point vs. circle' do
431
- it 'returns true if point is in shape' do
589
+ before do
432
590
  clean_shape(@circle1)
433
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 0, 0], @circle1)).to be true
434
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, 0, 0], @circle1)).to be true
435
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, 0, 0], @circle1)).to be true
436
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 4, 0], @circle1)).to be true
437
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -4, 0], @circle1)).to be true
438
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[5, 0, 0], @circle1)).to be true
439
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-5, 0, 0], @circle1)).to be true
440
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 5, 0], @circle1)).to be true
441
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -5, 0], @circle1)).to be true
591
+ end
592
+
593
+ it 'returns true if point is in shape' do
594
+ points = [
595
+ Snow::Vec3[0, 0, 0],
596
+ Snow::Vec3[4, 0, 0],
597
+ Snow::Vec3[-4, 0, 0],
598
+ Snow::Vec3[0, 4, 0],
599
+ Snow::Vec3[0, -4, 0],
600
+ Snow::Vec3[5, 0, 0],
601
+ Snow::Vec3[-5, 0, 0],
602
+ Snow::Vec3[0, 5, 0],
603
+ Snow::Vec3[0, -5, 0],
604
+ ]
605
+ points.each do |p|
606
+ expect(Gosling::Collision.is_point_in_shape?(p, @circle1)).to be true
607
+ end
442
608
  end
443
609
 
444
610
  it 'returns false if point is not in shape' do
445
- clean_shape(@circle1)
446
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[6, 0, 0], @circle1)).to be false
447
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-6, 0, 0], @circle1)).to be false
448
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 6, 0], @circle1)).to be false
449
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -6, 0], @circle1)).to be false
450
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, 4, 0], @circle1)).to be false
451
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, 4, 0], @circle1)).to be false
452
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, -4, 0], @circle1)).to be false
453
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, -4, 0], @circle1)).to be false
611
+ points = [
612
+ Snow::Vec3[6, 0, 0],
613
+ Snow::Vec3[-6, 0, 0],
614
+ Snow::Vec3[0, 6, 0],
615
+ Snow::Vec3[0, -6, 0],
616
+ Snow::Vec3[4, 4, 0],
617
+ Snow::Vec3[-4, 4, 0],
618
+ Snow::Vec3[-4, -4, 0],
619
+ Snow::Vec3[4, -4, 0],
620
+ ]
621
+ points.each do |p|
622
+ expect(Gosling::Collision.is_point_in_shape?(p, @circle1)).to be false
623
+ end
454
624
  end
455
625
  end
456
626
 
457
627
  context 'point vs. polygon' do
458
- it 'returns true if point is in shape' do
628
+ before do
459
629
  clean_shape(@polygon1)
460
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 0, 0], @polygon1)).to be true
461
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 4, 0], @polygon1)).to be true
462
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -4, 0], @polygon1)).to be true
463
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, -4, 0], @polygon1)).to be true
464
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, -4, 0], @polygon1)).to be true
465
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 5, 0], @polygon1)).to be true
466
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -5, 0], @polygon1)).to be true
467
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[5, -5, 0], @polygon1)).to be true
468
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-5, -5, 0], @polygon1)).to be true
630
+ end
631
+
632
+ it 'returns true if point is in shape' do
633
+ points = [
634
+ Snow::Vec3[0, 0, 0],
635
+ Snow::Vec3[0, 4, 0],
636
+ Snow::Vec3[0, -4, 0],
637
+ Snow::Vec3[4, -4, 0],
638
+ Snow::Vec3[-4, -4, 0],
639
+ Snow::Vec3[0, 5, 0],
640
+ Snow::Vec3[0, -5, 0],
641
+ Snow::Vec3[5, -5, 0],
642
+ Snow::Vec3[-5, -5, 0],
643
+ ]
644
+ points.each do |p|
645
+ expect(Gosling::Collision.is_point_in_shape?(p, @polygon1)).to be true
646
+ end
469
647
  end
470
648
 
471
649
  it 'returns false if point is not in shape' do
472
- clean_shape(@polygon1)
473
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 6, 0], @polygon1)).to be false
474
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -6, 0], @polygon1)).to be false
475
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[6, -6, 0], @polygon1)).to be false
476
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-6, -6, 0], @polygon1)).to be false
477
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, 4, 0], @polygon1)).to be false
478
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, 4, 0], @polygon1)).to be false
650
+ points = [
651
+ Snow::Vec3[0, 6, 0],
652
+ Snow::Vec3[0, -6, 0],
653
+ Snow::Vec3[6, -6, 0],
654
+ Snow::Vec3[-6, -6, 0],
655
+ Snow::Vec3[4, 4, 0],
656
+ Snow::Vec3[-4, 4, 0],
657
+ ]
658
+ points.each do |p|
659
+ expect(Gosling::Collision.is_point_in_shape?(p, @polygon1)).to be false
660
+ end
479
661
  end
480
662
  end
481
663
 
482
664
  context 'point vs. rect' do
483
- it 'returns true if point is in shape' do
665
+ before do
484
666
  clean_rect(@rect1)
485
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 0, 0], @rect1)).to be true
486
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, -4, 0], @rect1)).to be true
487
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -4, 0], @rect1)).to be true
488
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, -4, 0], @rect1)).to be true
489
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, 0, 0], @rect1)).to be true
490
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[4, 4, 0], @rect1)).to be true
491
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 4, 0], @rect1)).to be true
492
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, 4, 0], @rect1)).to be true
493
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-4, 0, 0], @rect1)).to be true
494
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-5, -5, 0], @rect1)).to be true
495
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -5, 0], @rect1)).to be true
496
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[5, -5, 0], @rect1)).to be true
497
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[5, 0, 0], @rect1)).to be true
498
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[5, 5, 0], @rect1)).to be true
499
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 5, 0], @rect1)).to be true
500
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-5, 5, 0], @rect1)).to be true
501
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-5, 0, 0], @rect1)).to be true
667
+ end
668
+
669
+ it 'returns true if point is in shape' do
670
+ points = [
671
+ Snow::Vec3[0, 0, 0],
672
+ Snow::Vec3[-4, -4, 0],
673
+ Snow::Vec3[0, -4, 0],
674
+ Snow::Vec3[4, -4, 0],
675
+ Snow::Vec3[4, 0, 0],
676
+ Snow::Vec3[4, 4, 0],
677
+ Snow::Vec3[0, 4, 0],
678
+ Snow::Vec3[-4, 4, 0],
679
+ Snow::Vec3[-4, 0, 0],
680
+ Snow::Vec3[-5, -5, 0],
681
+ Snow::Vec3[0, -5, 0],
682
+ Snow::Vec3[5, -5, 0],
683
+ Snow::Vec3[5, 0, 0],
684
+ Snow::Vec3[5, 5, 0],
685
+ Snow::Vec3[0, 5, 0],
686
+ Snow::Vec3[-5, 5, 0],
687
+ Snow::Vec3[-5, 0, 0],
688
+ ]
689
+ points.each do |p|
690
+ expect(Gosling::Collision.is_point_in_shape?(p, @rect1)).to be true
691
+ end
502
692
  end
503
693
 
504
694
  it 'returns false if point is not in shape' do
505
- clean_rect(@rect1)
506
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-6, -6, 0], @rect1)).to be false
507
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -6, 0], @rect1)).to be false
508
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[6, -6, 0], @rect1)).to be false
509
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[6, 0, 0], @rect1)).to be false
510
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[6, 6, 0], @rect1)).to be false
511
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 6, 0], @rect1)).to be false
512
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-6, 6, 0], @rect1)).to be false
513
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-6, 0, 0], @rect1)).to be false
695
+ points = [
696
+ Snow::Vec3[-6, -6, 0],
697
+ Snow::Vec3[0, -6, 0],
698
+ Snow::Vec3[6, -6, 0],
699
+ Snow::Vec3[6, 0, 0],
700
+ Snow::Vec3[6, 6, 0],
701
+ Snow::Vec3[0, 6, 0],
702
+ Snow::Vec3[-6, 6, 0],
703
+ Snow::Vec3[-6, 0, 0],
704
+ ]
705
+ points.each do |p|
706
+ expect(Gosling::Collision.is_point_in_shape?(p, @rect1)).to be false
707
+ end
514
708
  end
515
709
  end
516
710
 
517
711
  context 'point vs. sprite' do
518
- it 'returns true if point is in shape' do
712
+ before do
519
713
  clean_sprite(@sprite1)
520
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 0, 0], @sprite1)).to be true
521
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-7, -7, 0], @sprite1)).to be true
522
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -7, 0], @sprite1)).to be true
523
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[7, -7, 0], @sprite1)).to be true
524
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[7, 0, 0], @sprite1)).to be true
525
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[7, 7, 0], @sprite1)).to be true
526
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 7, 0], @sprite1)).to be true
527
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-7, 7, 0], @sprite1)).to be true
528
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-7, 0, 0], @sprite1)).to be true
529
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-8, -8, 0], @sprite1)).to be true
530
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -8, 0], @sprite1)).to be true
531
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[8, -8, 0], @sprite1)).to be true
532
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[8, 0, 0], @sprite1)).to be true
533
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[8, 8, 0], @sprite1)).to be true
534
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 8, 0], @sprite1)).to be true
535
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-8, 8, 0], @sprite1)).to be true
536
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-8, 0, 0], @sprite1)).to be true
714
+ end
715
+
716
+ it 'returns true if point is in shape' do
717
+ points = [
718
+ Snow::Vec3[0, 0, 0],
719
+ Snow::Vec3[-7, -7, 0],
720
+ Snow::Vec3[0, -7, 0],
721
+ Snow::Vec3[7, -7, 0],
722
+ Snow::Vec3[7, 0, 0],
723
+ Snow::Vec3[7, 7, 0],
724
+ Snow::Vec3[0, 7, 0],
725
+ Snow::Vec3[-7, 7, 0],
726
+ Snow::Vec3[-7, 0, 0],
727
+ Snow::Vec3[-8, -8, 0],
728
+ Snow::Vec3[0, -8, 0],
729
+ Snow::Vec3[8, -8, 0],
730
+ Snow::Vec3[8, 0, 0],
731
+ Snow::Vec3[8, 8, 0],
732
+ Snow::Vec3[0, 8, 0],
733
+ Snow::Vec3[-8, 8, 0],
734
+ Snow::Vec3[-8, 0, 0],
735
+ ]
736
+ points.each do |p|
737
+ expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-8, 0, 0], @sprite1)).to be true
738
+ end
537
739
  end
538
740
 
539
741
  it 'returns false if point is not in shape' do
540
- clean_sprite(@sprite1)
541
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-9, -9, 0], @sprite1)).to be false
542
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, -9, 0], @sprite1)).to be false
543
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[9, -9, 0], @sprite1)).to be false
544
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[9, 0, 0], @sprite1)).to be false
545
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[9, 9, 0], @sprite1)).to be false
546
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 9, 0], @sprite1)).to be false
547
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-9, 9, 0], @sprite1)).to be false
548
- expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-9, 0, 0], @sprite1)).to be false
742
+ points = [
743
+ Snow::Vec3[-9, -9, 0],
744
+ Snow::Vec3[0, -9, 0],
745
+ Snow::Vec3[9, -9, 0],
746
+ Snow::Vec3[9, 0, 0],
747
+ Snow::Vec3[9, 9, 0],
748
+ Snow::Vec3[0, 9, 0],
749
+ Snow::Vec3[-9, 9, 0],
750
+ Snow::Vec3[-9, 0, 0],
751
+ ]
752
+ points.each do |p|
753
+ expect(Gosling::Collision.is_point_in_shape?(Snow::Vec3[-9, 0, 0], @sprite1)).to be false
754
+ end
549
755
  end
550
756
  end
551
757
  end
@@ -677,6 +883,11 @@ describe Gosling::Collision do
677
883
  end
678
884
 
679
885
  describe '#get_circle_separation_axis' do
886
+ before do
887
+ clean_shape(@circle1)
888
+ clean_shape(@circle2)
889
+ end
890
+
680
891
  it 'expects two shape arguments' do
681
892
  expect { Gosling::Collision.get_circle_separation_axis(@circle1, @circle2) }.not_to raise_error
682
893
  expect { Gosling::Collision.get_circle_separation_axis(@circle1, @polygon1) }.not_to raise_error
@@ -690,11 +901,9 @@ describe Gosling::Collision do
690
901
  end
691
902
 
692
903
  it 'returns a 3d vector' do
693
- clean_shape(@circle1)
694
904
  @circle1.x = 0
695
905
  @circle1.y = 0
696
906
 
697
- clean_shape(@circle2)
698
907
  @circle2.x = 10
699
908
  @circle2.y = -5
700
909
 
@@ -703,11 +912,9 @@ describe Gosling::Collision do
703
912
  end
704
913
 
705
914
  it "returns nil if distance beween shape centers is 0" do
706
- clean_shape(@circle1)
707
915
  @circle1.x = 0
708
916
  @circle1.y = 0
709
917
 
710
- clean_shape(@circle2)
711
918
  @circle2.x = 0
712
919
  @circle2.y = 0
713
920
 
@@ -716,11 +923,9 @@ describe Gosling::Collision do
716
923
  end
717
924
 
718
925
  it 'returns a correct unit vector' do
719
- clean_shape(@circle1)
720
926
  @circle1.x = 5
721
927
  @circle1.y = -10
722
928
 
723
- clean_shape(@circle2)
724
929
  @circle2.x = 10
725
930
  @circle2.y = -5
726
931
 
@@ -933,8 +1138,11 @@ describe Gosling::Collision do
933
1138
  end
934
1139
 
935
1140
  context 'with a circle' do
936
- it 'returns expected values' do
1141
+ before do
937
1142
  clean_shape(@circle1)
1143
+ end
1144
+
1145
+ it 'returns expected values' do
938
1146
  @circle1.x = 0
939
1147
  @circle1.y = 0
940
1148
  @circle1.radius = 5
@@ -954,7 +1162,6 @@ describe Gosling::Collision do
954
1162
  end
955
1163
 
956
1164
  it 'respects centering' do
957
- clean_shape(@circle1)
958
1165
  @circle1.center_x = 3
959
1166
  @circle1.center_y = 6
960
1167
 
@@ -968,7 +1175,6 @@ describe Gosling::Collision do
968
1175
  end
969
1176
 
970
1177
  it 'respects scaling' do
971
- clean_shape(@circle1)
972
1178
  @circle1.scale_x = 2
973
1179
  @circle1.scale_y = 0.5
974
1180
 
@@ -982,7 +1188,6 @@ describe Gosling::Collision do
982
1188
  end
983
1189
 
984
1190
  it 'respects rotation' do
985
- clean_shape(@circle1)
986
1191
  @circle1.rotation = Math::PI
987
1192
 
988
1193
  axis = Snow::Vec3[1, 0, 0].normalize
@@ -991,7 +1196,6 @@ describe Gosling::Collision do
991
1196
  end
992
1197
 
993
1198
  it 'respects translation' do
994
- clean_shape(@circle1)
995
1199
  @circle1.x = -12
996
1200
  @circle1.y = 23
997
1201
 
@@ -1017,11 +1221,13 @@ describe Gosling::Collision do
1017
1221
 
1018
1222
  axis = Snow::Vec3[0, 1, 0].normalize
1019
1223
  result = Gosling::Collision.project_onto_axis(circle, axis)
1020
- expect(result).to be == [290.0, 340.0]
1224
+ expect(result[0]).to be_within(FLOAT_TOLERANCE).of(290.0)
1225
+ expect(result[1]).to be_within(FLOAT_TOLERANCE).of(340.0)
1021
1226
 
1022
1227
  axis = Snow::Vec3[1, 1, 0].normalize
1023
1228
  result = Gosling::Collision.project_onto_axis(circle, axis)
1024
- expect(result).to be == [-443.1343965537543, -385.5947509968793]
1229
+ expect(result[0]).to be_within(FLOAT_TOLERANCE).of(-443.1343965537543)
1230
+ expect(result[1]).to be_within(FLOAT_TOLERANCE).of(-385.5947509968793)
1025
1231
 
1026
1232
  break_inheritance_chain([@center_actor, @scale_actor, @rotate_actor, @translate_actor, circle])
1027
1233
  end
@@ -1120,11 +1326,13 @@ describe Gosling::Collision do
1120
1326
 
1121
1327
  axis = Snow::Vec3[0, 1, 0].normalize
1122
1328
  result = Gosling::Collision.project_onto_axis(polygon, axis)
1123
- expect(result).to be == [302.5, 327.5]
1329
+ expect(result[0]).to be_within(FLOAT_TOLERANCE).of(302.5)
1330
+ expect(result[1]).to be_within(FLOAT_TOLERANCE).of(327.5)
1124
1331
 
1125
1332
  axis = Snow::Vec3[1, 1, 0].normalize
1126
1333
  result = Gosling::Collision.project_onto_axis(polygon, axis)
1127
- expect(result).to be == [-426.7389424460814, -393.1513703397204]
1334
+ expect(result[0]).to be_within(FLOAT_TOLERANCE).of(-426.7389424460814)
1335
+ expect(result[1]).to be_within(FLOAT_TOLERANCE).of(-393.1513703397204)
1128
1336
 
1129
1337
  break_inheritance_chain([@center_actor, @scale_actor, @rotate_actor, @translate_actor, polygon])
1130
1338
  end
@@ -1175,9 +1383,74 @@ describe Gosling::Collision do
1175
1383
  end
1176
1384
 
1177
1385
  context 'when a touches b' do
1178
- it 'returns true' do
1179
- expect(Gosling::Collision.projections_overlap?([-10, 0], [0, 10])).to be true
1180
- expect(Gosling::Collision.projections_overlap?([-5, 30], [-17, -5])).to be true
1386
+ it 'returns false' do
1387
+ expect(Gosling::Collision.projections_overlap?([-10, 0], [0, 10])).to be false
1388
+ expect(Gosling::Collision.projections_overlap?([-5, 30], [-17, -5])).to be false
1389
+ end
1390
+ end
1391
+
1392
+ context 'when a just barely overlaps b' do
1393
+ it 'returns false' do
1394
+ expect(Gosling::Collision.projections_overlap?([-10, 0.0000001], [0, 10])).to be false
1395
+ expect(Gosling::Collision.projections_overlap?([-4.999999999, 30], [-17, -5])).to be false
1396
+ end
1397
+ end
1398
+ end
1399
+
1400
+ describe '#get_overlap' do
1401
+ it 'accepts two length 2 arrays with numbers' do
1402
+ expect { Gosling::Collision.get_overlap([0, 0], [0, 0]) }.not_to raise_error
1403
+ expect { Gosling::Collision.get_overlap([1, 2], [3, -4]) }.not_to raise_error
1404
+
1405
+ expect { Gosling::Collision.get_overlap([1, 2, 3], [4, 5, 6]) }.to raise_error(ArgumentError)
1406
+ expect { Gosling::Collision.get_overlap([1], [4]) }.to raise_error(ArgumentError)
1407
+ expect { Gosling::Collision.get_overlap([1, 2], [3, -4], [5, 6]) }.to raise_error(ArgumentError)
1408
+ expect { Gosling::Collision.get_overlap([1, 2]) }.to raise_error(ArgumentError)
1409
+ expect { Gosling::Collision.get_overlap([1, 2], :foo) }.to raise_error(ArgumentError)
1410
+ expect { Gosling::Collision.get_overlap(nil, [1, 2]) }.to raise_error(ArgumentError)
1411
+ end
1412
+
1413
+ context 'when a and b do not overlap' do
1414
+ it 'returns nil' do
1415
+ expect(Gosling::Collision.get_overlap([0, 10], [20, 30])).to be_nil
1416
+ expect(Gosling::Collision.get_overlap([-20, -30], [0, 10])).to be_nil
1417
+ end
1418
+ end
1419
+
1420
+ context 'when a contains b' do
1421
+ it 'returns the length of b' do
1422
+ expect(Gosling::Collision.get_overlap([0, 40], [20, 30])).to eq(10)
1423
+ expect(Gosling::Collision.get_overlap([-40, 0], [-25, -15])).to eq(10)
1424
+ expect(Gosling::Collision.get_overlap([-2, 0], [-1, 0])).to eq(1)
1425
+ end
1426
+ end
1427
+
1428
+ context 'when b contains a' do
1429
+ it 'returns the length of a' do
1430
+ expect(Gosling::Collision.get_overlap([5, 10], [0, 50])).to eq(5)
1431
+ expect(Gosling::Collision.get_overlap([-10, 10], [-25, 25])).to eq(20)
1432
+ expect(Gosling::Collision.get_overlap([5, 6], [5, 10])).to eq(1)
1433
+ end
1434
+ end
1435
+
1436
+ context 'when a overlaps b' do
1437
+ it 'returns the length that overlaps' do
1438
+ expect(Gosling::Collision.get_overlap([-10, 10], [0, 20])).to eq(10)
1439
+ expect(Gosling::Collision.get_overlap([-1000, 0], [-1, 314159])).to eq(1)
1440
+ end
1441
+ end
1442
+
1443
+ context 'when a touches b' do
1444
+ it 'returns zero' do
1445
+ expect(Gosling::Collision.get_overlap([-10, 0], [0, 10])).to eq(0)
1446
+ expect(Gosling::Collision.get_overlap([-5, 30], [-17, -5])).to eq(0)
1447
+ end
1448
+ end
1449
+
1450
+ context 'when a just barely overlaps b' do
1451
+ it 'returns a very tiny value' do
1452
+ expect(Gosling::Collision.get_overlap([-10, 0.0000001], [0, 10])).to eq(0.0000001)
1453
+ expect(Gosling::Collision.get_overlap([-5, 30], [-17, -4.999999999])).to be_within(0.00000001).of(0)
1181
1454
  end
1182
1455
  end
1183
1456
  end