Let a graph read and change the z of an object

Until now a behavior could not move an object in front of another
while the game runs. Set position writes only x and y, and z lives on
the running object rather than in its props, so Properties cannot
reach it either. Drawing already reads the z every frame, so only the
nodes were missing.

- Get Z (data): object in, z and world z out. World z is summed up
  with the parents, the way drawing does it (worldTransformOf).
- Set Z (action): object and z in. It sets the object's own z, local
  to its parent like Set position. Higher is drawn in front from the
  next frame on.
- Two nodes of their own rather than a z port on Set position and
  Get position, as asked.

Tests:
- node-catalog: Get Z for a child (2 below 5 is world z 7) and for no
  object, Set Z writes only z and leaves x/y.
- set-z.test.ts: in a running world a key sets the lower of two
  sprites to z 2, drawSlots then draws it in front, Get Z logs 2 and 2.
- Two counter-checks bite: Set Z without the write and Get Z without
  the parent fail 3 tests.
- Gate: 233 files, 3548 tests (3542 + 6), CHECK EXIT 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-03 20:08:35 +02:00
1 parent 3e05cbbed5
commit 8452a99c64
5 files changed
+110

No files matched your search

+18
View File
@@ -752,6 +752,14 @@ const CASES: Record<string, Case[]> = {
outputs: { x: 0, y: 0, worldX: 0, worldY: 0 },
},
],
GetZ: [
{
name: 'a child reports its own z and the z summed up with its parents',
inputs: { object: { ...at('child', 0, 0), z: 2, parent: { ...at('parent', 0, 0), z: 5 } } },
outputs: { z: 2, worldZ: 7 },
},
{ name: 'no object is 0', inputs: { object: null }, outputs: { z: 0, worldZ: 0 } },
],
Number: [
{ name: 'outputs its setting', params: { value: 7.5 }, outputs: { value: 7.5 } },
@@ -1500,6 +1508,10 @@ const CASES: Record<string, Case[]> = {
},
{ name: 'no object is a no-op', inputs: { object: null, x: 1, y: 1 }, next: 'exec' },
],
SetZ: [
{ name: 'sets the z and continues', inputs: { object: at('z', 0, 0), z: 3 }, next: 'exec' },
{ name: 'no object is a no-op', inputs: { object: null, z: 3 }, next: 'exec' },
],
ApplyForce: [
{
name: 'pushes for the length of the frame: force × dt, handed on as an impulse',
@@ -2142,6 +2154,12 @@ describe('action nodes write through to the object they are given', () => {
expect({ x: target.x, y: target.y }).toEqual({ x: 30, y: -40 });
});
it('SetZ sets only the z', () => {
const target = { ...at('z', 10, 20), z: 1 };
runDef('SetZ', fakeContext(), { object: target, z: -4 }, {});
expect({ x: target.x, y: target.y, z: target.z }).toEqual({ x: 10, y: 20, z: -4 });
});
it('Destroy hands the object to the context, children and all unless told to keep them', () => {
const removed: string[] = [];
const moved = [fakeEntity('Lid'), fakeEntity('Nail')];