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

61 lines
1.9 KiB
TypeScript

import type { Iwt2ArenaBounds, Iwt2Vec2 } from './types'
export const IWT2_ZERO_VECTOR: Iwt2Vec2 = { x: 0, y: 0 }
export function addVec2(a: Iwt2Vec2, b: Iwt2Vec2): Iwt2Vec2 {
return { x: a.x + b.x, y: a.y + b.y }
}
export function subtractVec2(a: Iwt2Vec2, b: Iwt2Vec2): Iwt2Vec2 {
return { x: a.x - b.x, y: a.y - b.y }
}
export function scaleVec2(vector: Iwt2Vec2, scale: number): Iwt2Vec2 {
return { x: vector.x * scale, y: vector.y * scale }
}
export function dotVec2(a: Iwt2Vec2, b: Iwt2Vec2): number {
return a.x * b.x + a.y * b.y
}
export function lengthSqVec2(vector: Iwt2Vec2): number {
return dotVec2(vector, vector)
}
export function lengthVec2(vector: Iwt2Vec2): number {
return Math.sqrt(lengthSqVec2(vector))
}
export function distanceVec2(a: Iwt2Vec2, b: Iwt2Vec2): number {
return lengthVec2(subtractVec2(a, b))
}
export function normalizeVec2(vector: Iwt2Vec2): Iwt2Vec2 {
const length = lengthVec2(vector)
if (length <= 0.0001) return { ...IWT2_ZERO_VECTOR }
return { x: vector.x / length, y: vector.y / length }
}
export function clamp(value: number, min: number, max: number): number {
return Math.min(max, Math.max(min, value))
}
export function clampVec2ToArena(position: Iwt2Vec2, radius: number, bounds: Iwt2ArenaBounds): Iwt2Vec2 {
return {
x: clamp(position.x, radius, bounds.width - radius),
y: clamp(position.y, radius, bounds.height - radius),
}
}
export function moveToward(current: Iwt2Vec2, target: Iwt2Vec2, maxDistance: number): Iwt2Vec2 {
const offset = subtractVec2(target, current)
const distance = lengthVec2(offset)
if (distance <= maxDistance || distance <= 0.0001) return { ...target }
return addVec2(current, scaleVec2(offset, maxDistance / distance))
}
export function withFallbackFacing(nextFacing: Iwt2Vec2, fallback: Iwt2Vec2): Iwt2Vec2 {
if (lengthSqVec2(nextFacing) <= 0.0001) return { ...fallback }
return normalizeVec2(nextFacing)
}