Spawn node: place assets at runtime into the play copy, Spawner demo behavior
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
c3a533c4e5
commit
91ee2feadd
13 files changed
+219
-37
No files matched your search
+21
-6
@@ -237,7 +237,7 @@ try {
|
||||
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);
|
||||
check('panels stay visible while playing', Boolean(await evaluate(`__gm.locate('INSPECTOR')`)) && (await evaluate('__gm.hierarchyOrder().length')) === 7);
|
||||
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);
|
||||
@@ -247,15 +247,30 @@ try {
|
||||
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));
|
||||
check('Delete while playing removes the entity and its collider child from the world', !liveIds.includes('o2') && !liveIds.includes('oc2') && liveIds.length === 5, 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));
|
||||
// 7a-ii. Spawning: the "Spawner" behavior places a Crate at (0, 150) on Space. The new object
|
||||
// shows up in the runtime scene (hierarchy), in the world and in the Game view at once;
|
||||
// Stop discards it with the rest of the runtime copy.
|
||||
const visibleBeforeSpawn = JSON.parse(await evaluate('JSON.stringify(__gm.gameInfo())')).visibleItems;
|
||||
await keyPress(' ', 'Space', { windowsVirtualKeyCode: 32 });
|
||||
await sleep(200);
|
||||
const spawnedObjects = JSON.parse(await evaluate('JSON.stringify(__gm.state.activeScene.objects)'));
|
||||
const spawned = spawnedObjects.find((o) => !['o1', 'o2', 'o3', 'o4', 'o5', 'oc1', 'oc2'].includes(o.id));
|
||||
check('Spawn node adds a crate object to the runtime scene at (0, 150)', spawned && spawned.assetId === 'crate' && spawned.parentId === '' && spawned.position.x === 0 && spawned.position.y === 150 && spawnedObjects.length === 8, JSON.stringify(spawned));
|
||||
const spawnWorld = JSON.parse(await evaluate('JSON.stringify(__gm.world())'));
|
||||
check('the spawned entity lives in the world and its name reached the Log node', spawnWorld.entities.length === 8 && spawnWorld.log.includes('Crate'), JSON.stringify({ n: spawnWorld.entities.length, log: spawnWorld.log }));
|
||||
check('hierarchy lists the spawned object', (await evaluate('__gm.hierarchyOrder().length')) === 8);
|
||||
info = await evaluate('JSON.stringify(__gm.gameInfo())');
|
||||
check('the Game view renders the spawned crate', JSON.parse(info).visibleItems === visibleBeforeSpawn + 1, `${info} before=${visibleBeforeSpawn}`);
|
||||
await shot('08c-spawned');
|
||||
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 restores the saved model untouched by play-mode edits (spawned object gone)', o2AfterEdit === xBeforePlay && (await evaluate('__gm.state.activeScene.objects.length')) === 7, `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.
|
||||
@@ -272,7 +287,7 @@ try {
|
||||
await evaluate(`__gm.state.select({ kind: 'object', sceneId: 'scene1', objectId: 'o3' })`);
|
||||
await keyPress('Delete', 'Delete', { windowsVirtualKeyCode: 46 });
|
||||
await sleep(200);
|
||||
check('camera object deleted', (await evaluate('__gm.state.activeScene.objects.length')) === 5);
|
||||
check('camera object deleted', (await evaluate('__gm.state.activeScene.objects.length')) === 6);
|
||||
await clickText('▶ Play');
|
||||
await sleep(300);
|
||||
info = await evaluate('JSON.stringify(__gm.gameInfo())');
|
||||
@@ -284,7 +299,7 @@ try {
|
||||
await sleep(300);
|
||||
await keyPress('z', 'KeyZ', { modifiers: 2, windowsVirtualKeyCode: 90 });
|
||||
await sleep(200);
|
||||
check('undo restored the camera object', (await evaluate('__gm.state.activeScene.objects.length')) === 6);
|
||||
check('undo restored the camera object', (await evaluate('__gm.state.activeScene.objects.length')) === 7);
|
||||
|
||||
// 8. Context menu on the Crate asset → menu shows "Place in scene".
|
||||
await clickText('Crate', 'right');
|
||||
@@ -295,7 +310,7 @@ try {
|
||||
await clickText('Place in scene');
|
||||
await sleep(200);
|
||||
const count = await evaluate('__gm.state.activeScene.objects.length');
|
||||
check('placing from the menu adds an object', count === 7, `objects=${count}`);
|
||||
check('placing from the menu adds an object', count === 8, `objects=${count}`);
|
||||
|
||||
// 9. Create a new asset through the + menu.
|
||||
await clickText('+');
|
||||
|
||||
Reference in new issue
Block a user