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
@@ -5,6 +5,7 @@ import {
|
||||
type NodeContext,
|
||||
type TraceListener,
|
||||
} from '../../core/graph';
|
||||
import { behaviorLookup } from '../../core/model/behaviorPrograms';
|
||||
import type { PropertyBag } from '../../core/model/Properties';
|
||||
import { findAsset, type Project } from '../../core/model/Project';
|
||||
import type { Entity } from '../Entity';
|
||||
@@ -78,7 +79,7 @@ export class BehaviorSystem implements System {
|
||||
const asset = findAsset(this.project, entity.assetId);
|
||||
if (!asset || asset.type !== 'behavior') continue;
|
||||
const trace: Trace = { edges: new Map(), nodes: new Map() };
|
||||
const interpreter = new GraphInterpreter(asset.graph);
|
||||
const interpreter = new GraphInterpreter(asset.graph, behaviorLookup(this.project));
|
||||
interpreter.trace = {
|
||||
onEdge: (id) => trace.edges.set(id, world.time),
|
||||
onNode: (id) => trace.nodes.set(id, world.time),
|
||||
@@ -153,14 +154,17 @@ export class BehaviorSystem implements System {
|
||||
return this.instances.map((i) => i.entity.objectId);
|
||||
}
|
||||
|
||||
/** Live highlight data for the graph editor: merged over all instances of the asset. */
|
||||
/**
|
||||
* Live highlight data for the graph editor: merged over all instances of the asset – and over
|
||||
* those that ran it as a node, which is the only way a nested behavior's graph ever lights up.
|
||||
*/
|
||||
traceFor(assetId: string): Trace {
|
||||
const merged: Trace = { edges: new Map(), nodes: new Map() };
|
||||
const latest = (into: Map<string, number>, from: Map<string, number>) => {
|
||||
for (const [id, t] of from) into.set(id, Math.max(t, into.get(id) ?? -Infinity));
|
||||
};
|
||||
for (const instance of this.instances) {
|
||||
if (instance.entity.assetId !== assetId) continue;
|
||||
if (instance.entity.assetId !== assetId && !instance.interpreter.calledBehaviors.has(assetId)) continue;
|
||||
latest(merged.edges, instance.trace.edges);
|
||||
latest(merged.nodes, instance.trace.nodes);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user