Let Get position give only the local x and y
game-maker / gate (push) Successful in 3m6s
game-maker / suite (push) Successful in 16m6s

Get world position now covers the world coordinates. Two nodes that
both offer world x and y made it unclear which one to take. No project
uses the world outputs of Get position any more.

- Get position drops its world x and world y outputs and its
  description points to Get world position.
- Old snapshots with edges on those outputs still load. The edges hang
  on ghost ports and the node warns about them.
- The unit tests in hierarchy and raycast and the graphs in e2e 43 use
  Get world position where they read the world coordinates.

Tests:
- node-catalog, hierarchy, raycast: 3 files, 417 tests, all green
- e2e 43 on melektaus-atx: ALL PASSED, 17 checks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-04 19:13:58 +02:00
1 parent 526b1da7f4
commit 2da07599d8
5 files changed
+24 -28

No files matched your search

+3 -5
View File
@@ -1,4 +1,3 @@
import { worldPositionOf } from '../../NodeContext';
import type { NodeDef } from '../../NodeRegistry';
import { asEntity } from '../../values';
import { num, obj } from '../shared';
@@ -7,13 +6,12 @@ export const GetPosition: NodeDef = {
type: 'GetPosition',
label: 'Get position',
category: 'data',
description: 'The position of an object: local to its parent (x/y) and in world units (world x/y).',
description: 'The position of an object local to its parent. Get world position gives it in world units.',
inputs: [obj('object')],
outputs: [num('x'), num('y'), num('worldX', 'world x'), num('worldY', 'world y')],
outputs: [num('x'), num('y')],
params: [],
run: (_ctx, inputs) => {
const target = asEntity(inputs.object);
const world = target ? worldPositionOf(target) : { x: 0, y: 0 };
return { outputs: { x: target?.x ?? 0, y: target?.y ?? 0, worldX: world.x, worldY: world.y } };
return { outputs: { x: target?.x ?? 0, y: target?.y ?? 0 } };
},
};
+6 -4
View File
@@ -237,7 +237,7 @@ describe('runtime hierarchy', () => {
expect(world.entities).toHaveLength(0);
});
it('Get position exposes local and world coordinates, Parent walks up', () => {
it('Get position and Get world position tell local from world, Parent walks up', () => {
const parent = { ...fakeEntity('p', 100), y: 20 };
const child = { ...fakeEntity('c', 5), y: 5, parent };
// On start → Log(world x of self) → Log(local x of self) → Log(world x of self's parent)
@@ -245,9 +245,10 @@ describe('runtime hierarchy', () => {
nodes: [
{ id: 'start', type: 'OnStart', x: 0, y: 0, params: {} },
{ id: 'self', type: 'Self', x: 0, y: 0, params: {} },
{ id: 'wpos', type: 'GetWorldPosition', x: 0, y: 0, params: {} },
{ id: 'pos', type: 'GetPosition', x: 0, y: 0, params: {} },
{ id: 'par', type: 'Parent', x: 0, y: 0, params: {} },
{ id: 'ppos', type: 'GetPosition', x: 0, y: 0, params: {} },
{ id: 'ppos', type: 'GetWorldPosition', x: 0, y: 0, params: {} },
{ id: 'log1', type: 'Log', x: 0, y: 0, params: {} },
{ id: 'log2', type: 'Log', x: 0, y: 0, params: {} },
{ id: 'log3', type: 'Log', x: 0, y: 0, params: {} },
@@ -257,11 +258,12 @@ describe('runtime hierarchy', () => {
{ id: 'e2', from: { node: 'log1', port: 'exec' }, to: { node: 'log2', port: 'exec' } },
{ id: 'e3', from: { node: 'log2', port: 'exec' }, to: { node: 'log3', port: 'exec' } },
{ id: 'e4', from: { node: 'self', port: 'object' }, to: { node: 'pos', port: 'object' } },
{ id: 'e4b', from: { node: 'self', port: 'object' }, to: { node: 'wpos', port: 'object' } },
{ id: 'e5', from: { node: 'self', port: 'object' }, to: { node: 'par', port: 'object' } },
{ id: 'e6', from: { node: 'par', port: 'parent' }, to: { node: 'ppos', port: 'object' } },
{ id: 'e7', from: { node: 'pos', port: 'worldX' }, to: { node: 'log1', port: 'message' } },
{ id: 'e7', from: { node: 'wpos', port: 'x' }, to: { node: 'log1', port: 'message' } },
{ id: 'e8', from: { node: 'pos', port: 'x' }, to: { node: 'log2', port: 'message' } },
{ id: 'e9', from: { node: 'ppos', port: 'worldX' }, to: { node: 'log3', port: 'message' } },
{ id: 'e9', from: { node: 'ppos', port: 'x' }, to: { node: 'log3', port: 'message' } },
],
};
const ctx = fakeContext({ self: child, owner: parent, variables: {} });
+5 -9
View File
@@ -737,20 +737,16 @@ const CASES: Record<string, Case[]> = {
],
GetPosition: [
{
name: 'local and world position of a top-level object are the same',
name: 'a top-level object is at its own position',
inputs: { object: at('A', 10, 20) },
outputs: { x: 10, y: 20, worldX: 10, worldY: 20 },
outputs: { x: 10, y: 20 },
},
{
name: 'a child reports its local position and the summed world position',
name: 'a child reports its position local to the parent',
inputs: { object: { ...at('child', 10, 20), parent: at('parent', 100, 200) } },
outputs: { x: 10, y: 20, worldX: 110, worldY: 220 },
},
{
name: 'no object is the origin',
inputs: { object: null },
outputs: { x: 0, y: 0, worldX: 0, worldY: 0 },
outputs: { x: 10, y: 20 },
},
{ name: 'no object is the origin', inputs: { object: null }, outputs: { x: 0, y: 0 } },
],
GetWorldPosition: [
{
+2 -2
View File
@@ -483,7 +483,7 @@ describe.each(COLLISION_SYSTEMS)('$system: every hit on the line (#157)', ({ phy
const logCount = edit.addNode('Log');
const logDistances = edit.addNode('Log');
const second = edit.addNode('ItemAt', { index: 1 });
const where = edit.addNode('GetPosition');
const where = edit.addNode('GetWorldPosition');
const logSecond = edit.addNode('Log');
edit.wire([
[update, 'exec', ray, 'exec'],
@@ -494,7 +494,7 @@ describe.each(COLLISION_SYSTEMS)('$system: every hit on the line (#157)', ({ phy
[ray, 'objects', second, 'list'],
[second, 'item', where, 'object'],
[logDistances, 'exec', logSecond, 'exec'],
[where, 'worldY', logSecond, 'message'],
[where, 'y', logSecond, 'message'],
]);
const r = run(s, physics);
r.frame(1 / 60);
+8 -8
View File
@@ -46,14 +46,14 @@ const eyeGraph = {
nodes: [
node('qe-update', 'OnUpdate', 0, 0),
node('qe-owner', 'Owner', 0, 160),
node('qe-where', 'GetPosition', 250, 160),
node('qe-where', 'GetWorldPosition', 250, 160),
node('qe-ray', 'Raycast', 500, 0, { dirX: 0, dirY: 1, length: 500 }),
],
edges: [
edge('qe-e1', 'qe-update', 'exec', 'qe-ray', 'exec'),
edge('qe-e2', 'qe-owner', 'object', 'qe-where', 'object'),
edge('qe-e3', 'qe-where', 'worldX', 'qe-ray', 'fromX'),
edge('qe-e4', 'qe-where', 'worldY', 'qe-ray', 'fromY'),
edge('qe-e3', 'qe-where', 'x', 'qe-ray', 'fromX'),
edge('qe-e4', 'qe-where', 'y', 'qe-ray', 'fromY'),
],
};
@@ -81,7 +81,7 @@ const allEyeGraph = {
nodes: [
node('qa-timer', 'OnTimer', 0, 320, { interval: 0.2 }),
node('qa-owner', 'Owner', 0, 160),
node('qa-where', 'GetPosition', 250, 160),
node('qa-where', 'GetWorldPosition', 250, 160),
node('qa-ray', 'RaycastAll', 500, 0, { dirX: 0, dirY: 1, length: 500 }),
node('qa-count', 'Log', 750, 0),
node('qa-distances', 'Log', 1000, 0),
@@ -94,8 +94,8 @@ const allEyeGraph = {
edges: [
edge('qa-e1', 'qa-timer', 'exec', 'qa-ray', 'exec'),
edge('qa-e2', 'qa-owner', 'object', 'qa-where', 'object'),
edge('qa-e3', 'qa-where', 'worldX', 'qa-ray', 'fromX'),
edge('qa-e4', 'qa-where', 'worldY', 'qa-ray', 'fromY'),
edge('qa-e3', 'qa-where', 'x', 'qa-ray', 'fromX'),
edge('qa-e4', 'qa-where', 'y', 'qa-ray', 'fromY'),
edge('qa-e5', 'qa-ray', 'exec', 'qa-count', 'exec'),
edge('qa-e6', 'qa-ray', 'count', 'qa-count', 'message'),
edge('qa-e7', 'qa-count', 'exec', 'qa-distances', 'exec'),
@@ -105,8 +105,8 @@ const allEyeGraph = {
edge('qa-e11', 'qa-distances', 'exec', 'qa-log-name', 'exec'),
edge('qa-e12', 'qa-name', 'name', 'qa-log-name', 'message'),
edge('qa-e13', 'qa-log-name', 'exec', 'qa-one', 'exec'),
edge('qa-e14', 'qa-where', 'worldX', 'qa-one', 'fromX'),
edge('qa-e15', 'qa-where', 'worldY', 'qa-one', 'fromY'),
edge('qa-e14', 'qa-where', 'x', 'qa-one', 'fromX'),
edge('qa-e15', 'qa-where', 'y', 'qa-one', 'fromY'),
edge('qa-e16', 'qa-one', 'exec', 'qa-log-one', 'exec'),
edge('qa-e17', 'qa-one', 'distances', 'qa-log-one', 'message'),
],