Set gravity survives a re-read of the model during play: World.setSceneProp remembers what the run itself set on the scene and syncFromModel lays it back over the copied scene props, so a project event mid-play no longer resets the gravity to the saved 980; the unit test re-reads the model mid-run and e2e 41c forces a project event right after play starts (#147)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0ff3c8b742
commit
328f978d3c
4 files changed
+22
-5
No files matched your search
@@ -37,6 +37,8 @@ export class World {
|
||||
readonly entities: Entity[] = [];
|
||||
/** The running scene's own properties – read from the model, and written by an animation over the scene. */
|
||||
readonly sceneProps: PropertyBag = {};
|
||||
/** What the run itself set on the scene (`setSceneProp`); re-reading the model does not undo it. */
|
||||
private readonly runSceneProps: PropertyBag = {};
|
||||
/** Set by a behavior (Stop game node); the editor leaves play mode on the next tick. */
|
||||
stopRequested = false;
|
||||
/** Set by a behavior (Restart game node); the editor restarts the scene on the next tick. */
|
||||
@@ -98,7 +100,7 @@ export class World {
|
||||
// behavior destroy one of them for good. Play does it (on its throwaway copy); the editor run
|
||||
// must not, so there the content stays resolved and `objectRef` writes into the instance edits.
|
||||
if (this.bakeContainers && bakeInstances(this.project, scene)) this.structureChanged = true;
|
||||
Object.assign(this.sceneProps, scene.props);
|
||||
Object.assign(this.sceneProps, scene.props, this.runSceneProps);
|
||||
const objects = new Map(resolveObjects(this.project, scene).map((o) => [o.id, o]));
|
||||
const keep = new Set<Entity>();
|
||||
for (const object of objects.values()) {
|
||||
@@ -115,6 +117,12 @@ export class World {
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a scene property for the rest of the run; the scene in the model keeps its own. */
|
||||
setSceneProp(key: string, value: PropertyBag[string]): void {
|
||||
this.sceneProps[key] = value;
|
||||
this.runSceneProps[key] = value;
|
||||
}
|
||||
|
||||
/** The entity for a scene object, created when missing; position, name and props re-read. */
|
||||
private materialize(object: SceneObject, asset: Asset): Entity {
|
||||
let entity = this.findByObjectId(object.id);
|
||||
|
||||
@@ -216,8 +216,8 @@ export class PhysicsSystem implements System, CollisionSource {
|
||||
|
||||
/** The scene's gravity for the rest of this run, in world units per second squared. */
|
||||
setGravity(world: World, gravity: Vec2): void {
|
||||
world.sceneProps.gravityX = gravity.x;
|
||||
world.sceneProps.gravityY = gravity.y;
|
||||
world.setSceneProp('gravityX', gravity.x);
|
||||
world.setSceneProp('gravityY', gravity.y);
|
||||
if (this.engine) this.engine.gravity = this.gravity(world);
|
||||
}
|
||||
|
||||
|
||||
@@ -586,13 +586,19 @@ describe('physics from the graph (#147)', () => {
|
||||
|
||||
it('Set gravity turns the fall around for the rest of the run; the scene in the project keeps its own', () => {
|
||||
const f = physicsScene();
|
||||
f.gravity(0, 980);
|
||||
const box = f.add(0, 0, { w: 32, body: {} });
|
||||
onOwner(f, box, 'OnStart', 'SetGravity', { x: 0, y: -980 }, true);
|
||||
const { seconds, entity, world } = run(f);
|
||||
seconds(0.5);
|
||||
seconds(0.25);
|
||||
// A model event while playing re-reads the scene, after the tick wrote back (as in PlaySession);
|
||||
// the run's own gravity outlives it.
|
||||
world.syncToModel();
|
||||
world.syncFromModel();
|
||||
seconds(0.25);
|
||||
expect(entity(box).y).toBeLessThan(-100);
|
||||
expect(world.sceneProps.gravityY).toBe(-980);
|
||||
expect(findAsset(f.project, f.sceneId)!.props.gravityY ?? 980).toBe(980);
|
||||
expect(findAsset(f.project, f.sceneId)!.props.gravityY).toBe(980);
|
||||
});
|
||||
|
||||
it('moving a dynamic body directly keeps its speed and says so once; a physics node on an object without one says so once', () => {
|
||||
|
||||
@@ -258,6 +258,9 @@ export async function physics(t) {
|
||||
put('phys-pushed-rb', 'phys-rb-free', 'phys-pushed', 0, 0);
|
||||
__gm.state.select(null)`);
|
||||
await play();
|
||||
// A model event while playing re-reads the scene (CI had one in the first frames): what the run
|
||||
// set with Set gravity has to outlive it.
|
||||
await evaluate(`__gm.state.preview()`);
|
||||
await evaluate(`(() => {
|
||||
const out = (window.__physicsGraph = []);
|
||||
const start = performance.now();
|
||||
|
||||
Reference in new issue
Block a user