gosling 2.0.1 → 2.1.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.
@@ -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