Unity3D项目的行为树。以代码驱动的方法编写,以最大限度地利用建筑商模式对大型项目的可维护性。灵感来自流利的行为树。
特征
支持
如果您有疑问或需要帮助,请加入Discord社区。
请参阅Trello Board的即将到来的功能和发展进度。
创建树时,您需要将它们存储在变量中以正确缓存所有必要的数据。
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Trees ;
public class MyCustomAi : MonoBehaviour {
[ SerializeField ]
private BehaviorTree _tree ;
private void Awake ( ) {
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Condition ( " Custom Condition " , ( ) => {
return true ;
} )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
}
private void Update ( ) {
// Update our tree every frame
_tree . Tick ( ) ;
}
}
根据您返回的任务状态的不同,将会发生不同的事情。
tree.Tick()
运行tree.Tick()
。树由树跟踪指针参考,只有在调用tree.Reset()
时才能清除。只要您的树存储变量设置为public
或具有SerializeField
属性属性。在编辑器中运行游戏时,您将能够打印树的可视化。请注意,游戏不运行时无法查看树。由于必须建造树才能可视化。
您可以用几行安全地将新代码添加到行为树中。允许您在支持未来版本升级的同时自定义BTS。
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Tasks . Actions ;
using CleverCrow . Fluid . BTs . Trees ;
public class CustomAction : ActionBase {
protected override TaskStatus OnUpdate ( ) {
Debug . Log ( Owner . name ) ;
return TaskStatus . Success ;
}
}
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomAction ( this BehaviorTreeBuilder builder , string name = " My Action " ) {
return builder . AddNode ( new CustomAction { Name = name } ) ;
}
}
public class ExampleUsage : MonoBehaviour {
public void Awake ( ) {
var bt = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. CustomAction ( )
. End ( ) ;
}
}
流体行为树通过Unity的软件包管理器使用。为了使用它,您需要将以下行添加到Packages/manifest.json
文件中。之后,您将能够视觉控制您在Unity的包装管理器窗口中使用哪种特定版本的流体行为树。必须这样做,以便您的Unity编辑器可以连接到NPM的软件包注册表。
{
"scopedRegistries" : [
{
"name" : " NPM " ,
"url" : " https://registry.npmjs.org " ,
"scopes" : [
" com.fluid "
]
}
],
"dependencies" : {
"com.fluid.behavior-tree" : " 2.2.0 "
}
}
特定版本和发行说明的档案可在“版本”页面上找到。
您可能想查看捕获的标志示例项目,以示出如何在项目中使用流体行为树。它展示了试图捕获国旗的单位的实时使用,同时抓住了力量,以尝试获得上风。
您可能想查看捕获的标志示例项目,以示出如何在项目中使用流体行为树。它展示了试图捕获国旗的单位的实时使用,同时抓住了力量,以尝试获得上风。
流体行为树带有强大的预制动作,条件,复合材料和其他节点的库,以帮助加快开发过程。
您可以即时创建通用动作。如果您发现自己重复使用相同的动作,则可能需要研究有关编写自己的自定义操作的部分。
. Sequence ( )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
在行为树上跳过许多壁虱。
. Sequence ( )
// Wait for 1 tick on the tree before continuing
. Wait ( 1 )
. Do ( MyAction )
. End ( )
等待,直到传递的秒数已在deltaTime
到期。
. Sequence ( )
. WaitTime ( 2.5f )
. Do ( MyAction )
. End ( )
您可以即时创建通用条件。如果您发现自己重复使用相同的动作,则可能需要研究编写自己的自定义条件的部分。
. Sequence ( )
. Condition ( " Custom Condtion " , ( ) => {
return true ;
} )
. Do ( MyAction )
. End ( )
根据传递的机会,随机评估节点为真或错误。
. Sequence ( )
// 50% chance this will return success
. RandomChance ( 1 , 2 )
. Do ( MyAction )
. End ( )
按顺序运行每个子节点,并期望成功的状态可以打勾下一个节点。如果返回失败,则该序列将停止执行子节点并将失败返回给父母。
请注意,重要的是,每个复合材料之后是.End()
语句。这可以确保在树上建造树时正确嵌套您的节点。
. Sequence ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. Do ( ( ) => { return TaskStatus . Success ; } )
// All tasks after this will not run and the sequence will exit
. Do ( ( ) => { return TaskStatus . Failure ; } )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
运行每个孩子节点直到返回成功。
. Selector ( )
// Runs but fails
. Do ( ( ) => { return TaskStatus . Failure ; } )
// Will stop here since the node returns success
. Do ( ( ) => { return TaskStatus . Success ; } )
// Does not run
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
随机选择带有洗牌算法的子节点。看起来直到返回Success
或每个节点失败为止。每当树最初开始运行它时,都会随时随地。
. SelectorRandom ( )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. Do ( ( ) => { return TaskStatus . Success ; } )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. End ( )
同时运行所有子节点,直到他们都回来成功。退出并停止所有运行节点,如果其中任何一个返回失败。
. Parallel ( )
// Both of these tasks will run every frame
. Do ( ( ) => { return TaskStatus . Continue ; } )
. Do ( ( ) => { return TaskStatus . Continue ; } )
. End ( )
装饰器是包装任何节点以更改返回值(或执行特殊逻辑)的母元素。它们非常强大,对动作,条件和复合材料非常有利。
您可以用自己的自定义装饰器代码包装任何节点。这使您可以自定义可重复使用的功能。
注意:您必须在子节点上手动调用Update()
,否则不会发射。另外,每个装饰符都必须随后进行.End()
语句。否则,树将无法正确构建。
. Sequence ( )
. Decorator ( " Return Success " , child => {
child . Update ( ) ;
return TaskStatus . Success ;
} )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. End ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
如果是TaskStatus.Success
或TaskStatus.Failure
,则将返回的子节点的返回状态逆转。不更改TaskStatus.Continue
。
. Sequence ( )
. Inverter ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
如果孩子返回TaskStatus.Success
,请返回TaskStatus.Failure
。不更改TaskStatus.Continue
。
. Sequence ( )
. ReturnSuccess ( )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. End ( )
. End ( )
如果孩子返回TaskStatus.Failure
,请返回TaskStatus.Success
。不更改TaskStatus.Continue
。
. Sequence ( )
. ReturnFailure ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
返回TaskStatus.Continue
,无论孩子返回什么状态。该装饰器(以及所有后代任务)可以通过呼叫BehaviorTree.Reset()
中断。
. Sequence ( )
. RepeatForever ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
返回TaskStatus.Failure
如果孩子返回TaskStatus.Failure
,否则返回TaskStatus.Continue
。
. Sequence ( )
. RepeatUntilFailure ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
返回TaskStatus.Success
如果孩子返回TaskStatus.Success
,否则返回TaskStatus.Continue
。
. Sequence ( )
. RepeatUntilSuccess ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
树只能与几行代码结合使用。这使您可以创建可注射的行为树,这些树将不同的节点捆绑在一起,以获得复杂功能,例如搜索或攻击。
请注意,剪接的树需要一棵新建的树进行注射,因为节点仅在.Build()
上深处复制。
using CleverCrow . Fluid . BTs . Trees ;
using CleverCrow . Fluid . BTs . Tasks ;
using UnityEngine ;
public class MyCustomAi : MonoBehaviour {
private BehaviorTree _tree ;
private void Awake ( ) {
var injectTree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( ) ;
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Splice ( injectTree . Build ( ) )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
}
private void Update ( ) {
// Update our tree every frame
_tree . Tick ( ) ;
}
}
使流体行为树如此强大的原因是能够编写自己的节点并将其添加到构建器中而无需编辑任何来源。您甚至可以创建添加新构建器功能的Unity软件包。例如,我们可以编写一个新的树木建筑商方法,该方法仅使用几行代码来设置AI系统的目标。
var tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. AgentDestination ( " Find Enemy " , target )
. Do ( ( ) => {
// Activate chase enemy code
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
创建您的第一个自定义操作并实施大约需要3分钟。首先创建一个新动作。
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Tasks . Actions ;
using UnityEngine ;
using UnityEngine . AI ;
public class AgentDestination : ActionBase {
private NavMeshAgent _agent ;
public Transform target ;
protected override void OnInit ( ) {
_agent = Owner . GetComponent < NavMeshAgent > ( ) ;
}
protected override TaskStatus OnUpdate ( ) {
_agent . SetDestination ( target . position ) ;
return TaskStatus . Success ;
}
}
接下来,我们需要使用我们的新代理操作扩展BehaviorTreeBuilder
脚本。有关C#类扩展的更多信息,请参见官方文档。
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder AgentDestination ( this BehaviorTreeBuilder builder , string name , Transform target ) {
return builder . AddNode ( new AgentDestination {
Name = name ,
target = target ,
} ) ;
}
}
你完成了!现在,您已经创建了一个自定义操作和可扩展的行为树建造器,该制造商将来对新版本进行了证明。以下示例将更加相同。但是每个都涵盖了不同的节点类型。
您可以使用以下模板创建自己的自定义操作。这对于捆绑您不断使用的代码很有用。
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Tasks . Actions ;
public class CustomAction : ActionBase {
// Triggers only the first time this node is run (great for caching data)
protected override void OnInit ( ) {
}
// Triggers every time this node starts running. Does not trigger if TaskStatus.Continue was last returned by this node
protected override void OnStart ( ) {
}
// Triggers every time `Tick()` is called on the tree and this node is run
protected override TaskStatus OnUpdate ( ) {
// Points to the GameObject of whoever owns the behavior tree
Debug . Log ( Owner . name ) ;
return TaskStatus . Success ;
}
// Triggers whenever this node exits after running
protected override void OnExit ( ) {
}
}
将您的新节点添加到扩展名中。
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomAction ( this BehaviorTreeBuilder builder , string name = " My Action " ) {
return builder . AddNode ( new CustomAction {
Name = name ,
} ) ;
}
}
可以使用以下示例模板添加自定义条件。如果AI可以移动到位置以及其他需要复杂检查的任务,您将需要使用这些检查,例如视力。
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
public class CustomCondition : ConditionBase {
// Triggers only the first time this node is run (great for caching data)
protected override void OnInit ( ) {
}
// Triggers every time this node starts running. Does not trigger if TaskStatus.Continue was last returned by this node
protected override void OnStart ( ) {
}
// Triggers every time `Tick()` is called on the tree and this node is run
protected override bool OnUpdate ( ) {
// Points to the GameObject of whoever owns the behavior tree
Debug . Log ( Owner . name ) ;
return true ;
}
// Triggers whenever this node exits after running
protected override void OnExit ( ) {
}
}
将新条件添加到您的行为树建造器中,并在以下片段中添加。
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomCondition ( this BehaviorTreeBuilder builder , string name = " My Condition " ) {
return builder . AddNode ( new CustomCondition {
Name = name ,
} ) ;
}
}
流体行为树不仅限于自定义动作和条件。您可以使用相当简单的API创建新的复合类型。这是基本序列的示例。
using CleverCrow . Fluid . BTs . TaskParents . Composites ;
using CleverCrow . Fluid . BTs . Tasks ;
public class CustomSequence : CompositeBase {
protected override TaskStatus OnUpdate ( ) {
for ( var i = ChildIndex ; i < Children . Count ; i ++ ) {
var child = Children [ ChildIndex ] ;
var status = child . Update ( ) ;
if ( status != TaskStatus . Success ) {
return status ;
}
ChildIndex ++ ;
}
return TaskStatus . Success ;
}
}
将自定义复合材料添加到行为树中与添加动作一样简单。只需采用一行代码即可。
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomSequence ( this BehaviorTreeBuilder builder , string name = " My Sequence " ) {
return builder . ParentTask < CustomSequence > ( name ) ;
}
}
还可以定制装饰器来减少重复代码。
using CleverCrow . Fluid . BTs . Decorators ;
using CleverCrow . Fluid . BTs . Tasks ;
public class CustomInverter : DecoratorBase {
protected override TaskStatus OnUpdate ( ) {
if ( Child == null ) {
return TaskStatus . Success ;
}
var childStatus = Child . Update ( ) ;
var status = childStatus ;
switch ( childStatus ) {
case TaskStatus . Success :
status = TaskStatus . Failure ;
break ;
case TaskStatus . Failure :
status = TaskStatus . Success ;
break ;
}
return status ;
}
}
实施装饰器类似于复合材料。如果您需要在复合材料上设置参数,则需要在Method BehaviorTreeBuilder.AddNodeWithPointer()
上进行战利品。
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomInverter ( this BehaviorTreeBuilder builder , string name = " My Inverter " ) {
// See BehaviorTreeBuilder.AddNodeWithPointer() if you need to set custom composite data from arguments
return builder . ParentTask < CustomInverter > ( name ) ;
}
}
如果您使用的是自动格式化器,则可能会使用构建器语法来处理您的代码格式。为了避免这种情况,您可以在Jetbrains Rider中关闭格式。如果您需要特定的IDE,则不难搜索您需要的特定格式禁用评论。
// @formatter:off
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Condition ( " Custom Condition " , ( ) => {
return true ;
} )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
// @formatter:on
要访问“包裹经理”友好的夜间开发develop
,您需要手动编辑Packages/manifest.json
。
{
"dependencies" : {
"com.fluid.behavior-tree" : " https://github.com/ashblue/fluid-behavior-tree.git#nightly "
}
}
请注意,要获得较新的夜间构建,您必须删除这一行和清单中的任何相关锁定数据,让Unity重建,然后将其添加回。当Unity锁定git URL的提交哈希作为软件包。
如果您想运行开发环境,则需要安装Node.js。然后一次从根中运行以下内容。
npm install
如果您想从根部创建构建运行npm run build
,它将填充dist
文件夹。
所有提交都应使用commitizen(运行npm install
时自动安装)进行。发行时将提交自动编译为版本号,因此非常重要。没有基于犯罪的提交的PR将被拒绝。
将提交类型从根部从根部开始到终端
npm run commit
请参阅贡献指南文件以获取更多信息。
谢谢这些好人(表情符号钥匙):
灰蓝 | 杰西·塔拉维拉·格林伯格(Jesse Talavera-Greenberg) | 纯化的生产 ? | 马丁·杜弗利(Martin Duvergey) ? | 呼叫堆 ? | piotr jastrzebski | Sounghoo |
tnthomas ? | Ownez | angstr0m ? | Izzy ? | 杰里米万克 |
该项目遵循全企业规范。欢迎任何形式的贡献!
谢谢这些好人(表情符号钥匙):
该项目遵循全企业规范。欢迎任何形式的贡献!