Behavior Graphs

Getting more out of AI with Visual Scripting

Sure, there are lots of awesome paid behavior editors on the Asset Store, but I haven't really enjoyed working in any of them. I've tried PlayMaker, Bolt and Node Canvas and while they are great at first, they all have limitations.

Worse, I make a lot of decisions based on open source game jams, so getting used to some closed source tools makes working in gamejams more complicated. My love for Odin Inspector, for example, often is problematic because I can't use them when open sourcing my project.

It's why I was excited to learn about xNode a completely open soure implementation. I wanted to try it out by rewriting my basic AI Path Follower driver using a StateGraph.

I think the part that is most difficult for a lot of these scripting languages for me is that what I'm primarily interested in is the GUI. I want the graph portion of it to be as flexible as possible

For example, take two common visual scripting tasks:

  • Shader Editor
  • State Machine

In a Shader Editor, you are interested in using the nodes to describe a calculation into several discrete steps, but you want to execute this graph once, and capture the output each time the graph is run. In this mode, the final result of the graph is the important result.

In a state machine, each node represents a particular state of the system. There is no final result, but rather the update of each node is what matters. (Spoiler alert: this is what I built.)

Some things are good at one or the other, but most don't do both. The ones that do, rarely handle it the way I would like, (for example: nesting graphs, or handling custom logic on/for transitions).

The most exciting thing about xNode is the open source permissive licensing. This means I can put it in my core libraries and use it even when doing open source game jamming (horray!) It also means I can take the pieces I like or need (like the Editor GUI) and rewrite the pieces I don't. Unlike some of the other libraries (even the source included ones), xNode is extremely easy to read, and as simple as I would expect a system like this.

xNode Evaluation

Their code revolves around two basic classes (A node and a graph, as expected), and the editors for them. Each node contains a port list which can be explicitly declared using attributes ([Input] and [Output] respectively) with the additional caveat that they need to be default serializable.

Alternatively you can use a fairly basic API for adding DynamicPorts and handling the conversion to and from a generic object class as required. Both modes require only a handful of lines of code.

Below is a complete source listing for a SeekPath class, which takes a target as a Vector3, starts calculating a path to that location from the current position, waits until that completes, then publishes the resulting path as an output of this node.