Let a behavior be a node in another graph
A behavior that has a Start and an End node can now be dropped into any other graph as a node of its own. What is declared on the start node becomes the inputs of that node, what hangs on the end node its outputs; the port list is derived from the sub graph, not copied, so declaring a port in one graph grows the node in the other without touching it. The node carries the behavior's name and the palette lists behaviors by name, so a call is one grab instead of a node plus a dropdown. An embedded behavior has no object and therefore no place for variables: every call starts on the asset defaults and communicates only through its ports. That is the conservative direction - state can still be added later, and shared state already has a home in a behavior object in the scene. Node ids are unique per graph only, so each call gets its own pulse cache; without that, two graphs would collide. Renaming a port used to silently drop the value typed on the calling node. It is carried along now, project wide, like the edges.
This commit is contained in:
1 parent
64e034ffb9
commit
6702ff8abe
31 files changed
+1402
-107
No files matched your search
@@ -0,0 +1,21 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { BEHAVIOR_END } from '../../nested';
|
||||
import { exec } from '../shared';
|
||||
|
||||
/**
|
||||
* The exit of a behavior used as a node: what arrives at its declared inputs leaves the calling
|
||||
* node as output. Handing the inputs straight back out is what parks the result in the pulse
|
||||
* cache, where the caller reads it once the flow has returned.
|
||||
*/
|
||||
export const BehaviorEnd: NodeDef = {
|
||||
type: BEHAVIOR_END,
|
||||
label: 'End',
|
||||
category: 'flow',
|
||||
description:
|
||||
'Ends this behavior and hands its results back to the graph that ran it. Every output declared ' +
|
||||
'here becomes an output port on that node.',
|
||||
inputs: [exec()],
|
||||
outputs: [],
|
||||
params: [],
|
||||
run: (_ctx, inputs) => ({ outputs: inputs }),
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { BEHAVIOR_START } from '../../nested';
|
||||
import { exec } from '../shared';
|
||||
|
||||
/**
|
||||
* The entry point of a behavior used as a node. Its declared outputs are the inputs the calling
|
||||
* graph passes in; the interpreter seeds them, so it has no `run` – like an event node.
|
||||
*/
|
||||
export const BehaviorStart: NodeDef = {
|
||||
type: BEHAVIOR_START,
|
||||
label: 'Start',
|
||||
category: 'event',
|
||||
description:
|
||||
'Where this behavior begins when another graph runs it as a node. Every input declared here ' +
|
||||
'becomes an input port on that node.',
|
||||
inputs: [],
|
||||
outputs: [exec()],
|
||||
params: [],
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { BEHAVIOR_PARAM, RUN_BEHAVIOR } from '../../nested';
|
||||
import { exec } from '../shared';
|
||||
|
||||
/**
|
||||
* Runs another behavior's graph in place, from its start node to its end node. The ports come from
|
||||
* those two nodes (see `nested.ts`); the interpreter does the call, because only it can hold a
|
||||
* second graph's pulse.
|
||||
*/
|
||||
export const RunBehavior: NodeDef = {
|
||||
type: RUN_BEHAVIOR,
|
||||
label: 'Run behavior',
|
||||
category: 'flow',
|
||||
description:
|
||||
'Runs another behavior as a step of this one, passing values in and taking results out. The ' +
|
||||
'behavior keeps no state between calls: its variables start at their defaults every time.',
|
||||
inputs: [exec()],
|
||||
outputs: [exec()],
|
||||
params: [{ key: BEHAVIOR_PARAM, label: 'Behavior', kind: 'asset', default: '', assetTypes: ['behavior'] }],
|
||||
run: (_ctx, inputs, params) => ({
|
||||
call: { behaviorId: String(params[BEHAVIOR_PARAM] ?? ''), inputs },
|
||||
next: 'exec',
|
||||
}),
|
||||
};
|
||||
@@ -65,8 +65,11 @@ import { OnKeyUp } from './events/OnKeyUp';
|
||||
import { OnStart } from './events/OnStart';
|
||||
import { OnTimer } from './events/OnTimer';
|
||||
import { OnUpdate } from './events/OnUpdate';
|
||||
import { BehaviorEnd } from './flow/BehaviorEnd';
|
||||
import { BehaviorStart } from './flow/BehaviorStart';
|
||||
import { Branch } from './flow/Branch';
|
||||
import { Repeat } from './flow/Repeat';
|
||||
import { RunBehavior } from './flow/RunBehavior';
|
||||
import { Sequence } from './flow/Sequence';
|
||||
import { GetVariable } from './variable/GetVariable';
|
||||
import { SetVariable } from './variable/SetVariable';
|
||||
@@ -87,10 +90,13 @@ export const BUILT_IN_NODES: readonly NodeDef[] = [
|
||||
OnCollisionStay,
|
||||
OnCollisionExit,
|
||||
OnClick,
|
||||
BehaviorStart,
|
||||
// flow
|
||||
Branch,
|
||||
Sequence,
|
||||
Repeat,
|
||||
RunBehavior,
|
||||
BehaviorEnd,
|
||||
// variables
|
||||
GetVariable,
|
||||
SetVariable,
|
||||
|
||||
Reference in new issue
Block a user