Line data Source code
1 : import '../../extensions.dart'; 2 : import '../../geometry.dart'; 3 : import '../components/mixins/collidable.dart'; 4 : 5 4 : final Set<int> _collidableHashes = {}; 6 4 : final Set<int> _shapeHashes = {}; 7 : 8 2 : int _collidableTypeCompare(Collidable a, Collidable b) { 9 10 : return a.collidableType.index - b.collidableType.index; 10 : } 11 : 12 : /// Check whether any [Collidable] in [collidables] collide with each other and 13 : /// call their onCollision methods accordingly. 14 2 : void collisionDetection(List<Collidable> collidables) { 15 2 : collidables.sort(_collidableTypeCompare); 16 6 : for (var x = 0; x < collidables.length; x++) { 17 2 : final collidableX = collidables[x]; 18 4 : if (collidableX.collidableType != CollidableType.active) { 19 : break; 20 : } 21 : 22 8 : for (var y = x + 1; y < collidables.length; y++) { 23 2 : final collidableY = collidables[y]; 24 4 : if (collidableY.collidableType == CollidableType.inactive) { 25 : break; 26 : } 27 : 28 2 : final intersectionPoints = intersections(collidableX, collidableY); 29 2 : if (intersectionPoints.isNotEmpty) { 30 2 : collidableX.onCollision(intersectionPoints, collidableY); 31 2 : collidableY.onCollision(intersectionPoints, collidableX); 32 2 : final collisionHash = _combinedHash(collidableX, collidableY); 33 4 : _collidableHashes.add(collisionHash); 34 : } else { 35 2 : _handleCollisionEnd(collidableX, collidableY); 36 : } 37 : } 38 : } 39 : } 40 : 41 2 : bool hasActiveCollision(Collidable collidableA, Collidable collidableB) { 42 4 : return _collidableHashes.contains( 43 2 : _combinedHash(collidableA, collidableB), 44 : ); 45 : } 46 : 47 2 : bool hasActiveShapeCollision(HitboxShape shapeA, HitboxShape shapeB) { 48 4 : return _shapeHashes.contains( 49 2 : _combinedHash(shapeA, shapeB), 50 : ); 51 : } 52 : 53 2 : void _handleCollisionEnd(Collidable collidableA, Collidable collidableB) { 54 2 : if (hasActiveCollision(collidableA, collidableB)) { 55 1 : collidableA.onCollisionEnd(collidableB); 56 1 : collidableB.onCollisionEnd(collidableA); 57 3 : _collidableHashes.remove(_combinedHash(collidableA, collidableB)); 58 : } 59 : } 60 : 61 2 : void _handleShapeCollisionEnd(HitboxShape shapeA, HitboxShape shapeB) { 62 2 : if (hasActiveShapeCollision(shapeA, shapeB)) { 63 2 : shapeA.onCollisionEnd(shapeB); 64 2 : shapeB.onCollisionEnd(shapeA); 65 3 : _shapeHashes.remove(_combinedHash(shapeA, shapeB)); 66 : } 67 : } 68 : 69 : /// Check what the intersection points of two collidables are 70 : /// returns an empty list if there are no intersections 71 2 : Set<Vector2> intersections( 72 : Collidable collidableA, 73 : Collidable collidableB, 74 : ) { 75 2 : if (!collidableA.possiblyOverlapping(collidableB)) { 76 : // These collidables can't have any intersection points 77 1 : if (hasActiveCollision(collidableA, collidableB)) { 78 2 : for (final shapeA in collidableA.hitboxes) { 79 2 : for (final shapeB in collidableB.hitboxes) { 80 1 : _handleShapeCollisionEnd(shapeA, shapeB); 81 : } 82 : } 83 : } 84 : return {}; 85 : } 86 : 87 : final result = <Vector2>{}; 88 : final currentResult = <Vector2>{}; 89 4 : for (final shapeA in collidableA.hitboxes) { 90 4 : for (final shapeB in collidableB.hitboxes) { 91 4 : currentResult.addAll(shapeA.intersections(shapeB)); 92 2 : if (currentResult.isNotEmpty) { 93 2 : result.addAll(currentResult); 94 : // Do callbacks to the involved shapes 95 4 : shapeA.onCollision(currentResult, shapeB); 96 4 : shapeB.onCollision(currentResult, shapeA); 97 2 : currentResult.clear(); 98 6 : _shapeHashes.add(_combinedHash(shapeA, shapeB)); 99 : } else { 100 0 : _handleShapeCollisionEnd(shapeA, shapeB); 101 : } 102 : } 103 : } 104 : return result; 105 : } 106 : 107 2 : int _combinedHash(Object o1, Object o2) { 108 6 : return o1.hashCode ^ o2.hashCode; 109 : }