airframe.io / src /game /math.ts
LATTICEWORKS's picture
feat: integrate Google Earth 3D Tiles and optimize engine hooks
565f6e7
Raw
History Blame Contribute Delete
1.79 kB
/**
* @license
* SPDX-License-Identifier: Apache-2.0
*/
import * as THREE from "three";
import { Pilot, AircraftSpecs } from "../types";
// AXIS CONTRACT (shared across all physics and rendering modules)
// Aircraft local +Z = nose / forward / guns
// Aircraft local +Y = up
// Aircraft local +X = right wing
export const LOCAL_FORWARD = new THREE.Vector3(0, 0, 1);
export const LOCAL_UP = new THREE.Vector3(0, 1, 0);
export const LOCAL_RIGHT = new THREE.Vector3(1, 0, 0);
export function generateId(): string {
return Math.random().toString(36).substring(2, 11);
}
const abTmp = new THREE.Vector3();
const apTmp = new THREE.Vector3();
export function closestPointOnSegment(
a: THREE.Vector3,
b: THREE.Vector3,
p: THREE.Vector3,
out: THREE.Vector3 = new THREE.Vector3()
): THREE.Vector3 {
abTmp.copy(b).sub(a);
const denom = abTmp.lengthSq();
if (denom < 1e-8) {
return out.copy(a);
}
apTmp.copy(p).sub(a);
const t = THREE.MathUtils.clamp(apTmp.dot(abTmp) / denom, 0, 1);
return out.copy(a).addScaledVector(abTmp, t);
}
export function getPlaneHitRadius(specs: AircraftSpecs): number {
if (specs.class === "HeavyFighter") return 34;
if (specs.class === "Attacker") return 36;
if (specs.class === "Turnfighter") return 24;
return 28;
}
export function getForwardVector(pilot: Pilot): THREE.Vector3 {
const q = new THREE.Quaternion(pilot.qx, pilot.qy, pilot.qz, pilot.qw);
return LOCAL_FORWARD.clone().applyQuaternion(q).normalize();
}
export function airDensityAtAltitude(altitudeMeters: number): number {
return 1.225 * Math.exp(-Math.max(0, altitudeMeters) / 8500);
}
export function safeNormalize(v: THREE.Vector3, fallback: THREE.Vector3): THREE.Vector3 {
if (v.lengthSq() < 1e-8) return fallback.clone();
return v.normalize();
}