基于Unity行为树设计与实现的尝试

查阅了一些行为树资料,目前最主要是参考了这篇文章看完后感觉行为树实乃强大,绝对是替代状态机的不二之选。但从理论看起来很简单的行为树,真正着手起来却发现很多细节无从下手。


总结起来,就是:

1、行为树只是单纯的一棵决策树,还是决策+控制树。为了防止不必要的麻烦,我目前设计成单纯的决策树。

2、什么时候执行行为树的问题,也就是行为树的Tick问题,是在条件变化的时候执行一次,还是只要对象激活,就在Update里面一直Tick。前者明显很节省开销,但那样设计的最终结果可能是最后陷入事件发送的泥潭中。那么一直Tick可能是最简单的办法,于是就引下面出新的问题。目前采用了一直Tick的办法。

3、基本上可以明显节点有   Composite Node、 Decorator Node、 Condition Node、 Action Node,但具体细节就很头疼。比如组合节点里的Sequence Node。这个节点是不是在每个Tick周期都从头迭代一次子节点,还是记录正在运行的子节点。每次都迭代子节点,就感觉开销有点大。记录运行节点就会出现条件冗余问题,具体后面再讨论。目前采用保存当前运行节点的办法。

4、条件节点(Condition Node)的位置问题。看到很多设计都是条件节点在最后才进行判断,而实际上,如果把条件放在组合节点处,就可以有效短路判断,不再往下迭代。于是我就采用了这种方法。


设计开始

在Google Code上看到的某个行为树框架,用的是抽象类做节点。考虑到C#不能多继承,抽象类可能会导致某些时候会很棘手,所以还是用接口。虽然目前还未发现接口的好处。

在进行抽象设计的时候,接口的纯粹性虽然看起来更加清晰,不过有时候遇到需要重复使用某些类函数的时候就挺麻烦,让人感觉有点不利于复用。

public enum RunStatus
{
    Completed,
    Failure,
    Running,
}

public interface IBehaviourTreeNode
{
    RunStatus status { get; set; }
    string nodeName { get; set; }
    bool Enter(object input);
    bool Leave(object input);
    bool Tick(object input, object output);
    RenderableNode renderNode { get; set; }
    IBehaviourTreeNode parent { get; set; }
    IBehaviourTreeNode Clone();
}

/************************************************************************/
/* 组合结点                                                             */
/************************************************************************/
public interface ICompositeNode : IBehaviourTreeNode
{
    void AddNode(IBehaviourTreeNode node);
    void RemoveNode(IBehaviourTreeNode node);
    bool HasNode(IBehaviourTreeNode node);

    void AddCondition(IConditionNode node);
    void RemoveCondition(IConditionNode node);
    bool HasCondition(IConditionNode node);

    ArrayList nodeList { get; }
    ArrayList conditionList { get; }
}

/************************************************************************/
/* 选择节点                                                             */
/************************************************************************/
public interface ISelectorNode : ICompositeNode
{

}

/************************************************************************/
/*顺序节点                                                              */
/************************************************************************/
public interface ISequenceNode : ICompositeNode
{

}

/************************************************************************/
/* 平行(并列)节点                                                             */
/************************************************************************/
public interface IParallelNode : ICompositeNode
{

}

//

/************************************************************************/
/* 装饰结点                                                             */
/************************************************************************/
public interface IDecoratorNode : IBehaviourTreeNode
{

}

/************************************************************************/
/* 条件节点                                                             */
/************************************************************************/
public interface IConditionNode
{
    string nodeName { get; set; }
    bool ExternalCondition();
}

/************************************************************************/
/* 行为节点                                                             */
/************************************************************************/
public interface IActionNode : IBehaviourTreeNode
{

}

public interface IBehaviourTree
{
    
}

很多节点的接口都是空的,目前唯一的作用就是用于类型判断,很可能在最后也没有什么实际的作用,搞不好就是所谓的过度设计。如果最终确定没有用再删掉吧。

接口里出现了一个渲染节点,目的是为了能够更方便的把这个节点和负责渲染的节点联系到一起,方便节点的可视化。


如果只有接口,每次实现接口都要重复做很多工作,为了利用面向对象的复用特性,就来实现一些父类


public class BaseNode
{
    public BaseNode() { nodeName_ = this.GetTyp
### 创建和使用 Unity 行为树 #### 导入必要的工具包 为了在 Unity 中创建行为树,可以利用现有的插件简化开发过程。例如,NodeCanvas 是一种流行的选择[^1]。从 Unity Asset Store 下载并安装 NodeCanvas 插件至项目中。 #### 设计行为树架构 设计阶段涉及规划 AI 的决策路径。基于需求构建一棵由不同类型的节点组成的行为树,这些节点代表特定的动作或者判断条件[^3]。每条分支对应着不同的可能行动方案,而叶子节点则表示具体可执行的任务。 #### 实现行为树逻辑 一旦完成了初步的设计工作,在 Unity 编辑器里就可以着手建立实际的行为树实例了。对于采用传统方法的情况: - **创建新行为树**:右键点击场景视图或层级窗口中的 GameObject,选择 `Add Component` -> `NodeCanvas` 类目下找到合适的模板。 - **添加配置节点**:依据预先设定好的蓝图逐一加入相应的功能模块,并设置好各个属性值以及相互间的关联关系。 如果考虑更高效的 ECS 架构,则推荐尝试 EntitiesBT 这样的专门针对 DOTS 优化过的解决方案[^2]。这类库允许开发者编写更加贴近底层硬件特性的高性能代码片段,从而提升整体性能表现。 #### 测试及迭代改进 完成上述步骤之后便可以在模拟环境中运行程序观察效果;必要时返回修改参数直至达到满意的结果为止。 ```csharp // 示例 C# 脚本用于演示如何启动一个简单的 BehaviorTree 组件 using UnityEngine; using NodeCanvas.Framework; public class ExampleBehavior : MonoBehaviour { private BehaviourStatus status; void Start() { BTComponent btComp = GetComponent<BTComponent>(); if(btComp != null){ status = btComp.behaviour.Status; } } void Update(){ Debug.Log($"Current Status: {status}"); } } ```
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值