The graph was only locked by five edit-mode guards in GraphCanvas. The running game reads the graph by reference each frame, so a new node, edge, changed value, disconnect or undo takes effect from the next frame. Stop discards these edits like everything else changed in play. A new On start node does not fire for a behavior that has already started. During play every data output shows the value it last produced, in the highlight colour and refreshed ten times a second. Values are kept per graph, because node ids are only unique within one; with several instances the most recent value wins. The Variables node reads the live variable bag, so only its own outputs are kept, as a snapshot. Each time an exec edge fires, a bead runs along it in 0.3 s, at most one every 0.15 s per edge, following the same curve the edge is drawn with. Beads run on game time and freeze while paused; the game logic is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
41 lines
1.6 KiB
TypeScript
41 lines
1.6 KiB
TypeScript
/** Seconds a bead takes from the source port to the target port. */
|
|
export const BEAD_TRAVEL = 0.3;
|
|
/** Shortest gap between two beads on one edge: an edge firing every frame shows a chain, not a solid line. */
|
|
export const BEAD_SPACING = 0.15;
|
|
|
|
/** Launch times of the beads on one edge, oldest first; drops those that have arrived. */
|
|
export function launchBead(times: number[], now: number): void {
|
|
const last = times[times.length - 1];
|
|
// The tolerance keeps a fire exactly one spacing later (nine frames at 60 fps) from rounding below it.
|
|
if (last !== undefined && now - last < BEAD_SPACING - 1e-9) return;
|
|
while (times.length > 0 && now - times[0]! > BEAD_TRAVEL) times.shift();
|
|
times.push(now);
|
|
}
|
|
|
|
/** How far each bead has come, 0 at the source and 1 at the target. */
|
|
export function beadsInFlight(times: readonly number[], now: number): number[] {
|
|
return times.map((t) => (now - t) / BEAD_TRAVEL).filter((p) => p >= 0 && p <= 1);
|
|
}
|
|
|
|
/** How far an edge's curve reaches out of its ports before it bends towards the other end. */
|
|
export function curveReach(x1: number, x2: number): number {
|
|
return Math.max(40, Math.abs(x2 - x1) * 0.5);
|
|
}
|
|
|
|
/** The point at `t` on the curve `bezier` draws from (x1, y1) to (x2, y2). */
|
|
export function curvePoint(
|
|
x1: number,
|
|
y1: number,
|
|
x2: number,
|
|
y2: number,
|
|
t: number,
|
|
): { x: number; y: number } {
|
|
const dx = curveReach(x1, x2);
|
|
const u = 1 - t;
|
|
const [a, b, c, d] = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t];
|
|
return {
|
|
x: a * x1 + b * (x1 + dx) + c * (x2 - dx) + d * x2,
|
|
y: a * y1 + b * y1 + c * y2 + d * y2,
|
|
};
|
|
}
|