flightmath
local FM = require("ship.flightmath")
The small pile of maths the helm and its camera share. It exists because one thing has to be true in both files at once: what the ship's axes are.
Which way is the bow
An unrotated entity in this engine reports transform.forward = (0, 0, -1), so
the engine's own forward axis is local -Z.
The Aurelian's hull is authored the other way round. An orthographic side elevation shows the bowsprit and jib at local +Z and the drive nozzles at local -Z, and the same was true of the blocked-out placeholder it replaced. So the art's bow is local +Z, and the helm flies the art.
The price, stated plainly: entity.transform.forward on the Aurelian points at
its stern. Nothing in this world reads it — everything reads
Drift.state.heading, which is the bow direction and the direction of travel —
but anything added later must read heading rather than forward. If the hull
is ever re-authored bow-to--Z, basis and quat are the pair to change.
API
basis(yaw, pitch, roll) | the ship's bow / right / up in world space, as nine numbers |
quat(fx,fy,fz, rx,ry,rz, ux,uy,uz) | rotation for a hull frame (bow on +Z) |
viewQuat(dx,dy,dz, ux,uy,uz) | rotation for a camera looking along dir (view on -Z) |
approach(cur, target, tau, dt) | frame-rate-independent exponential approach, tau in seconds |
blend(cur, target, smoothing, dt) | per-second blend, the shape the built-in controllers use |
normalize(x, y, z) | normalize, falling back to the engine's forward when degenerate |
localCameraRig() | the Camera component of the rig this peer flies behind |
selfTest() | prove basis and quat agree with the live engine |
quat and viewQuat are not interchangeable. Handing a camera the hull's
rotation aims it exactly backwards, and does so silently: the camera is still
the right distance from its subject and the frame is still full of stars.
Transform.lookAtQuat is not a substitute for viewQuat either — it takes no
up vector, so a camera built with it can never roll with what it films.
localCameraRig finds the rig by the one thing true of it and of nothing else
on this client — it follows this client's avatar — so it stays correct with
several peers in the world. layers.active.camera is the documented shorthand
and is used as the fallback, but in edit mode it answers with the editor's
own fly-camera, which is refused by participation.
(layers.active.players.localPlayer.camera, which Drift.setCameraBehavior
reaches for, is nil on a live player — hence this helper.)
selfTest
local ok, report = require("ship.flightmath").selfTest()
Spawns a throwaway entity, assigns the quaternion for six poses, and asserts the axes come back out of the live engine within 1e-4. Run it after touching anything about rotation. Last run: ok, worst error 1.9e-7.
Scoped to this part · feeds back into the world's score.