Physics stage 1b: six new nodes act on dynamic bodies in play (Apply force over the frame, independent of the frame rate, Apply impulse, Set velocity, Set angular velocity, Get velocity, Set gravity for the rest of the run), a node on an object without a dynamic body and moving a dynamic body directly each log a hint once per object, and Move with collision now pushes dynamic bodies with a mass-dependent push while the mover stays flush; Move keeps its own move-and-slide instead of Rapier's character controller, which measurably snags on seams between colliders (#147)
game-maker / gate (push) Successful in 1m46s
game-maker / suite (push) Failing after 5m35s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-18 19:19:21 +02:00
1 parent 78899b1ace
commit 0ff3c8b742
10 files changed
+783 -43

No files matched your search

+34
View File
@@ -10,6 +10,7 @@ import {
GraphInterpreter,
isHandleEnabled,
type NodeContext,
type PhysicsControl,
type SharedState,
startStates,
type TraceListener,
@@ -61,6 +62,9 @@ interface StateChange {
source: Instance | null;
}
const NO_DYNAMIC_BODY =
'has no dynamic rigidbody, so Apply force, Apply impulse and Set velocity do nothing on it.';
/** How often state events may cause the next move before the run is called endless. */
const MAX_STATE_ROUNDS = 100;
@@ -565,6 +569,10 @@ export class BehaviorSystem implements System {
found.y += dy;
return { blockedX: false, blockedY: false };
},
physics:
this.collisions instanceof PhysicsSystem
? physicsControl(world, this.collisions, resolve)
: undefined,
log: (message) => {
world.log.push(message);
// The `Log` node's whole purpose: the author wants this in the browser console.
@@ -599,3 +607,29 @@ export class BehaviorSystem implements System {
};
}
}
/** The physics nodes' way into the played game's engine, with the handles of the graph resolved. */
function physicsControl(
world: World,
physics: PhysicsSystem,
resolve: (handle: EntityHandle | null) => Entity | undefined,
): PhysicsControl {
const act = (handle: EntityHandle, action: (entity: Entity) => boolean): boolean => {
const found = resolve(handle);
if (!found) return false;
if (action(found)) return true;
physics.hint(world, found, NO_DYNAMIC_BODY);
return false;
};
return {
velocityOf: (handle) => {
const found = resolve(handle);
const v = found ? physics.velocityOf(found) : null;
return found && v ? { ...v, angular: physics.angularVelocityOf(found) ?? 0 } : null;
},
setVelocity: (handle, x, y) => act(handle, (e) => physics.setVelocity(e, { x, y })),
setAngularVelocity: (handle, degrees) => act(handle, (e) => physics.setAngularVelocity(e, degrees)),
applyImpulse: (handle, x, y) => act(handle, (e) => physics.applyImpulse(e, { x, y })),
setGravity: (x, y) => physics.setGravity(world, { x, y }),
};
}