This document contains notice for using and extending nodes, SharedVariables and attributes.
- Behavior Node Type
- Built In Composite Node
- Create New Behaviors
- Attributes
- BehaviorTree Builder
- SharedVariable
| Name | Description |
|---|---|
| Composite Node | It has one or more child nodes and controls which child node to update. |
| Action Node | This is the leaf node. It execute action such as follow player, attack, escape or others you define. |
| Conditional Node | It has one child node and check the condition whether child is updatable. when having no child, Conditional Node is the leaf node like Action Node. |
| Decorator Node | It has one child node and will modify the return value according to the return value of the child node |
I have prepared several built in Composite Node.
- Updates the child nodes in order from the top.
- Returns failure immediately if the child node returns failure.
- Returns running immediately and calls the child at the next update timing if the child node returns running.
- Returns success if all child nodes return success.
Sequence has following parameter.
| Name | Description |
|---|---|
| abortOnConditionChanged | true: Aborts the running node when a node with a higher priority than the running node becomes infeasible. Specifically, the execution result of Conditional.CanUpdate, which is a descendant of a node with a higher priority than the running node, is used. |
- Updates the child nodes in order from the top.
- Returns success immediately if the child node returns success.
- Returns running immediately and calls the child at the next update timing if the child node returns running.
- Returns failure if all child nodes return failure.
Selector has following parameter.
| Name | Description |
|---|---|
| abortOnConditionChanged | true: Aborts the running node when a node with a higher priority than the running node becomes executable. Specifically, the execution result of Conditional.CanUpdate, which is a descendant of a node with a higher priority than the running node, is used. |
- Updates all child nodes.
- Returns running if any child node returns running.
- Returns failure if any child node returns failure.
- Otherwise, returns success.
- The child nodes are elected and executed according to the probability based on the uniform distribution.
- Select one for each update. However, if the running status is returned during the last update, the node will continue to run.
- Updates the child nodes in order. Unlike Sequencer, one child node is executed by one update instead of executing all child nodes by one update.
- For example, if there are three child nodes, the first Update will execute the top node, the next Update will execute the second node, and the next Update will execute the third node.
- The next run will run the top node again.
- If a child node returns a running state, it exits without executing subsequent child nodes, and the child node continues to run on the next update.
Rotator has following parameter.
| Name | Description |
|---|---|
| resetOnAbort | It is a flag whether to return the next execution target node from the top when the execution condition of the ancestor Conditional Node changes and the running node is interrupted. |
- Create C# Script and extends
AkiBT.Action - Override
OnUpdateand return status(Success/Running/Failure). - Override
Awakecalled byAkiBT.BehaviorTree.Awakeif needed. - Override
Startcalled byAkiBT.BehaviorTree.Startif needed. - Override
Abortto reset field or any state when the parent condition changed.. - Action has Node
gameObjectfield withAkiBT.BehaviorTreeattached. - Private [SerializeField] field and public field can be set on Behavior Tree editor window.
public class Wait : Action
{
[SerializeField]
private float waitTime;
private float elapsedTime = 0.0f;
protected override Status OnUpdate()
{
elapsedTime += Time.deltaTime;
if (elapsedTime < waitTime)
{
return Status.Running;
}
elapsedTime = 0.0f;
return Status.Success;
}
// abort when the parent conditional changed on previous status is running.
public override void Abort()
{
elapsedTime = 0.0f;
}
}- Create C# Script and extends
AkiBT.Conditional - Override
IsUpdatableand return result(true/false). whenIsUpdatablereturns update child. - Override
OnAwakecalled byAkiBT.BehaviorTree.Awakeif needed. - Override
OnStartcalled byAkiBT.BehaviorTree.Startif needed. - Conditional Node has
gameObjectfield withAkiBT.BehaviorTreeattached. - Private
[SerializeField]field and public field can be set on Behavior Tree editor window.
| Name | Description |
|---|---|
| evaluateOnRunning | true : evaluate the condition if the previous status is Status.Running. |
public class IsHateGt: Conditional
{
[SerializeField]
private int threshold;
private Enemy enemy;
protected override void OnAwake()
{
enemy = gameObject.GetComponent<Enemy>();
}
protected override bool IsUpdatable()
{
return enemy.Hate > threshold;
}
}- Conditional Node can be leaf node like Action Node.
- Conditional Node can be branch node.
- Create C# Script and extends
AkiBT.Composite - Override
OnUpdateand return status(Success/Running/Failure). - Override
OnAwakecalled byAkiBT.BehaviorTree.Awakeif needed. - Override
OnStartcalled byAkiBT.BehaviorTree.Startif needed. - To abort the running node when the condition changed override
Abort. - Composite Node has
gameObjectfield withAkiBT.BehaviorTreeattached. - Private [SerializeField] field and public field can be set on Behavior Tree editor window.
[AkiInfo("Composite : Random, random update a child and reselect the next node")]
public class Random : Composite
{
private NodeBehavior runningNode;
protected override Status OnUpdate()
{
// proceed to update same node when the previous status is running
if (runningNode != null)
{
return HandleStatus(runningNode.Update(), runningNode);
}
// update random children
var result = UnityEngine.Random.Range(0, Children.Count);
var target = Children[result];
return HandleStatus(target.Update(), target);
}
private Status HandleStatus(Status status, NodeBehavior updated)
{
//save running node for next update.
runningNode = status == Status.Running ? updated : null;
return status;
}
// abort when the parent conditional changed on previous status is running.
public override void Abort()
{
if (runningNode != null)
{
runningNode.Abort();
runningNode = null;
}
}
}- Decorator node is used to modify the return value and reduce the number of Conditional or Composite nodes used
- Create C# Script and extends
AkiBT.Decorator - Override
OnDecorate(Status childStatus)to modify the return value according to the return value of the child node. - Decorator inherits the
CanUpdateof the child node, that is, if the child node is Conditional, the node will inherit its judgment value. If you want to modifyCanUpdate, you can overrideOnDecorate(bool childCanUpdate) - Override
OnAwakecalled byAkiBT.BehaviorTree.Awakeif needed. - Override
OnStartcalled byAkiBT.BehaviorTree.Startif needed. - Composite Node has
gameObjectfield withAkiBT.BehaviorTreeattached. - Private [SerializeField] field and public field can be set on Behavior Tree editor window.
[AkiInfo("Decorator : If the child node returns Success, it is reversed to Failure," +
" if it is Failure, it is reversed to Success.")]
public class Invertor : Decorator
{
protected override Status OnDecorate(Status childeStatus)
{
if(childeStatus==Status.Success)
return Status.Failure;
else if(childeStatus==Status.Failure)
return Status.Success;
else
return childeStatus;
}
}AkiInfo用以描述结点行为
AkiInfo is used to describe the information of node.
[AkiInfo("Action : Stop NavmeshAgent according to isStopped")]
public class NavmeshStopAgent : Action
{
private NavMeshAgent _navMeshAgent;
}AkiLabel用以替换编辑器中的结点名称,新版本中你同样可以使用AkiLabel替换编辑器中的字段名称.
AkiLabel is added for replacing label of node's title or field especially for Chinese.
[AkiLabel("Navmesh : StopAgent")]
public class NavmeshStopAgent : Action
{
private NavMeshAgent _navMeshAgent;
[SerializeField,AkiLabel("Whether to stop")]
private SharedBool isStopped;
}AkiGroup用以对结点进行分类
AkiGroup is an advanced attribute to category node
[AkiGroup("Animator")]
public class AnimatorSetBool : AnimatorAction
{
}-
你可以使用
'/'符号进行子分类 -
You can also subcategory the SearchWindow by using
'/'.
ForceShared用以强制共享共享变量
ForceShared is used to force shared variables to be shared
public class SetFloat : Action
{
[SerializeField]
private float setValue;
//Force this variable to be shared
[SerializeField, ForceShared]
private SharedFloat floatToSet;
}WrapField用以显示UIElement不支持显示的对象,将使用IMGUI进行显示
WrapField is used to display objects that UIElement does not support display, and IMGUI will be used to display them.
public class InvokeUnityEvent : Action
{
//Use IMGUI to show UnityEvent
[SerializeField, WrapField]
private UnityEvent unityEvent;
}Use BehaviorTreeBuilder to build a behaviorTree on the builder pattern.
Use BeginChild to start writing child or children.
Use EndChild to end writing.
Use New{VariableType} to get a reference of SharedVariable, if not exist before, it will create new one.
// Example code
var builder = new BehaviorTreeBuilder(gameObject);
//Create and set value of local variable
builder.NewObject<NavMeshAgent>("NavAgent",navmeshAgent);
//Create and bind global variable
builder.NewFloat("Distance").IsGlobal = true;
bool success = builder.BeginChild(new Sequence() { abortOnConditionChanged = true })
.Append(new FloatComparison()
{
operation = FloatComparison.Operation.GreaterThan,
float1 = builder.NewFloat("Distance"),
float2 = new(4f)
})
.BeginChild()
.BeginChild(new Sequence())
.Append(new NavmeshSetDestination()
{
agent = builder.NewObject<NavMeshAgent>("NavAgent"),
destination = builder.NewVector3("EnemyPosition")
})
.Append(new SetBool()
{
boolValue = new(true),
storeResult = builder.NewBool("IsFollowing")
})
.EndChild()
.EndChild()
.BeginChild(new Sequence())
.Append(new SetBool()
{
boolValue = new(false),
storeResult = builder.NewBool("IsFollowing")
})
.EndChild(new NavmeshStopAgent()
{
agent = builder.NewObject<UnityEngine.AI.NavMeshAgent>("NavAgent"),
isStopped = new(true)
})
.EndChild()
.Build(out BehaviorTree behaviorTree);-
除了值类型外,你可以使用
SharedObject来共享任何继承自UnityEngine.Object类型的对象。如要限制类型可以使用SharedTObject<T>这样在编辑器中的下拉栏中你将只能引用具有相同类型的SharedObjectIn addition to value types, you can use
SharedObjectto share any object that inherits fromUnityEngine.Object. If you want to limit the type you can useSharedTObject<T>so that in the drop-down bar in the editor you will only be able to reference SharedObjects with the same type -
在黑板中,你可以通过创建
SharedObject并限制其类型来提升类型安全性并且使字段只能拖拽相应类型的对象。In the blackboard, you can create a
SharedObjectand restrict its type to improve type safety and make the field only drag and drop objects of the corresponding type.
-
Property Reference
Name Description IsGlobal Whether varible binding to global variables IsShared Whether varible is shared in behavior tree Name Variable's name, important for binding -
Method Reference
Name Description SetValue Set variable value GetValue Get variable value Bind Bind to other sharedVariable Unbind Unbind self Observe Create an observe proxy variable






