Move with collision reacts along the contact normal: it travels to the surface, stays flush and slides the rest of the move along it with Coulomb friction (the mean of both colliders, a tile counts as 0.5), a circle now rolls over an edge instead of catching on it, pushed dynamic bodies move off along the normal, Move gains the outputs hit, normal x and normal y, an object without its own collider moves freely, and editor run and play share the same path through Solids; contact point and normal come from our own f64 geometry (contactBetween), because Rapier's castShape lands 3e-6 px inside the wall in f32 (#150)
game-maker / gate (push) Successful in 1m48s
game-maker / suite (push) Successful in 6m23s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-18 21:52:11 +02:00
1 parent d931e66f92
commit 1b5e386b60
15 files changed
+680 -161

No files matched your search

+14 -3
View File
@@ -97,6 +97,17 @@ export interface PhysicsControl {
setGravity(x: number, y: number): void;
}
/**
* What a move with collision met: which of the object's own axes something stood against, whether
* it hit anything, and the world normal of the first contact (pointing away from what was hit).
*/
export interface MoveOutcome {
blockedX: boolean;
blockedY: boolean;
hit: boolean;
normal: { x: number; y: number };
}
/**
* Everything the graph does to the world goes through here, so the core stays free of runtime
* imports. Implemented by the runtime (BehaviorSystem) and by test doubles.
@@ -132,10 +143,10 @@ export interface NodeContext {
/** A collider entity stands for itself; any other entity for its direct collider children. */
isTouching(a: EntityHandle, b: EntityHandle): boolean;
/**
* Moves `target` by (dx, dy) in local units, stopping solid colliders at other solid ones axis by
* axis (x first, then y) so it slides along walls.
* Moves `target` by (dx, dy) in local units; its solid colliders stop flush at other solid ones
* and the rest of the move goes on along the surface, less what friction takes.
*/
moveAndSlide(target: EntityHandle, dx: number, dy: number): { blockedX: boolean; blockedY: boolean };
moveAndSlide(target: EntityHandle, dx: number, dy: number): MoveOutcome;
/** Absent where nothing is simulated: the editor run, and a test double that does not ask for it. */
physics?: PhysicsControl;
log(message: string): void;