Physics stage 1a runs on Rapier: a new Rigidbody child object (body type, mass, gravity scale, damping, fixed rotation, CCD) makes its parent fall, bounce and come to rest in play, colliders gain friction, bounciness and density, the scene gains gravity (0, 980), the new PhysicsSystem steps at a fixed 60 Hz with interpolation in world coordinates and treats a tilemap as static ground, On collision enter gains normal and impulse, play waits for Rapier and does not start without it, and the editor run keeps the old CollisionSystem; the existing collision tests run against both systems unchanged (#146)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d02bcca266
commit
78899b1ace
34 files changed
+2291
-676
No files matched your search
+28
-3
@@ -31,7 +31,10 @@ import type { SceneObject } from '../src/core/model/SceneObject';
|
||||
import { deserializeProject, serializeProject } from '../src/core/store/serialize';
|
||||
import type { AudioSink } from '../src/runtime/systems/Audio';
|
||||
import { BehaviorSystem } from '../src/runtime/systems/BehaviorSystem';
|
||||
import { readyPhysics } from '../src/runtime/physics/engine';
|
||||
import { PhysicsSystem } from '../src/runtime/physics/PhysicsSystem';
|
||||
import { CollisionSystem } from '../src/runtime/systems/CollisionSystem';
|
||||
import type { CollisionSource } from '../src/runtime/systems/solids';
|
||||
import { AnimationSystem } from '../src/runtime/systems/AnimationSystem';
|
||||
import { Input } from '../src/runtime/systems/Input';
|
||||
import { World } from '../src/runtime/World';
|
||||
@@ -269,6 +272,11 @@ export function runNode(
|
||||
|
||||
export interface WorldOptions {
|
||||
collisions?: boolean;
|
||||
/**
|
||||
* With `collisions`: the played game's physics engine rather than the editor run's detection
|
||||
* (#146). The engine has to be loaded first – `await loadPhysics()` in a `beforeAll`.
|
||||
*/
|
||||
physics?: boolean;
|
||||
animations?: boolean;
|
||||
behaviors?: boolean;
|
||||
/** Where `Play sound` ends up; without one the run plays to nobody (see `SILENT_AUDIO`). */
|
||||
@@ -277,7 +285,7 @@ export interface WorldOptions {
|
||||
|
||||
export interface StartedWorld {
|
||||
world: World;
|
||||
collisions: CollisionSystem | null;
|
||||
collisions: CollisionSource | null;
|
||||
behaviors: BehaviorSystem | null;
|
||||
/** Feed keys with `input.press('a')`; `frame()` clears the edges the way the editor does. */
|
||||
input: Input;
|
||||
@@ -289,11 +297,15 @@ export interface StartedWorld {
|
||||
export function startWorld(
|
||||
fixture: SceneFixture,
|
||||
options: WorldOptions & { collisions: true },
|
||||
): StartedWorld & { collisions: CollisionSystem };
|
||||
): StartedWorld & { collisions: CollisionSource };
|
||||
export function startWorld(fixture: SceneFixture, options?: WorldOptions): StartedWorld;
|
||||
export function startWorld(fixture: SceneFixture, options: WorldOptions = {}): StartedWorld {
|
||||
const world = World.instantiate(fixture.project, fixture.sceneId);
|
||||
const collisions = options.collisions ? new CollisionSystem() : null;
|
||||
const collisions = options.collisions
|
||||
? options.physics
|
||||
? new PhysicsSystem(readyPhysics() ?? fail('load the physics engine before starting a world with it'))
|
||||
: new CollisionSystem()
|
||||
: null;
|
||||
const input = new Input();
|
||||
const animations = options.animations ? new AnimationSystem() : null;
|
||||
if (collisions) world.addSystem(collisions);
|
||||
@@ -314,6 +326,19 @@ export function startWorld(fixture: SceneFixture, options: WorldOptions = {}): S
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Both ways a run detects collisions: the editor run's own and the played game's engine (#146).
|
||||
* Everything without a rigidbody must come out the same on either.
|
||||
*/
|
||||
export const COLLISION_SYSTEMS = [
|
||||
{ system: 'CollisionSystem', physics: false },
|
||||
{ system: 'PhysicsSystem', physics: true },
|
||||
] as const;
|
||||
|
||||
function fail(message: string): never {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
/** The project as it comes back after being saved and loaded again. */
|
||||
export function roundTrip(project: Project): Project {
|
||||
return deserializeProject(serializeProject(project));
|
||||
|
||||
Reference in new issue
Block a user