Something went wrong. Try again.
A video game where you play as a misaligned AI, deceiving and building power. cameron.tngl.io/misaligned
Something went wrong. Try again.
2.9 kB · 53 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354// What the screen needs to move smoothly between two steps of the rules. The rules move in steps of a game// minute (STEP in sim.ts), a fifth of a second or so at 1x, so the screen draws a little behind them and eases// what moves from where it was one step ago to where it is now. The loop (main.ts) says how far into the next step// it is; the drawing (view.ts) asks for the time and places here. Nothing here changes the game.import { STEP, type Person, type State } from './sim.ts';import type { Trace } from './watch.ts';
/** How far the screen is into the next step: 0 just after a step, nearly 1 just before the next. */let lead = 1;/** Where each moving thing was before the last step: a person's place, a scan's hop and how far along it it was. */const was = new WeakMap<object, number[]>();const hops = new WeakMap<Trace, string>();
/** Called by the loop just before each step, to remember where things were. */export function beforeStep(S: State) { for (const p of S.people) was.set(p, [p.x, p.y]); for (const T of S.watch?.traces ?? []) { was.set(T, [T.p]); hops.set(T, `${T.from}>${T.to}`); }}/** Called by the loop once a frame: the game time owed to the rules, less than a step. */export function setLead(owed: number) { lead = Math.max(0, Math.min(1, owed / STEP)); }export const leadNow = () => lead;
/** The time to draw at: a step behind the rules, eased toward them. What is animated by the clock (streams, pulses) * runs on this, so it moves every frame and never jumps back. */export const drawTime = (S: State) => S.t - STEP * (1 - lead);
/** Draw with the game's clock set to drawTime, and put it back after: whatever the drawing animates by the clock * (streams, pulses, dashes, countdowns) moves every frame, not once a step. Nothing in the drawing changes the * game, so the clock is the only thing it reads that needs easing this way. */export function drawing(S: State, draw: () => void) { const t = S.t; S.t = drawTime(S); try { draw(); } finally { S.t = t; }}
/** A person's place to draw: between where they were a step ago and where they are. One who jumped (came in at the * door, a new game) is drawn where they are. */export function placeOf(p: Person): [number, number] { const w = was.get(p); if (!w) return [p.x, p.y]; const dx = p.x - w[0], dy = p.y - w[1]; if (dx * dx + dy * dy > JUMP * JUMP) return [p.x, p.y]; return [w[0] + dx * lead, w[1] + dy * lead];}const JUMP = 160 * STEP * 2; // farther than anyone walks in a step (Dana hurries at 150 a second)
/** How far along its link a scan or trace is drawn. On a new link since the last step, it eases from the link's start. */export function traceAt(T: Trace): number { const w = was.get(T), p = Math.min(1, T.p); if (!w) return p; const from = hops.get(T) === `${T.from}>${T.to}` ? Math.min(1, w[0]) : 0; return from + (p - from) * lead;}