gosling 2.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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