Editing while playing: play runs on a runtime copy, new Game tab (Scene | Game | Graph)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
cb8885359f
commit
c3a533c4e5
14 files changed
+408
-118
No files matched your search
+34
-7
@@ -208,7 +208,7 @@ try {
|
||||
await sleep(300);
|
||||
s = JSON.parse(await stateJson());
|
||||
check('play mode entered', s.mode === 'play', JSON.stringify(s));
|
||||
let info = await evaluate('JSON.stringify(__gm.viewportInfo())');
|
||||
let info = await evaluate('JSON.stringify(__gm.gameInfo())');
|
||||
check('play renders the camera frame with both crates', JSON.parse(info).rendering && JSON.parse(info).visibleItems === 2, info);
|
||||
await shot('08-playing');
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'ArrowRight', code: 'ArrowRight', windowsVirtualKeyCode: 39 });
|
||||
@@ -231,11 +231,38 @@ try {
|
||||
const o1AfterPlay = await evaluate(`__gm.state.activeScene.objects.find(o => o.id === 'o1').position.x`);
|
||||
check('play did not write back to the model', o2AfterPlay === xBeforePlay && o1AfterPlay === -150, `${o2AfterPlay} vs ${xBeforePlay}, o1=${o1AfterPlay}`);
|
||||
|
||||
// 7a. Editing while playing: Play opens the Game tab, the panels stay open and edit a runtime
|
||||
// copy. Moving the blue crate (model hook + preview, as a scrub does) and deleting it with
|
||||
// the Delete key change the world at once, undo brings it back, Esc restores the saved model.
|
||||
await clickText('▶ Play');
|
||||
await sleep(300);
|
||||
check('play opens the Game tab', (await evaluate('__gm.tab()')) === 'game');
|
||||
check('panels stay visible while playing', Boolean(await evaluate(`__gm.locate('INSPECTOR')`)) && (await evaluate('__gm.hierarchyOrder().length')) === 6);
|
||||
await evaluate(`__gm.state.select({ kind: 'object', sceneId: 'scene1', objectId: 'o2' })`);
|
||||
await evaluate(`__gm.state.activeScene.objects.find(o => o.id === 'o2').position.x = 400; __gm.state.preview()`);
|
||||
await sleep(100);
|
||||
let liveO2 = JSON.parse(await evaluate('JSON.stringify(__gm.world())')).entities.find((e) => e.objectId === 'o2');
|
||||
check('an edit while playing moves the entity in the world', liveO2 && liveO2.x === 400, JSON.stringify(liveO2));
|
||||
await shot('08b-editing-while-playing');
|
||||
await keyPress('Delete', 'Delete', { windowsVirtualKeyCode: 46 });
|
||||
await sleep(150);
|
||||
const liveIds = JSON.parse(await evaluate('JSON.stringify(__gm.world())')).entities.map((e) => e.objectId);
|
||||
check('Delete while playing removes the entity and its collider child from the world', !liveIds.includes('o2') && !liveIds.includes('oc2') && liveIds.length === 4, JSON.stringify(liveIds));
|
||||
await keyPress('z', 'KeyZ', { modifiers: 2, windowsVirtualKeyCode: 90 });
|
||||
await sleep(150);
|
||||
liveO2 = JSON.parse(await evaluate('JSON.stringify(__gm.world())')).entities.find((e) => e.objectId === 'o2');
|
||||
check('undo while playing brings the entity back into the world', liveO2 && liveO2.x === 400, JSON.stringify(liveO2));
|
||||
await keyPress('Escape', 'Escape', { windowsVirtualKeyCode: 27 });
|
||||
await sleep(300);
|
||||
const o2AfterEdit = await evaluate(`__gm.state.activeScene.objects.find(o => o.id === 'o2').position.x`);
|
||||
check('stop restores the saved model untouched by play-mode edits', o2AfterEdit === xBeforePlay && (await evaluate('__gm.state.activeScene.objects.length')) === 6, `x=${o2AfterEdit}`);
|
||||
check('stop returns to the Scene tab', (await evaluate('__gm.tab()')) === 'scene');
|
||||
|
||||
// 7b. Culling: move the blue crate far outside the camera frame → only one item visible.
|
||||
await evaluate(`__gm.state.activeScene.objects.find(o => o.id === 'o2').position.x = 5000; __gm.state.preview()`);
|
||||
await clickText('▶ Play');
|
||||
await sleep(300);
|
||||
info = await evaluate('JSON.stringify(__gm.viewportInfo())');
|
||||
info = await evaluate('JSON.stringify(__gm.gameInfo())');
|
||||
check('objects outside the camera frame are culled', JSON.parse(info).visibleItems === 1, info);
|
||||
await keyPress('Escape', 'Escape', { windowsVirtualKeyCode: 27 });
|
||||
await sleep(200);
|
||||
@@ -248,7 +275,7 @@ try {
|
||||
check('camera object deleted', (await evaluate('__gm.state.activeScene.objects.length')) === 5);
|
||||
await clickText('▶ Play');
|
||||
await sleep(300);
|
||||
info = await evaluate('JSON.stringify(__gm.viewportInfo())');
|
||||
info = await evaluate('JSON.stringify(__gm.gameInfo())');
|
||||
s = JSON.parse(await stateJson());
|
||||
check('play without camera renders nothing', s.mode === 'play' && !JSON.parse(info).rendering && JSON.parse(info).visibleItems === 0, info);
|
||||
check('play without camera shows a notice', s.notice.includes('no camera'), s.notice);
|
||||
@@ -424,7 +451,7 @@ try {
|
||||
const restored = await graphCounts();
|
||||
check('undo restores node and edge', restored.nodes === before13.nodes + 1 && restored.edges === before13.edges + 1, JSON.stringify(restored));
|
||||
|
||||
// 13e. Play always starts on the Scene tab; switching back to Graph while playing shows
|
||||
// 13e. Play always starts on the Game tab; switching to Graph while playing shows
|
||||
// the live highlight: hold ArrowRight → the exec edge is hot.
|
||||
const fpsEdit = await evaluate('__gm.fps()');
|
||||
check('fps readout is measured in edit mode', typeof fpsEdit === 'number' && fpsEdit > 0, `fps=${fpsEdit}`);
|
||||
@@ -433,7 +460,7 @@ try {
|
||||
check('fps label is visible in the toolbar', fpsLabel === true);
|
||||
await clickText('▶ Play');
|
||||
await sleep(200);
|
||||
check('play switches to the scene tab', (await evaluate('__gm.tab()')) === 'scene');
|
||||
check('play switches to the game tab', (await evaluate('__gm.tab()')) === 'game');
|
||||
await sleep(600);
|
||||
const fpsPlay = await evaluate('__gm.fps()');
|
||||
check('fps readout keeps running in play mode', typeof fpsPlay === 'number' && fpsPlay > 0, `fps=${fpsPlay}`);
|
||||
@@ -584,8 +611,8 @@ try {
|
||||
const collisionWorld = JSON.parse(await evaluate('JSON.stringify(__gm.world())'));
|
||||
check('On collision enter fired once with the other body', collisionWorld && collisionWorld.log.filter((l) => l === 'Blue crate').length === 1, JSON.stringify(collisionWorld?.log));
|
||||
const spriteCount = await evaluate(`__gm.state.activeScene.objects.filter(o => __gm.state.project.assets.find(a => a.id === o.assetId)?.type === 'sprite').length`);
|
||||
info = await evaluate('JSON.stringify(__gm.viewportInfo())');
|
||||
check('colliders are not rendered in play mode', JSON.parse(info).visibleItems === spriteCount, `${info} sprites=${spriteCount}`);
|
||||
info = await evaluate('JSON.stringify(__gm.gameInfo())');
|
||||
check('colliders are not rendered in the game view', JSON.parse(info).visibleItems === spriteCount, `${info} sprites=${spriteCount}`);
|
||||
await keyPress('Escape', 'Escape', { windowsVirtualKeyCode: 27 });
|
||||
await sleep(200);
|
||||
|
||||
|
||||
Reference in new issue
Block a user