I believe I may have an answer, though please do point out if I'm incorrect. I'll be pasting my answers in TypeScript, leaving out the basic functions that you can find pretty easily on the web.
Wedge-Circle Collision
This appears to be the simplest. Already knowing how to make two circles collide (test their distances from one another is less than the two radiuses), we want to do a similar test for a wedge and a circle, and then determine if the point of collision is inside the wedge:
export function wedgeAndCircleCollide(
wedge: BoundingWedge,
circle: BoundingCircle,
): boolean {
if (!circlesCollide(
boundingCircleFromWedge(wedge),
circle,
)) {
return false
}
// Determine the collision angle between the two circles for
// the wedge
const wedgeCollisionAngle = pointAngle(
wedge.center,
circle.center,
)
// Return whether the angle of collision is within the wedge's
// angles
return angleInRange(wedgeCollisionAngle, wedge.directionAngle, wedge.widthAngle)
}
Wedge-Wedge Collision
Similarly, wedge-wedge collision adds a second step of testing if that angle is in the range of the second wedge as well:
export function wedgesCollide(bw1: BoundingWedge, bw2: BoundingWedge): boolean {
if (!circlesCollide(
boundingCircleFromWedge(bw1),
boundingCircleFromWedge(bw2),
)) {
return false
}
// Determine the collision angle between the two circles for...
// ...wedge 1
const w1CollisionAngle = pointAngle(
bw1.center,
bw2.center,
)
// ...wedge 2
const w2CollisionAngle = pointAngle(
bw2.center,
bw1.center,
)
// If the collision angle for wedge 1 is within wedge 1's
// angle, mark it down
const collisionInW1 = angleInRange(w1CollisionAngle, bw1.directionAngle, bw1.widthAngle)
// If the collision angle for wedge 2 is within wedge 2's
// angle, mark it down
const collisionInW2 = angleInRange(w2CollisionAngle, bw2.directionAngle, bw2.widthAngle)
// Return whether the collision is in both wedge 1 and wedge 2
return collisionInW1 && collisionInW2
}
Box-Wedge Collision
This is by far the most complicated.
The main function goes something like:
export function wedgeAndBoxCollide(wedge: BoundingWedge, box: BoundingBox) {
const circleFromWedge = boundingCircleFromWedge(wedge)
// Cheap check:
// Check that the circle is inside the rectangle. If so,
// return true
if (boundingCircleInBox(circleFromWedge, box)) {
return true
}
const boxCentreX = box.x + (box.width / 2)
const boxCentreY = box.y + (box height / 2)
const topLeft: PointTuple = [box.x, box.y]
const bottomLeft: PointTuple = [box.x, box.y + box.height]
const topRight: PointTuple = [box.x + box.width, box.y]
const bottomRight: PointTuple = [box.x + box.width, box.y + box.height]
const closestHorizontalWall: LineTuple = wedge.center.x <= boxCentreX
? [topLeft, bottomLeft]
: [topRight, bottomRight]
const closestVerticallWall: LineTuple = wedge.center.y <= boxCentreY
? [topLeft, topRight]
: [bottomLeft, bottomRight]
// Check the two most relevant walls. If there's a collision,
// return true
return wedgeCollidesWithLine(closestHorizontalWall, wedge) ||
wedgeCollidesWithLine(closestVerticallWall, wedge)
}
where wedgeCollidesWithLine()
looks like:
export function wedgeCollidesWithLine(
line: LineTuple,
wedge: BoundingWedge,
): boolean {
const safeDirectionAngle = getSafeAngle(wedge.directionAngle)
const wedgeHalfAngle = getSafeAngle(wedge.widthAngle) / 2
if (
pointInWedge(line[0], wedge) ||
pointInWedge(line[1], wedge)
) {
return true
}
const lineSlope = getSlope(line)
// y = mx + b
// b = -mx + y
const perpendicularLineIntercept = (lineSlope * wedge.center.x * -1) + wedge.center.y
const perpendicularX = wedge.center.x + 10
const perpendicularY = (lineSlope * perpendicularX) + perpendicularLineIntercept
// Point-angle to box edge
// Return true if in wedge
const centreToLineIntersectionPoint = getLineIntersectionPoint(
[ wedge.center, [perpendicularX, perpendicularY] ],
line,
)
// If the distance from the line to the wedge circle
// is greater than the radius length, there's not going
// to be an intersection
if (
pointDistance(
wedge.center,
centreToLineIntersectionPoint,
) > wedgeRadius
) {
return false
}
if (pointInWedge(centreToLineIntersectionPoint, wedge)) {
return true
}
const safeLeftBound = getSafeAngle(safeDirectionAngle - wedgeHalfAngle)
const safeRightBound = getSafeAngle(safeDirectionAngle + wedgeHalfAngle)
// Get intersection by wedge bounds
// Is it in the given line?
const leftEdgePoint: PointTuple = [
wedge.center.x + getLengthDirX(
safeLeftBound,
wedge.radius,
),
wedge.center.y + getLengthDirY(
safeLeftBound,
wedge.radius,
),
]
const leftIntersectionPoint = getLineIntersectionPoint(
[wedgeCentre, leftEdgePoint],
line,
)
const rightEdgePoint: PointTuple = [
wedge.center.x + getLengthDirX(
safeRightBound,
wedge.radius,
),
wedge.center.y + getLengthDirY(
safeRightBound,
wedge.radius,
),
]
const rightIntersectionPoint = getLineIntersectionPoint(
[wedgeCenter, rightEdgePoint],
line,
)
// Check if the intersections with the wedge bounds
// are within the wedge: if not, the wedge is not facing
// the line, and thus no collision occurs
return pointInWedge(leftIntersectionPoint, wedge) ||
pointInWedge(rightIntersectionPoint, wedge)
}
The idea here being:
- If there's a collision with a corner, it's a collision
- For each relevant edge:
- Get the distance to the edge
- Get the point-angle between the wedge and the box edge
- Determine if the line from the wedge to the edge is in the wedge
- If not, extend the "wings" of the wedge, and see if they collide with the line at all. If they do, determine if that collision is inside the wedge bounds.