Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
3.9 kB · 101 lines
TypeScript
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102import { pubsub } from "@thorium/.server/init/pubsub";import { type Entity, System } from "@thorium/utils/ecs";import { Quaternion, Vector3, Matrix4 } from "three";
const shipPosition = new Vector3();const waypointPosition = new Vector3();const up = new Vector3(0, 1, 0);const matrix = new Matrix4();const rotationMatrix = new Matrix4().makeRotationY(-Math.PI);const rotationQuat = new Quaternion();const desiredRotationQuat = new Quaternion();const dirVector1 = new Vector3();const dirVector2 = new Vector3();const HELIOPAUSE_DISTANCE_KM = 20_000_000_000;
export class FacingWaypointSystem extends System { static flightMode = ["nova"]; frequency = 5;
test(entity: Entity) { return !!( entity.components.isShip && entity.components.position && entity.components.rotation && entity.components.facingWaypoints ); }
update(entity: Entity) { const { position, rotation, facingWaypoints } = entity.components; if (!position || !rotation || !facingWaypoints) return;
shipPosition.set(position.x, position.y, position.z);
const facingEntries: { id: number; distance: number }[] = [];
const shipSystemEntity = position.parentId ? this.ecs.getEntityById(position.parentId) : null; const shipSystemPosition = shipSystemEntity?.components.position || null;
for (const waypoint of this.ecs.componentCache.get("isWaypoint") || []) { if (waypoint.components.isWaypoint?.assignedShipId !== entity.id) continue; if (!waypoint.components.isWaypoint.isActive) continue; if (!waypoint.components.position) continue;
const wpPosition = waypoint.components.position; const wpParentId = wpPosition.parentId;
// Resolve waypoint position into ship's coordinate space if (wpParentId === position.parentId) { // Same system (or both in interstellar space) waypointPosition.set(wpPosition.x, wpPosition.y, wpPosition.z); } else { const wpSystemEntity = wpParentId ? this.ecs.getEntityById(wpParentId) : null; const wpSystemPosition = wpSystemEntity?.components.position || null;
if (position.parentId === null && wpSystemPosition) { // Ship is in interstellar space waypointPosition.set(wpSystemPosition.x, wpSystemPosition.y, wpSystemPosition.z); } else if (wpSystemPosition && shipSystemPosition) { // Cross-system: place at heliopause direction dirVector1.set(shipSystemPosition.x, shipSystemPosition.y, shipSystemPosition.z); dirVector2.set(wpSystemPosition.x, wpSystemPosition.y, wpSystemPosition.z); waypointPosition .subVectors(dirVector2, dirVector1) .normalize() .multiplyScalar(HELIOPAUSE_DISTANCE_KM); } else { continue; } }
// Compute the facing angle using the ship's own up vector so // the check is roll-agnostic (only yaw/pitch matter for locking on). rotationQuat.set(rotation.x, rotation.y, rotation.z, rotation.w); up.set(0, 1, 0).applyQuaternion(rotationQuat); matrix.lookAt(shipPosition, waypointPosition, up).multiply(rotationMatrix); desiredRotationQuat.setFromRotationMatrix(matrix);
const angle = Math.abs(rotationQuat.angleTo(desiredRotationQuat)); // 3 degrees = PI/60 radians if (angle < Math.PI / 60) { const distance = shipPosition.distanceTo(waypointPosition); facingEntries.push({ id: waypoint.id, distance }); } }
// Sort by distance so the nearest facing waypoint is first facingEntries.sort((a, b) => a.distance - b.distance); const facingIds = facingEntries.map((e) => e.id);
// Only update the component if the facing waypoints have changed const currentFacing = facingWaypoints.ids; if ( facingIds.length !== currentFacing.length || facingIds.some((id, i) => currentFacing[i] !== id) ) { entity.updateComponent("facingWaypoints", { ids: facingIds }); pubsub.publish.pilot.autopilot.get({ shipId: entity.id }); } }}