gosling 2.1.0 → 2.3.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,21 @@
1
+ require_relative 'object_cache.rb'
2
+
3
+ class VectorCache
4
+ include Singleton
5
+ include ObjectCache
6
+
7
+ def initialize
8
+ @cache = {}
9
+ end
10
+
11
+ protected
12
+
13
+ def create
14
+ Snow::Vec3.new
15
+ end
16
+
17
+ def reset(vector)
18
+ type_check(vector, Snow::Vec3)
19
+ vector.set(0, 0, 0)
20
+ end
21
+ end
@@ -3,5 +3,5 @@
3
3
  # MINOR version when you add functionality in a backwards-compatible manner, and
4
4
  # PATCH version when you make backwards-compatible bug fixes.
5
5
  module Gosling
6
- VERSION = '2.1.0'
6
+ VERSION = '2.3.0'
7
7
  end
@@ -1,5 +1,27 @@
1
1
  require 'set'
2
2
 
3
+ module Gosling
4
+ class Collision
5
+ def self.collision_buffer
6
+ @@collision_buffer
7
+ end
8
+
9
+ def self.global_vertices_cache
10
+ @@global_vertices_cache
11
+ end
12
+
13
+ def self.global_position_cache
14
+ @@global_position_cache
15
+ end
16
+
17
+ def self.global_transform_cache
18
+ @@global_transform_cache
19
+ end
20
+
21
+ public_class_method :reset_separation_axes, :separation_axes
22
+ end
23
+ end
24
+
3
25
  def angle_to_vector(angle)
4
26
  Snow::Vec3[Math.sin(angle).round(12), Math.cos(angle).round(12), 0]
5
27
  end
@@ -117,11 +139,17 @@ describe Gosling::Collision do
117
139
  @angles = (0...ANGLE_COUNT).map { |i| Math::PI * 2 * i / ANGLE_COUNT }
118
140
  end
119
141
 
142
+ before do
143
+ Gosling::Collision.reset_separation_axes
144
+ end
145
+
120
146
  context 'any actor vs. itself' do
121
147
  it 'never collides' do
122
148
  [@actor1, @circle1, @polygon1, @rect1, @sprite1].each do |actor|
123
149
  expect(Gosling::Collision.test(actor, actor)).to be false
124
150
  result = Gosling::Collision.get_collision_info(actor, actor)
151
+ expect(result[:actors]).to include(actor)
152
+ expect(result[:actors].length).to eq(2)
125
153
  expect(result[:colliding]).to be false
126
154
  expect(result[:overlap]).to be nil
127
155
  expect(result[:penetration]).to be nil
@@ -141,6 +169,7 @@ describe Gosling::Collision do
141
169
  pairs.each do |pair|
142
170
  expect(Gosling::Collision.test(*pair)).to be false
143
171
  result = Gosling::Collision.get_collision_info(*pair)
172
+ expect(result[:actors]).to include(*pair)
144
173
  expect(result[:colliding]).to be false
145
174
  expect(result[:overlap]).to be nil
146
175
  expect(result[:penetration]).to be nil
@@ -162,6 +191,7 @@ describe Gosling::Collision do
162
191
  it 'collides if the shapes are close enough' do
163
192
  expect(Gosling::Collision.test(@circle1, @circle2)).to be true
164
193
  result = Gosling::Collision.get_collision_info(@circle1, @circle2)
194
+ expect(result[:actors]).to include(@circle1, @circle2)
165
195
  expect(result[:colliding]).to be true
166
196
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(10 - Math.sqrt(50))
167
197
  expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
@@ -192,6 +222,7 @@ describe Gosling::Collision do
192
222
  expect(Gosling::Collision.test(@circle1, @circle2)).to be false
193
223
 
194
224
  result = Gosling::Collision.get_collision_info(@circle1, @circle2)
225
+ expect(result[:actors]).to include(@circle1, @circle2)
195
226
  expect(result[:colliding]).to be false
196
227
  expect(result[:overlap]).to be nil
197
228
  expect(result[:penetration]).to be nil
@@ -212,6 +243,7 @@ describe Gosling::Collision do
212
243
  it 'collides if the shapes are close enough' do
213
244
  expect(Gosling::Collision.test(@circle1, @polygon1)).to be true
214
245
  result = Gosling::Collision.get_collision_info(@circle1, @polygon1)
246
+ expect(result[:actors]).to include(@circle1, @polygon1)
215
247
  expect(result[:colliding]).to be true
216
248
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
217
249
  expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
@@ -229,6 +261,7 @@ describe Gosling::Collision do
229
261
 
230
262
  expect(Gosling::Collision.test(@circle1, @polygon1)).to be false
231
263
  result = Gosling::Collision.get_collision_info(@circle1, @polygon1)
264
+ expect(result[:actors]).to include(@circle1, @polygon1)
232
265
  expect(result[:colliding]).to be false
233
266
  expect(result[:overlap]).to be nil
234
267
  expect(result[:penetration]).to be nil
@@ -249,6 +282,7 @@ describe Gosling::Collision do
249
282
  it 'collides if the shapes are close enough' do
250
283
  expect(Gosling::Collision.test(@circle1, @rect1)).to be true
251
284
  result = Gosling::Collision.get_collision_info(@circle1, @rect1)
285
+ expect(result[:actors]).to include(@circle1, @rect1)
252
286
  expect(result[:colliding]).to be true
253
287
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
254
288
  expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
@@ -266,6 +300,7 @@ describe Gosling::Collision do
266
300
 
267
301
  expect(Gosling::Collision.test(@circle1, @rect1)).to be false
268
302
  result = Gosling::Collision.get_collision_info(@circle1, @rect1)
303
+ expect(result[:actors]).to include(@circle1, @rect1)
269
304
  expect(result[:colliding]).to be false
270
305
  expect(result[:overlap]).to be nil
271
306
  expect(result[:penetration]).to be nil
@@ -286,6 +321,7 @@ describe Gosling::Collision do
286
321
  it 'collides if the shapes are close enough' do
287
322
  expect(Gosling::Collision.test(@circle1, @sprite1)).to be true
288
323
  result = Gosling::Collision.get_collision_info(@circle1, @sprite1)
324
+ expect(result[:actors]).to include(@circle1, @sprite1)
289
325
  expect(result[:colliding]).to be true
290
326
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
291
327
  expect(result[:penetration]).to eq(Snow::Vec3[1, 1, 0].normalize * result[:overlap])
@@ -303,6 +339,7 @@ describe Gosling::Collision do
303
339
 
304
340
  expect(Gosling::Collision.test(@circle1, @sprite1)).to be false
305
341
  result = Gosling::Collision.get_collision_info(@circle1, @sprite1)
342
+ expect(result[:actors]).to include(@circle1, @sprite1)
306
343
  expect(result[:colliding]).to be false
307
344
  expect(result[:overlap]).to be nil
308
345
  expect(result[:penetration]).to be nil
@@ -323,12 +360,13 @@ describe Gosling::Collision do
323
360
  it 'collides if the shapes are close enough' do
324
361
  expect(Gosling::Collision.test(@polygon1, @polygon2)).to be true
325
362
  result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
363
+ expect(result[:actors]).to include(@polygon1, @polygon2)
326
364
  expect(result[:colliding]).to be true
327
365
  axis = Snow::Vec2[-10, -5].normalize
328
366
  a = Snow::Vec2[0, 0].dot_product(axis)
329
367
  b = Snow::Vec2[0, 5].dot_product(axis)
330
368
  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])
369
+ expect(result[:penetration]).to eq(Snow::Vec3[-2, 1, 0].normalize * result[:overlap])
332
370
  end
333
371
 
334
372
  it 'returns a vector that separates the shapes' do
@@ -365,6 +403,7 @@ describe Gosling::Collision do
365
403
 
366
404
  expect(Gosling::Collision.test(@polygon1, @polygon2)).to be false
367
405
  result = Gosling::Collision.get_collision_info(@polygon1, @polygon2)
406
+ expect(result[:actors]).to include(@polygon1, @polygon2)
368
407
  expect(result[:colliding]).to be false
369
408
  expect(result[:overlap]).to be nil
370
409
  expect(result[:penetration]).to be nil
@@ -385,6 +424,7 @@ describe Gosling::Collision do
385
424
  it 'collides if the shapes are close enough' do
386
425
  expect(Gosling::Collision.test(@polygon1, @rect1)).to be true
387
426
  result = Gosling::Collision.get_collision_info(@polygon1, @rect1)
427
+ expect(result[:actors]).to include(@polygon1, @rect1)
388
428
  expect(result[:colliding]).to be true
389
429
  axis = Snow::Vec2[-10, -5].normalize
390
430
  a = Snow::Vec2[0, 0].dot_product(axis)
@@ -404,6 +444,7 @@ describe Gosling::Collision do
404
444
 
405
445
  expect(Gosling::Collision.test(@polygon1, @rect1)).to be false
406
446
  result = Gosling::Collision.get_collision_info(@polygon1, @rect1)
447
+ expect(result[:actors]).to include(@polygon1, @rect1)
407
448
  expect(result[:colliding]).to be false
408
449
  expect(result[:overlap]).to be nil
409
450
  expect(result[:penetration]).to be nil
@@ -424,6 +465,7 @@ describe Gosling::Collision do
424
465
  it 'collides if the shapes are close enough' do
425
466
  expect(Gosling::Collision.test(@polygon1, @sprite1)).to be true
426
467
  result = Gosling::Collision.get_collision_info(@polygon1, @sprite1)
468
+ expect(result[:actors]).to include(@polygon1, @sprite1)
427
469
  expect(result[:colliding]).to be true
428
470
  axis = Snow::Vec2[-10, -5].normalize
429
471
  a = Snow::Vec2[0, 0].dot_product(axis)
@@ -443,6 +485,7 @@ describe Gosling::Collision do
443
485
 
444
486
  expect(Gosling::Collision.test(@polygon1, @sprite1)).to be false
445
487
  result = Gosling::Collision.get_collision_info(@polygon1, @sprite1)
488
+ expect(result[:actors]).to include(@polygon1, @sprite1)
446
489
  expect(result[:colliding]).to be false
447
490
  expect(result[:overlap]).to be nil
448
491
  expect(result[:penetration]).to be nil
@@ -463,6 +506,7 @@ describe Gosling::Collision do
463
506
  it 'collides if the shapes are close enough' do
464
507
  expect(Gosling::Collision.test(@rect1, @rect2)).to be true
465
508
  result = Gosling::Collision.get_collision_info(@rect1, @rect2)
509
+ expect(result[:actors]).to include(@rect1, @rect2)
466
510
  expect(result[:colliding]).to be true
467
511
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
468
512
  if result[:penetration].x == 0
@@ -483,6 +527,7 @@ describe Gosling::Collision do
483
527
 
484
528
  expect(Gosling::Collision.test(@rect1, @rect2)).to be false
485
529
  result = Gosling::Collision.get_collision_info(@rect1, @rect2)
530
+ expect(result[:actors]).to include(@rect1, @rect2)
486
531
  expect(result[:colliding]).to be false
487
532
  expect(result[:overlap]).to be nil
488
533
  expect(result[:penetration]).to be nil
@@ -503,6 +548,7 @@ describe Gosling::Collision do
503
548
  it 'collides if the shapes are close enough' do
504
549
  expect(Gosling::Collision.test(@rect1, @sprite1)).to be true
505
550
  result = Gosling::Collision.get_collision_info(@rect1, @sprite1)
551
+ expect(result[:actors]).to include(@rect1, @sprite1)
506
552
  expect(result[:colliding]).to be true
507
553
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(5)
508
554
  if result[:penetration].x == 0
@@ -523,6 +569,7 @@ describe Gosling::Collision do
523
569
 
524
570
  expect(Gosling::Collision.test(@rect1, @sprite1)).to be false
525
571
  result = Gosling::Collision.get_collision_info(@rect1, @sprite1)
572
+ expect(result[:actors]).to include(@rect1, @sprite1)
526
573
  expect(result[:colliding]).to be false
527
574
  expect(result[:overlap]).to be nil
528
575
  expect(result[:penetration]).to be nil
@@ -543,6 +590,7 @@ describe Gosling::Collision do
543
590
  it 'collides if the shapes are close enough' do
544
591
  expect(Gosling::Collision.test(@sprite1, @sprite2)).to be true
545
592
  result = Gosling::Collision.get_collision_info(@sprite1, @sprite2)
593
+ expect(result[:actors]).to include(@sprite1, @sprite2)
546
594
  expect(result[:colliding]).to be true
547
595
  expect(result[:overlap]).to be_within(FLOAT_TOLERANCE).of(8)
548
596
  if result[:penetration].x == 0
@@ -563,13 +611,14 @@ describe Gosling::Collision do
563
611
 
564
612
  expect(Gosling::Collision.test(@sprite1, @sprite2)).to be false
565
613
  result = Gosling::Collision.get_collision_info(@sprite1, @sprite2)
614
+ expect(result[:actors]).to include(@sprite1, @sprite2)
566
615
  expect(result[:colliding]).to be false
567
616
  expect(result[:overlap]).to be nil
568
617
  expect(result[:penetration]).to be nil
569
618
  end
570
619
  end
571
620
 
572
- describe '#is_point_in_shape?' do
621
+ describe '.is_point_in_shape?' do
573
622
  it 'expects a point and an actor' do
574
623
  expect { Gosling::Collision.is_point_in_shape?(Snow::Vec3[0, 0, 0], @actor1) }.not_to raise_error
575
624
 
@@ -756,13 +805,13 @@ describe Gosling::Collision do
756
805
  end
757
806
  end
758
807
 
759
- describe '#get_normal' do
808
+ describe '.get_normal' do
760
809
  it 'expects a 3d vector' do
761
810
  expect { Gosling::Collision.get_normal(Snow::Vec3[1, 0, 0]) }.not_to raise_error
762
811
  expect { Gosling::Collision.get_normal(Snow::Vec3[1, 0, 1, 0]) }.to raise_error(ArgumentError)
763
812
  expect { Gosling::Collision.get_normal(Snow::Vec3[1, 0]) }.to raise_error(ArgumentError)
764
- expect { Gosling::Collision.get_normal(:foo) }.to raise_error(ArgumentError)
765
- expect { Gosling::Collision.get_normal(nil) }.to raise_error(ArgumentError)
813
+ expect { Gosling::Collision.get_normal(:foo) }.to raise_error
814
+ expect { Gosling::Collision.get_normal(nil) }.to raise_error
766
815
  end
767
816
 
768
817
  it 'returns a 3d vector' do
@@ -815,7 +864,7 @@ describe Gosling::Collision do
815
864
  end
816
865
  end
817
866
 
818
- describe '#get_polygon_separation_axes' do
867
+ describe '.get_polygon_separation_axes' do
819
868
  it 'expects an array of length 3 vectors' do
820
869
  good_vector_array = [
821
870
  Snow::Vec3[3, 1, 0],
@@ -833,10 +882,10 @@ describe Gosling::Collision do
833
882
  ]
834
883
  p = Gosling::Polygon.new(@window)
835
884
  expect { Gosling::Collision.get_polygon_separation_axes(good_vector_array) }.not_to raise_error
836
- expect { Gosling::Collision.get_polygon_separation_axes(bad_vector_array) }.to raise_error(ArgumentError)
885
+ expect { Gosling::Collision.get_polygon_separation_axes(bad_vector_array) }.to raise_error
837
886
  expect { Gosling::Collision.get_polygon_separation_axes(p.get_vertices) }.not_to raise_error
838
- expect { Gosling::Collision.get_polygon_separation_axes(p) }.to raise_error(ArgumentError)
839
- expect { Gosling::Collision.get_polygon_separation_axes(:foo) }.to raise_error(ArgumentError)
887
+ expect { Gosling::Collision.get_polygon_separation_axes(p) }.to raise_error
888
+ expect { Gosling::Collision.get_polygon_separation_axes(:foo) }.to raise_error
840
889
  end
841
890
 
842
891
  it 'returns an array of 3d vectors' do
@@ -847,7 +896,8 @@ describe Gosling::Collision do
847
896
  Snow::Vec3[1, 4, 0],
848
897
  Snow::Vec3[2, 5, 0]
849
898
  ]
850
- result = Gosling::Collision.get_polygon_separation_axes(vertices)
899
+ Gosling::Collision.get_polygon_separation_axes(vertices)
900
+ result = Gosling::Collision.separation_axes
851
901
  expect(result).to be_instance_of(Array)
852
902
  expect(result.reject { |v| v.is_a?(Snow::Vec3) }).to be_empty
853
903
  end
@@ -860,7 +910,8 @@ describe Gosling::Collision do
860
910
  Snow::Vec3[2, 2, 0],
861
911
  Snow::Vec3[2, 2, 0]
862
912
  ]
863
- result = Gosling::Collision.get_polygon_separation_axes(vertices)
913
+ Gosling::Collision.get_polygon_separation_axes(vertices)
914
+ result = Gosling::Collision.separation_axes
864
915
  expect(result.length).to be == 3
865
916
  end
866
917
 
@@ -872,17 +923,19 @@ describe Gosling::Collision do
872
923
  Snow::Vec3[-1, -1, 0],
873
924
  Snow::Vec3[-1, 2, 0]
874
925
  ]
875
- result = Gosling::Collision.get_polygon_separation_axes(vertices)
876
- expect(result.length).to be == 5
877
- expect(result[0]).to be == Snow::Vec3[ 2, -1, 0].normalize
878
- expect(result[1]).to be == Snow::Vec3[ 1, -1, 0].normalize
879
- expect(result[2]).to be == Snow::Vec3[-1, -1, 0].normalize
880
- expect(result[3]).to be == Snow::Vec3[-3, 0, 0].normalize
881
- expect(result[4]).to be == Snow::Vec3[ 1, 3, 0].normalize
926
+ Gosling::Collision.get_polygon_separation_axes(vertices)
927
+ result = Gosling::Collision.separation_axes
928
+ expect(result).to match_array([
929
+ Snow::Vec3[ 1, 3, 0].normalize,
930
+ Snow::Vec3[ 2, -1, 0].normalize,
931
+ Snow::Vec3[ 1, -1, 0].normalize,
932
+ Snow::Vec3[-1, -1, 0].normalize,
933
+ Snow::Vec3[-3, 0, 0].normalize
934
+ ])
882
935
  end
883
936
  end
884
937
 
885
- describe '#get_circle_separation_axis' do
938
+ describe '.get_circle_separation_axis' do
886
939
  before do
887
940
  clean_shape(@circle1)
888
941
  clean_shape(@circle2)
@@ -893,8 +946,8 @@ describe Gosling::Collision do
893
946
  expect { Gosling::Collision.get_circle_separation_axis(@circle1, @polygon1) }.not_to raise_error
894
947
  expect { Gosling::Collision.get_circle_separation_axis(@rect1, @circle2) }.not_to raise_error
895
948
 
896
- expect { Gosling::Collision.get_circle_separation_axis(:foo, @circle2) }.to raise_error(ArgumentError)
897
- expect { Gosling::Collision.get_circle_separation_axis(@circle1, @circle2, @circle1) }.to raise_error(ArgumentError)
949
+ expect { Gosling::Collision.get_circle_separation_axis(@circle1, @circle2, Snow::Vec3.new) }.to raise_error(ArgumentError)
950
+ expect { Gosling::Collision.get_circle_separation_axis(:foo, @circle2) }.to raise_error
898
951
  expect { Gosling::Collision.get_circle_separation_axis(@circle1) }.to raise_error(ArgumentError)
899
952
  expect { Gosling::Collision.get_circle_separation_axis() }.to raise_error(ArgumentError)
900
953
  expect { Gosling::Collision.get_circle_separation_axis(:foo) }.to raise_error(ArgumentError)
@@ -907,8 +960,10 @@ describe Gosling::Collision do
907
960
  @circle2.x = 10
908
961
  @circle2.y = -5
909
962
 
910
- result = Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
911
- expect(result).to be_instance_of(Snow::Vec3)
963
+ Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
964
+ result = Gosling::Collision.separation_axes
965
+ expect(result.length).to eq(1)
966
+ expect(result.first).to be_instance_of(Snow::Vec3)
912
967
  end
913
968
 
914
969
  it "returns nil if distance beween shape centers is 0" do
@@ -929,12 +984,14 @@ describe Gosling::Collision do
929
984
  @circle2.x = 10
930
985
  @circle2.y = -5
931
986
 
932
- result = Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
933
- expect(result).to be == Snow::Vec3[1, 1, 0].normalize
987
+ Gosling::Collision.get_circle_separation_axis(@circle1, @circle2)
988
+ result = Gosling::Collision.separation_axes
989
+ expect(result.length).to eq(1)
990
+ expect(result.first).to be == Snow::Vec3[1, 1, 0].normalize
934
991
  end
935
992
  end
936
993
 
937
- describe '#get_separation_axes' do
994
+ describe '.get_separation_axes' do
938
995
  it 'expects two shapes' do
939
996
  expect { Gosling::Collision.get_separation_axes(@circle1, @circle2) }.not_to raise_error
940
997
  expect { Gosling::Collision.get_separation_axes(@circle1, @polygon2) }.not_to raise_error
@@ -943,7 +1000,7 @@ describe Gosling::Collision do
943
1000
  expect { Gosling::Collision.get_separation_axes(@sprite1, @polygon2) }.not_to raise_error
944
1001
 
945
1002
  expect { Gosling::Collision.get_separation_axes(@actor1, @circle2) }.to raise_error(ArgumentError)
946
- expect { Gosling::Collision.get_separation_axes(@circle1, @circle2, @polygon2) }.to raise_error(ArgumentError)
1003
+ expect { Gosling::Collision.get_separation_axes(@circle1, @circle2, @polygon2) }.to raise_error
947
1004
  expect { Gosling::Collision.get_separation_axes(@circle1, 1) }.to raise_error(ArgumentError)
948
1005
  expect { Gosling::Collision.get_separation_axes(@polygon1, :foo) }.to raise_error(ArgumentError)
949
1006
  expect { Gosling::Collision.get_separation_axes(:foo) }.to raise_error(ArgumentError)
@@ -951,13 +1008,15 @@ describe Gosling::Collision do
951
1008
  end
952
1009
 
953
1010
  it 'returns an array of 3d vectors' do
954
- result = Gosling::Collision.get_separation_axes(@polygon1, @polygon2)
1011
+ Gosling::Collision.get_separation_axes(@polygon1, @polygon2)
1012
+ result = Gosling::Collision.separation_axes
955
1013
  expect(result).to be_instance_of(Array)
956
1014
  expect(result.reject { |v| v.is_a?(Snow::Vec3) }).to be_empty
957
1015
  end
958
1016
 
959
1017
  it 'returns only unit vectors' do
960
- result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1018
+ Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1019
+ result = Gosling::Collision.separation_axes
961
1020
  expect(result).to be_instance_of(Array)
962
1021
  result.each do |v|
963
1022
  expect(v).to be_instance_of(Snow::Vec3)
@@ -965,22 +1024,19 @@ describe Gosling::Collision do
965
1024
  end
966
1025
  end
967
1026
 
968
- it 'returns only right-facing (positive x direction) vectors' do
969
- result = Gosling::Collision.get_separation_axes(@rect2, @polygon1)
970
- expect(result).to be_instance_of(Array)
971
- expect(result.reject { |v| v.is_a?(Snow::Vec3) && v[0] >= 0 }).to be_empty
972
- end
973
-
974
1027
  it 'returns only unique vectors' do
975
- result = Gosling::Collision.get_separation_axes(@rect2, @polygon2)
1028
+ Gosling::Collision.get_separation_axes(@rect2, @polygon2)
1029
+ result = Gosling::Collision.separation_axes
976
1030
  expect(result).to be_instance_of(Array)
977
1031
  expect(result.uniq.length).to be == result.length
978
1032
  end
979
1033
 
980
1034
  it 'is commutative' do
981
- result1 = Gosling::Collision.get_separation_axes(@rect2, @polygon2)
982
- result2 = Gosling::Collision.get_separation_axes(@polygon2, @rect2)
983
- expect(result1.map { |x| x.to_s }.sort).to be == result2.map { |x| x.to_s }.sort
1035
+ Gosling::Collision.get_separation_axes(@rect2, @polygon2)
1036
+ result1 = Gosling::Collision.separation_axes.dup
1037
+ Gosling::Collision.get_separation_axes(@polygon2, @rect2)
1038
+ result2 = Gosling::Collision.separation_axes.dup
1039
+ expect(result1.map { |v| v.to_s }).to match_array(result2.map { |v| v.to_s })
984
1040
  end
985
1041
 
986
1042
  it 'respects centering' do
@@ -990,12 +1046,13 @@ describe Gosling::Collision do
990
1046
 
991
1047
  clean_shape(@circle1)
992
1048
 
993
- result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
994
- expect(result).to be == [
995
- Snow::Vec3[10, 5, 0].normalize,
996
- Snow::Vec3[0, -10, 0].normalize,
997
- Snow::Vec3[10, -5, 0].normalize
998
- ]
1049
+ Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1050
+ result = Gosling::Collision.separation_axes
1051
+ expect(result).to match_array([
1052
+ Snow::Vec3[10, 5, 0].normalize,
1053
+ Snow::Vec3[0, -10, 0].normalize,
1054
+ Snow::Vec3[-10, 5, 0].normalize
1055
+ ])
999
1056
  end
1000
1057
 
1001
1058
  it 'respects scaling' do
@@ -1005,26 +1062,28 @@ describe Gosling::Collision do
1005
1062
 
1006
1063
  clean_shape(@circle1)
1007
1064
 
1008
- result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1009
- expect(result).to be == [
1010
- Snow::Vec3[20, 15, 0].normalize,
1011
- Snow::Vec3[0, -30, 0].normalize,
1012
- Snow::Vec3[20, -15, 0].normalize
1013
- ]
1065
+ Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1066
+ result = Gosling::Collision.separation_axes
1067
+ expect(result).to match_array([
1068
+ Snow::Vec3[20, 15, 0].normalize,
1069
+ Snow::Vec3[0, -30, 0].normalize,
1070
+ Snow::Vec3[-20, 15, 0].normalize
1071
+ ])
1014
1072
  end
1015
1073
 
1016
1074
  it 'respects rotation' do
1017
1075
  clean_shape(@polygon1)
1018
1076
  @polygon1.rotation = Math::PI / 2
1019
- result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1077
+ Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1078
+ result = Gosling::Collision.separation_axes
1020
1079
 
1021
1080
  clean_shape(@circle1)
1022
1081
 
1023
- expect(result).to be == [
1024
- Snow::Vec3[5, -10, 0].normalize,
1025
- Snow::Vec3[10, 0, 0].normalize,
1026
- Snow::Vec3[5, 10, 0].normalize
1027
- ]
1082
+ expect(result).to match_array([
1083
+ Snow::Vec3[5, -10, 0].normalize,
1084
+ Snow::Vec3[-10, 0, 0].normalize,
1085
+ Snow::Vec3[5, 10, 0].normalize
1086
+ ])
1028
1087
  end
1029
1088
 
1030
1089
  it 'respects translation' do
@@ -1034,13 +1093,14 @@ describe Gosling::Collision do
1034
1093
 
1035
1094
  clean_shape(@circle1)
1036
1095
 
1037
- result = Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1038
- expect(result).to be == [
1039
- Snow::Vec3[10, 5, 0].normalize,
1040
- Snow::Vec3[0, -10, 0].normalize,
1041
- Snow::Vec3[10, -5, 0].normalize,
1042
- Snow::Vec3[50, -10, 0].normalize
1043
- ]
1096
+ Gosling::Collision.get_separation_axes(@polygon1, @circle1)
1097
+ result = Gosling::Collision.separation_axes
1098
+ expect(result).to match_array([
1099
+ Snow::Vec3[10, 5, 0].normalize,
1100
+ Snow::Vec3[0, -10, 0].normalize,
1101
+ Snow::Vec3[-10, 5, 0].normalize,
1102
+ Snow::Vec3[50, -10, 0].normalize
1103
+ ])
1044
1104
  end
1045
1105
 
1046
1106
  context 'with two polygons' do
@@ -1062,7 +1122,8 @@ describe Gosling::Collision do
1062
1122
  [@rect2, @sprite2],
1063
1123
  [@sprite1, @sprite2]
1064
1124
  ].each do |shapes|
1065
- result = Gosling::Collision.get_separation_axes(*shapes)
1125
+ Gosling::Collision.get_separation_axes(*shapes)
1126
+ result = Gosling::Collision.separation_axes
1066
1127
  vertex_count = 0
1067
1128
  shapes.each { |s| vertex_count += s.get_vertices.length }
1068
1129
  expect(result.length).to be_between(2, vertex_count).inclusive
@@ -1077,7 +1138,8 @@ describe Gosling::Collision do
1077
1138
  @circle1.y = 0
1078
1139
  @circle2.x = 0
1079
1140
  @circle2.y = 0
1080
- result = Gosling::Collision.get_separation_axes(@circle1, @circle2)
1141
+ Gosling::Collision.get_separation_axes(@circle1, @circle2)
1142
+ result = Gosling::Collision.separation_axes
1081
1143
  expect(result).to be_instance_of(Array)
1082
1144
  expect(result).to be_empty
1083
1145
  end
@@ -1088,7 +1150,8 @@ describe Gosling::Collision do
1088
1150
  @circle1.y = 0
1089
1151
  @circle2.x = 17
1090
1152
  @circle2.y = -5
1091
- result = Gosling::Collision.get_separation_axes(@circle1, @circle2)
1153
+ Gosling::Collision.get_separation_axes(@circle1, @circle2)
1154
+ result = Gosling::Collision.separation_axes
1092
1155
  expect(result).to be_instance_of(Array)
1093
1156
  expect(result.length).to be == 1
1094
1157
  end
@@ -1104,7 +1167,8 @@ describe Gosling::Collision do
1104
1167
  [@circle1, @sprite1],
1105
1168
  [@circle2, @sprite2]
1106
1169
  ].each do |shapes|
1107
- result = Gosling::Collision.get_separation_axes(*shapes)
1170
+ Gosling::Collision.get_separation_axes(*shapes)
1171
+ result = Gosling::Collision.separation_axes
1108
1172
  vertex_count = shapes[1].get_vertices.length
1109
1173
  expect(result.length).to be_between(2, vertex_count + 1).inclusive
1110
1174
  end
@@ -1112,8 +1176,8 @@ describe Gosling::Collision do
1112
1176
  end
1113
1177
  end
1114
1178
 
1115
- describe '#project_onto_axis' do
1116
- it 'expects a shape and a 3d unit vector' do
1179
+ describe '.project_onto_axis' do
1180
+ it 'expects a shape and a 3d or better unit vector' do
1117
1181
  axis = Snow::Vec3[1, 1, 0]
1118
1182
 
1119
1183
  expect { Gosling::Collision.project_onto_axis(@sprite1, axis) }.not_to raise_error
@@ -1121,11 +1185,11 @@ describe Gosling::Collision do
1121
1185
  expect { Gosling::Collision.project_onto_axis(@circle1, axis) }.not_to raise_error
1122
1186
  expect { Gosling::Collision.project_onto_axis(@polygon1, axis) }.not_to raise_error
1123
1187
 
1124
- expect { Gosling::Collision.project_onto_axis(:foo, axis) }.to raise_error(ArgumentError)
1125
- expect { Gosling::Collision.project_onto_axis(@sprite1, Snow::Vec4[1, 1, 0, 2]) }.to raise_error(ArgumentError)
1188
+ expect { Gosling::Collision.project_onto_axis(:foo, axis) }.to raise_error
1189
+ expect { Gosling::Collision.project_onto_axis(@sprite1, Snow::Vec4[1, 1, 0, 2]) }.not_to raise_error
1126
1190
  expect { Gosling::Collision.project_onto_axis(@rect1, Snow::Vec2[1, 1]) }.to raise_error(ArgumentError)
1127
1191
  expect { Gosling::Collision.project_onto_axis(@polygon1, :foo) }.to raise_error(ArgumentError)
1128
- expect { Gosling::Collision.project_onto_axis(@circle1, @circle1, axis) }.to raise_error(ArgumentError)
1192
+ expect { Gosling::Collision.project_onto_axis(@circle1, @circle1, axis) }.to raise_error
1129
1193
  expect { Gosling::Collision.project_onto_axis() }.to raise_error(ArgumentError)
1130
1194
  end
1131
1195
 
@@ -1137,6 +1201,22 @@ describe Gosling::Collision do
1137
1201
  expect(result.reject { |x| x.is_a?(Numeric) }).to be_empty
1138
1202
  end
1139
1203
 
1204
+ it 'works with four dimensional axes' do
1205
+ clean_shape(@circle1)
1206
+ @circle1.x = 1
1207
+ @circle1.y = 1
1208
+ @circle1.radius = 5
1209
+
1210
+ axis = Snow::Vec4[-1, 1, 0, 0].normalize
1211
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
1212
+ expect(result).to be == [-5, 5]
1213
+
1214
+ axis.z = 2
1215
+ axis.w = -3
1216
+ result = Gosling::Collision.project_onto_axis(@circle1, axis)
1217
+ expect(result).to be == [-5, 5]
1218
+ end
1219
+
1140
1220
  context 'with a circle' do
1141
1221
  before do
1142
1222
  clean_shape(@circle1)
@@ -1339,7 +1419,7 @@ describe Gosling::Collision do
1339
1419
  end
1340
1420
  end
1341
1421
 
1342
- describe '#projections_overlap?' do
1422
+ describe '.projections_overlap?' do
1343
1423
  it 'accepts two length 2 arrays with numbers' do
1344
1424
  expect { Gosling::Collision.projections_overlap?([0, 0], [0, 0]) }.not_to raise_error
1345
1425
  expect { Gosling::Collision.projections_overlap?([1, 2], [3, -4]) }.not_to raise_error
@@ -1349,7 +1429,7 @@ describe Gosling::Collision do
1349
1429
  expect { Gosling::Collision.projections_overlap?([1, 2], [3, -4], [5, 6]) }.to raise_error(ArgumentError)
1350
1430
  expect { Gosling::Collision.projections_overlap?([1, 2]) }.to raise_error(ArgumentError)
1351
1431
  expect { Gosling::Collision.projections_overlap?([1, 2], :foo) }.to raise_error(ArgumentError)
1352
- expect { Gosling::Collision.projections_overlap?(nil, [1, 2]) }.to raise_error(ArgumentError)
1432
+ expect { Gosling::Collision.projections_overlap?(nil, [1, 2]) }.to raise_error
1353
1433
  end
1354
1434
 
1355
1435
  context 'when a and b do not overlap' do
@@ -1397,7 +1477,7 @@ describe Gosling::Collision do
1397
1477
  end
1398
1478
  end
1399
1479
 
1400
- describe '#get_overlap' do
1480
+ describe '.get_overlap' do
1401
1481
  it 'accepts two length 2 arrays with numbers' do
1402
1482
  expect { Gosling::Collision.get_overlap([0, 0], [0, 0]) }.not_to raise_error
1403
1483
  expect { Gosling::Collision.get_overlap([1, 2], [3, -4]) }.not_to raise_error
@@ -1407,7 +1487,7 @@ describe Gosling::Collision do
1407
1487
  expect { Gosling::Collision.get_overlap([1, 2], [3, -4], [5, 6]) }.to raise_error(ArgumentError)
1408
1488
  expect { Gosling::Collision.get_overlap([1, 2]) }.to raise_error(ArgumentError)
1409
1489
  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)
1490
+ expect { Gosling::Collision.get_overlap(nil, [1, 2]) }.to raise_error
1411
1491
  end
1412
1492
 
1413
1493
  context 'when a and b do not overlap' do
@@ -1454,4 +1534,222 @@ describe Gosling::Collision do
1454
1534
  end
1455
1535
  end
1456
1536
  end
1537
+
1538
+ describe '.buffer_shapes' do
1539
+ it 'accepts an array of actors' do
1540
+ expect { Gosling::Collision.buffer_shapes([]) }.not_to raise_error
1541
+ expect { Gosling::Collision.buffer_shapes([@actor1, @circle1, @polygon1, @rect1, @sprite1]) }.not_to raise_error
1542
+
1543
+ expect { Gosling::Collision.buffer_shapes(@actor1) }.to raise_error(ArgumentError)
1544
+ expect { Gosling::Collision.buffer_shapes(:foo) }.to raise_error(ArgumentError)
1545
+ expect { Gosling::Collision.buffer_shapes(nil) }.to raise_error(ArgumentError)
1546
+ end
1547
+
1548
+ it 'resets the buffer iterators' do
1549
+ expect(Gosling::Collision).to receive(:reset_buffer_iterators)
1550
+ Gosling::Collision.buffer_shapes([@actor1])
1551
+ end
1552
+
1553
+ context 'when actors are initially buffered' do
1554
+ before(:all) do
1555
+ Gosling::Collision.clear_buffer
1556
+ [@actor1, @circle1, @polygon1, @rect1, @sprite1].each { |a|
1557
+ @scale_actor.add_child(a)
1558
+ a.x = 0
1559
+ a.y = 0
1560
+ }
1561
+ Gosling::Collision.buffer_shapes([@actor1, @circle1, @polygon1, @rect1, @sprite1])
1562
+ end
1563
+
1564
+ it 'adds those actors to the collision test set' do
1565
+ [@circle1, @polygon1, @rect1, @sprite1].each do |actor|
1566
+ expect(Gosling::Collision.collision_buffer).to include(actor)
1567
+ end
1568
+ end
1569
+
1570
+ it 'caches computationally expensive information about each actor' do
1571
+ expect(Gosling::Collision.global_vertices_cache.length).to eq(3)
1572
+ expect(Gosling::Collision.global_position_cache.length).to eq(4)
1573
+ expect(Gosling::Collision.global_transform_cache.length).to eq(4)
1574
+
1575
+ [@actor1, @circle1, @polygon1, @rect1, @sprite1].each do |actor|
1576
+ expect(actor).not_to receive(:get_global_vertices)
1577
+ expect(actor).not_to receive(:get_global_position)
1578
+ expect(actor).not_to receive(:get_global_transform)
1579
+ end
1580
+
1581
+ collisions = []
1582
+ while true
1583
+ info = Gosling::Collision.next_collision_info
1584
+ break unless info
1585
+ collisions << info
1586
+ end
1587
+ expect(collisions.length).to eq(6)
1588
+ end
1589
+
1590
+ it 'only caches info for children of the Actor class' do
1591
+ [@actor1].each do |actor|
1592
+ expect(Gosling::Collision.collision_buffer).not_to include(actor)
1593
+ end
1594
+ end
1595
+
1596
+ context 'and then re-buffered' do
1597
+ it 'updates info for already buffered actors' do
1598
+ [@circle1, @circle2].each do |actor|
1599
+ expect(actor).to receive(:get_global_position).once.and_call_original
1600
+ expect(actor).to receive(:get_global_transform).twice.and_call_original
1601
+ end
1602
+ [@rect1].each do |actor|
1603
+ expect(actor).to receive(:get_global_vertices).once.and_call_original
1604
+ expect(actor).to receive(:get_global_transform).exactly(3).times.and_call_original
1605
+ end
1606
+
1607
+ Gosling::Collision.buffer_shapes([@circle1, @circle2, @rect1])
1608
+
1609
+ [@circle1, @circle2, @rect1].each do |actor|
1610
+ expect(Gosling::Collision.collision_buffer.select { |a| a == actor }.length).to eq(1)
1611
+ end
1612
+ expect(Gosling::Collision.global_vertices_cache.length).to eq(3)
1613
+ expect(Gosling::Collision.global_position_cache.length).to eq(5)
1614
+ expect(Gosling::Collision.global_transform_cache.length).to eq(5)
1615
+ end
1616
+ end
1617
+
1618
+ after(:all) do
1619
+ Gosling::Collision.clear_buffer
1620
+ [@actor1, @circle1, @polygon1, @rect1, @sprite1].each { |a| @scale_actor.remove_child(a) }
1621
+ end
1622
+ end
1623
+ end
1624
+
1625
+ describe '.next_collision_info' do
1626
+ before(:all) do
1627
+ Gosling::Collision.clear_buffer
1628
+ [@circle1, @polygon1, @rect1, @sprite1].each { |a| a.x = 0; a.y = 0 }
1629
+ Gosling::Collision.buffer_shapes([@circle1, @polygon1, @rect1, @sprite1])
1630
+ end
1631
+
1632
+ it 'returns collision information for the next pair of colliding actors, then nil when done' do
1633
+ info = Gosling::Collision.next_collision_info
1634
+ expect(info[:actors]).to include(@polygon1, @circle1)
1635
+ expect(info[:colliding]).to be true
1636
+
1637
+ info = Gosling::Collision.next_collision_info
1638
+ expect(info[:actors]).to include(@rect1, @circle1)
1639
+ expect(info[:colliding]).to be true
1640
+
1641
+ info = Gosling::Collision.next_collision_info
1642
+ expect(info[:actors]).to include(@rect1, @polygon1)
1643
+ expect(info[:colliding]).to be true
1644
+
1645
+ info = Gosling::Collision.next_collision_info
1646
+ expect(info[:actors]).to include(@sprite1, @circle1)
1647
+ expect(info[:colliding]).to be true
1648
+
1649
+ info = Gosling::Collision.next_collision_info
1650
+ expect(info[:actors]).to include(@sprite1, @polygon1)
1651
+ expect(info[:colliding]).to be true
1652
+
1653
+ info = Gosling::Collision.next_collision_info
1654
+ expect(info[:actors]).to include(@sprite1, @rect1)
1655
+ expect(info[:colliding]).to be true
1656
+
1657
+ expect(Gosling::Collision.next_collision_info).to be_nil
1658
+ end
1659
+
1660
+ after(:all) do
1661
+ Gosling::Collision.clear_buffer
1662
+ end
1663
+ end
1664
+
1665
+ describe '.peek_at_next_collision' do
1666
+ before(:all) do
1667
+ Gosling::Collision.clear_buffer
1668
+ [@circle1, @polygon1, @rect1, @sprite1].each { |a| a.x = 0; a.y = 0 }
1669
+ Gosling::Collision.buffer_shapes([@circle1, @polygon1, @rect1, @sprite1])
1670
+ end
1671
+
1672
+ it 'returns references to the next two buffered actors to be collision tested, if any' do
1673
+ expect(Gosling::Collision.peek_at_next_collision).to eq([@polygon1, @circle1])
1674
+ 2.times { Gosling::Collision.skip_next_collision }
1675
+ expect(Gosling::Collision.peek_at_next_collision).to eq([@rect1, @polygon1])
1676
+ 2.times { Gosling::Collision.skip_next_collision }
1677
+ info = Gosling::Collision.next_collision_info
1678
+ expect(info[:actors]).to include(@sprite1, @polygon1)
1679
+ 2.times { Gosling::Collision.skip_next_collision }
1680
+ expect(Gosling::Collision.peek_at_next_collision).to be_nil
1681
+ end
1682
+
1683
+ after(:all) do
1684
+ Gosling::Collision.clear_buffer
1685
+ end
1686
+ end
1687
+
1688
+ describe '.skip_next_collision' do
1689
+ before(:all) do
1690
+ Gosling::Collision.clear_buffer
1691
+ [@circle1, @polygon1, @rect1, @sprite1].each { |a| a.x = 0; a.y = 0 }
1692
+ Gosling::Collision.buffer_shapes([@circle1, @polygon1, @rect1])
1693
+ end
1694
+
1695
+ it 'moves the collision iterators forward without performing any collision testing' do
1696
+ expect(Gosling::Collision.peek_at_next_collision).to eq([@polygon1, @circle1])
1697
+ Gosling::Collision.skip_next_collision
1698
+ expect(Gosling::Collision.peek_at_next_collision).to eq([@rect1, @circle1])
1699
+ Gosling::Collision.skip_next_collision
1700
+ info = Gosling::Collision.next_collision_info
1701
+ expect(info[:actors]).to include(@rect1, @polygon1)
1702
+ Gosling::Collision.skip_next_collision
1703
+ expect(Gosling::Collision.peek_at_next_collision).to be_nil
1704
+ end
1705
+
1706
+ after(:all) do
1707
+ Gosling::Collision.clear_buffer
1708
+ end
1709
+ end
1710
+
1711
+ describe '.unbuffer_shapes' do
1712
+ it 'accepts an array of actors' do
1713
+ expect { Gosling::Collision.unbuffer_shapes([]) }.not_to raise_error
1714
+ expect { Gosling::Collision.unbuffer_shapes([@actor1, @circle1, @polygon1, @rect1, @sprite1]) }.not_to raise_error
1715
+
1716
+ expect { Gosling::Collision.unbuffer_shapes(@actor1) }.to raise_error(ArgumentError)
1717
+ expect { Gosling::Collision.unbuffer_shapes(:foo) }.to raise_error(ArgumentError)
1718
+ expect { Gosling::Collision.unbuffer_shapes(nil) }.to raise_error(ArgumentError)
1719
+ end
1720
+
1721
+ it 'resets the buffer iterators' do
1722
+ expect(Gosling::Collision).to receive(:reset_buffer_iterators)
1723
+ Gosling::Collision.unbuffer_shapes([@actor1])
1724
+ end
1725
+
1726
+ it 'removes those actors from the collision test list and related info from the caches' do
1727
+ Gosling::Collision.buffer_shapes([@actor1, @circle1, @polygon1, @rect1, @sprite1])
1728
+ Gosling::Collision.unbuffer_shapes([@actor1, @polygon1, @sprite1])
1729
+ [@actor1, @polygon1, @sprite1].each do |actor|
1730
+ expect(Gosling::Collision.collision_buffer).not_to include(actor)
1731
+ end
1732
+ expect(Gosling::Collision.global_vertices_cache.length).to eq(1)
1733
+ expect(Gosling::Collision.global_position_cache.length).to eq(2)
1734
+ expect(Gosling::Collision.global_transform_cache.length).to eq(2)
1735
+ end
1736
+ end
1737
+
1738
+ describe '.clear_buffer' do
1739
+ it 'removes all actors from the collision test list and related info from the caches' do
1740
+ Gosling::Collision.buffer_shapes([@actor1, @circle1, @polygon1, @rect1, @sprite1])
1741
+ Gosling::Collision.clear_buffer
1742
+ [@actor1, @circle1, @polygon1, @rect1, @sprite1].each do |actor|
1743
+ expect(Gosling::Collision.collision_buffer).not_to include(actor)
1744
+ end
1745
+ expect(Gosling::Collision.global_vertices_cache.length).to eq(0)
1746
+ expect(Gosling::Collision.global_position_cache.length).to eq(0)
1747
+ expect(Gosling::Collision.global_transform_cache.length).to eq(0)
1748
+ end
1749
+
1750
+ it 'resets the buffer iterators' do
1751
+ expect(Gosling::Collision).to receive(:reset_buffer_iterators)
1752
+ Gosling::Collision.clear_buffer
1753
+ end
1754
+ end
1457
1755
  end