The Constraint node acts an interrupt: if the constraint expression ever becomes false while it is running any of the child nodes it will stop them and return failure. It also acts as a guard: ensuring that the constraint expression is true before allowing child nodes to run.
Most of the time, only a single node is used within a Constraint, but it can have more than one child and will behave the same way a Sequencer does as long as its constraint expression is true.
Many options on a behavior tree contain expression fields, which allow you to enter an expression instead of a constant value. For instance, an expression field for a target will often take the name of a Navigation Target, a Transform, a GameObject, or Vector3, and an expression allows you to use any of these.
Expression fields will highlight red if there is an error in the expression. For longer expressions it can be easier if you copy the field out into a larger editor.
See Expressions for more information.
Aside from the Never option, repeating has three states it can be in, and is available on most nodes in the behavior tree.
Until Success will cause a node to repeat until it returns Success. This can be used for several purposes: waiting for a Detect to succeed, waiting for a particular Mecanim State to occur, waiting for an Expression to be true, etc.
Until Failure will cause a node to repeat until it returns Failure. Essentially this is used for the same things that Until Success is used for. For instance, if an AI was waiting to detect the player before following them, once they started following you could use another Detect, this one repeating until failure, to determine when the AI has lost the player.
Forever will cause a node to always return Running. Much like its name implies, once this node starts it will continue to run forever. A very common setup for this is in a Parallel, where one node repeats forever and the other one eventually returns Failure or Success. A Constraint is also useful for interrupting a node that is repeating forever.
The most common use for a Constraint is when you need to interrupt a particular action that is going to continue running for some undefined period of time. For instance, if I have a Jester that I want to dance as long as music is playing I could construct the following tree:
The “dance and bow” Sequencer is going to repeat forever, so the only thing that keeps the Jester from dancing forever is the Constraint that is continuously checking whether the music is playing or not.
Variables are a very useful part of expressions, but are probably the number one pitfall for three reasons:
This means if you misspell or incorrectly capitalize your variable, it will treat it as an unassigned new variable and not raise an error of any kind. Keeping your variables names short, concise, and easy to spell will keep this from being too much of a problem.
Another problem this can cause is if you intend to use a string but forget the quotes. If it is a multiple word string it will highlight red, which makes it easy to catch, but if it is a single word string it will be considered a variable instead.
Talk about interrupting too high which doesn't allow you to account for transitions.
Talk about using evaluate expression to check a value, vs using a constraint around the whole thing.