Files
i-want-to-heal/src/modes/iwt2/sim/collision.ts
T
2026-07-04 12:43:59 -04:00

47 lines
1.6 KiB
TypeScript

import type { Iwt2ArenaBounds, Iwt2Circle, Iwt2Vec2 } from './types'
import {
addVec2,
clamp,
clampVec2ToArena,
distanceVec2,
dotVec2,
lengthSqVec2,
normalizeVec2,
scaleVec2,
subtractVec2,
} from './vector'
export function circlesOverlap(a: Iwt2Circle, b: Iwt2Circle): boolean {
const radiusSum = a.radius + b.radius
return distanceVec2(a.position, b.position) <= radiusSum
}
export function distanceToSegment(point: Iwt2Vec2, start: Iwt2Vec2, end: Iwt2Vec2): number {
const segment = subtractVec2(end, start)
const segmentLengthSq = lengthSqVec2(segment)
if (segmentLengthSq <= 0.0001) return distanceVec2(point, start)
const pointOffset = subtractVec2(point, start)
const t = clamp(dotVec2(pointOffset, segment) / segmentLengthSq, 0, 1)
const projection = addVec2(start, scaleVec2(segment, t))
return distanceVec2(point, projection)
}
export function circleIntersectsSegment(
circle: Iwt2Circle,
start: Iwt2Vec2,
end: Iwt2Vec2,
width: number,
): boolean {
return distanceToSegment(circle.position, start, end) <= circle.radius + width
}
export function separateCircles(moving: Iwt2Circle, fixed: Iwt2Circle, bounds: Iwt2ArenaBounds): Iwt2Vec2 {
const offset = subtractVec2(moving.position, fixed.position)
const minDistance = moving.radius + fixed.radius
const distanceSq = lengthSqVec2(offset)
if (distanceSq >= minDistance * minDistance) return moving.position
const direction = distanceSq <= 0.0001 ? { x: 1, y: 0 } : normalizeVec2(offset)
const resolved = addVec2(fixed.position, scaleVec2(direction, minDistance))
return clampVec2ToArena(resolved, moving.radius, bounds)
}