1 module prova.collision.resolve; 2 3 import prova.collision, 4 prova.math; 5 6 // Helper functions for getting a displacement vector that allows colliderA to escape colliderB 7 8 // pushes to the left by the smallest value representable by a floating point 9 Vector2 resolvePointPoint(PointCollider colliderA, PointCollider colliderB) 10 { 11 return Vector2(-float.min_normal, 0); 12 } 13 14 Vector2 resolvePointCircle(PointCollider colliderA, CircleCollider colliderB) 15 { 16 const Vector2 difference = colliderA.getPosition() - colliderB.getPosition(); 17 Vector2 resolution = difference; 18 19 resolution.setMagnitude(colliderB.radius); 20 resolution -= difference; 21 22 return resolution; 23 } 24 25 Vector2 resolvePointRect(PointCollider colliderA, RectCollider colliderB) 26 { 27 const Vector2 position = colliderA.getPosition(); 28 const Rect bounds = colliderB.getBounds(); 29 const Side side = bounds.getClosestSide(position); 30 Vector2 resolution; 31 32 if(side == Side.LEFT) 33 resolution.x = bounds.left - position.x; 34 else if(side == Side.RIGHT) 35 resolution.x = bounds.right - position.x; 36 else if(side == Side.TOP) 37 resolution.y = bounds.top - position.y; 38 else if(side == Side.BOTTOM) 39 resolution.y = bounds.bottom - position.y; 40 41 return resolution; 42 } 43 44 Vector2 resolveCircleCircle(CircleCollider colliderA, CircleCollider colliderB) 45 { 46 const Vector2 difference = colliderA.getPosition() - colliderB.getPosition(); 47 Vector2 resolution = difference; 48 49 resolution.setMagnitude(colliderA.radius + colliderB.radius); 50 resolution -= difference; 51 52 return resolution; 53 } 54 55 Vector2 resolveCircleRect(CircleCollider colliderA, RectCollider colliderB) 56 { 57 Vector2 circlePosition = colliderA.getPosition(); 58 Rect circleBounds = colliderA.getBounds(); 59 Rect rectBounds = colliderB.getBounds(); 60 bool topBottom = circlePosition.x < rectBounds.right && circlePosition.x > rectBounds.left; 61 bool leftRight = circlePosition.y < rectBounds.top && circlePosition.y > rectBounds.bottom; 62 63 // touching a side 64 if(leftRight || topBottom) 65 return resolveRectBounds(circleBounds, rectBounds); 66 67 // on a corner 68 return resolveCircleCorners(colliderA, rectBounds); 69 } 70 71 Vector2 resolveCircleCorners(CircleCollider circle, Rect rectBounds) 72 { 73 Vector2 circlePosition = circle.getPosition(); 74 Vector2 rectPosition = rectBounds.getCenter(); 75 Vector2[4] corners = [ 76 rectBounds.getTopLeft(), 77 rectBounds.getTopRight(), 78 rectBounds.getBottomLeft(), 79 rectBounds.getBottomRight() 80 ]; 81 82 Vector2 resolution; 83 84 foreach(Vector2 corner; corners) 85 { 86 if(corner.distanceTo(circlePosition) > circle.radius) 87 continue; 88 89 const Vector2 difference = circlePosition - corner; 90 resolution = difference; 91 92 resolution.setMagnitude(circle.radius + 1e-06); 93 resolution -= difference; 94 95 break; 96 } 97 98 return resolution; 99 } 100 101 Vector2 resolveRectRect(RectCollider colliderA, RectCollider colliderB) 102 { 103 const Rect boundsA = colliderA.getBounds(); 104 const Rect boundsB = colliderB.getBounds(); 105 106 return resolveRectBounds(boundsA, boundsB); 107 } 108 109 Vector2 resolveRectBounds(Rect boundsA, Rect boundsB) 110 { 111 const Side side = boundsB.getClosestSide(boundsA); 112 Vector2 resolution; 113 114 if(side == Side.LEFT) 115 resolution.x = boundsB.left - boundsA.right; 116 else if(side == Side.RIGHT) 117 resolution.x = boundsB.right - boundsA.left; 118 else if(side == Side.TOP) 119 resolution.y = boundsB.top - boundsA.bottom; 120 else if(side == Side.BOTTOM) 121 resolution.y = boundsB.bottom - boundsA.top; 122 123 return resolution; 124 }