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
@@ -81,14 +81,21 @@ export class NodeView extends Widget {
|
||||
/** Data inputs that currently have a connection (their inline value is hidden). */
|
||||
private connected = new Set<string>();
|
||||
|
||||
/**
|
||||
* Not fixed at construction: a nested-behavior node's ports come from another graph, so the
|
||||
* definition that applies to this node can change without the node itself changing.
|
||||
*/
|
||||
def: NodeDef;
|
||||
|
||||
constructor(
|
||||
readonly node: GraphNode,
|
||||
readonly def: NodeDef,
|
||||
def: NodeDef,
|
||||
) {
|
||||
super();
|
||||
this.def = def;
|
||||
this.cursor = 'grab';
|
||||
this.addChild(this.box, this.ports);
|
||||
this.sync(node, { nodes: [node], edges: [] }, null, null);
|
||||
this.sync(node, { nodes: [node], edges: [] }, null, null, def);
|
||||
}
|
||||
|
||||
/** Ports sit on the left/right edges; widen the hit area so they can be grabbed. */
|
||||
@@ -98,10 +105,23 @@ export class NodeView extends Widget {
|
||||
}
|
||||
|
||||
/** `project` resolves asset references (Spawn, Is asset). */
|
||||
sync(node: GraphNode, graph: Graph, asset: BehaviorAsset | null, project: Project | null): void {
|
||||
this.paramLines = this.def.params.map(
|
||||
(p) => `${p.label}: ${formatParam(p, node.params[p.key] ?? p.default, asset, project)}`,
|
||||
);
|
||||
sync(
|
||||
node: GraphNode,
|
||||
graph: Graph,
|
||||
asset: BehaviorAsset | null,
|
||||
project: Project | null,
|
||||
def: NodeDef,
|
||||
): void {
|
||||
this.def = def;
|
||||
this.paramLines = this.def.params
|
||||
.map((p) => ({
|
||||
label: p.label,
|
||||
value: formatParam(p, node.params[p.key] ?? p.default, asset, project),
|
||||
}))
|
||||
// A setting the title already states is not worth a row: a nested-behavior node is titled
|
||||
// with the behavior it runs, so "Behavior: Double" under "Double" says nothing new.
|
||||
.filter((p) => p.value !== this.def.label)
|
||||
.map((p) => `${p.label}: ${p.value}`);
|
||||
this.connected = new Set(
|
||||
inlineInputs(this.def)
|
||||
.filter((p) => edgesInto(graph, node.id, p.key).length > 0)
|
||||
|
||||
Reference in new issue
Block a user