Let Destroy keep the children and hand them back as a list
Destroying a container used to take everything below it along. Now Destroy can remove just the object itself and pass its direct children on, so a behavior can keep working with what was inside. - New input keep children (bool, default off). When on, only the object goes. Its direct children move up to the object's parent, or to the top level if there is none. Grandchildren stay where they are. - New output children (object list) with the direct children that were kept. It is empty when keep children is off. - The children keep their place on screen. carriedTransform folds the destroyed object's position, rotation and scale into their own, the same as reparenting in the editor. - Behaviors and the rigidbody of the object are always destroyed with it and are not in the list. Moved up they would steer or simulate the parent. - World remembers which children it reparented, and syncToModel writes their new parent into the scene. A reload of the model keeps it. - Limit, read from the code only: in the editor run the contents of a placed container are not baked. Moved children there last for the run only. Tests: - ./check.sh: 170 files, 2478 tests, CHECK EXIT 0 - e2e 34 (the module with a Destroy node): ALL PASSED, 21 checks - world-sync: world matrix of child and grandchild unchanged under a rotated and scaled parent, parent survives syncFromModel, top level case, already destroyed object gives [] - destroy-keep-children: real graph Destroy(Owner) -> Log(children) logs Lid, Label without the grandchild Nail - 3 counter-probes, all caught: no world transform (1 test fails), no parent in the scene (1), behaviors and rigidbody moved up (2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7979b8ff19
commit
483c34bb5c
8 files changed
+196
-17
No files matched your search
@@ -227,7 +227,11 @@ export interface NodeContext {
|
||||
position: { x: number; y: number; z: number },
|
||||
parent: EntityHandle | null,
|
||||
): EntityHandle | null;
|
||||
destroy(target: EntityHandle): void;
|
||||
/**
|
||||
* Removes `target` with everything below it. With `keepChildren` only the object goes: its
|
||||
* children move up to its parent where they stand, and are answered, nearest level only.
|
||||
*/
|
||||
destroy(target: EntityHandle, keepChildren: boolean): EntityHandle[];
|
||||
stop(): void;
|
||||
/** Ends the run and starts it again from the saved scene (everything spawned is lost). */
|
||||
restart(): void;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { asEntity } from '../../values';
|
||||
import { exec, obj } from '../shared';
|
||||
import { asBoolean, asEntity } from '../../values';
|
||||
import { bool, exec, list, obj, withDefault } from '../shared';
|
||||
|
||||
export const Destroy: NodeDef = {
|
||||
type: 'Destroy',
|
||||
label: 'Destroy',
|
||||
category: 'action',
|
||||
description: 'Removes an object from the running game.',
|
||||
inputs: [exec(), obj('object')],
|
||||
outputs: [exec()],
|
||||
description:
|
||||
'Removes an object from the running game, with everything below it. With "keep children" only the ' +
|
||||
'object goes: its children move up to its parent and stay where they are in the world, and come out ' +
|
||||
'as "children" – the nearest level only. Its behaviors and its rigidbody go with it either way.',
|
||||
inputs: [exec(), obj('object'), withDefault(bool('keepChildren', 'keep children'), false)],
|
||||
outputs: [exec(), list('children')],
|
||||
params: [],
|
||||
run: (ctx, inputs) => {
|
||||
const target = asEntity(inputs.object);
|
||||
if (target) ctx.destroy(target);
|
||||
return { next: 'exec' };
|
||||
const children = target ? ctx.destroy(target, asBoolean(inputs.keepChildren)) : [];
|
||||
return { next: 'exec', outputs: { children } };
|
||||
},
|
||||
};
|
||||
Reference in new issue
Block a user