C#/Unity 行为树 简单实现

孙广东   2018.7.25    

          行为树的概念, 各种 Unity 插件 都没时间介绍。 代码是看了 Unity的 2D Game Kit , 提炼出来,测试!   对于学习和理解行为树会很有帮助!!!   纯代码, 没有Unity插件的节点编辑导出配置等内容。 

using BTAI;
using UnityEngine;

public class TestBT : MonoBehaviour, BTAI.IBTDebugable
{
    Root aiRoot = BT.Root();


    private void OnEnable()
    {
        aiRoot.OpenBranch(
                BT.If(TestVisibleTarget).OpenBranch(
                BT.Call(Aim),
                BT.Call(Shoot)
                 ),
                BT.Sequence().OpenBranch(
                BT.Call(Walk),
                BT.Wait(5.0f),
                BT.Call(Turn),
                BT.Wait(1.0f),
                BT.Call(Turn)
             )
        );
    }

    private void Turn()
    {
        Debug.Log("执行了 Turn");
    }

    private void Walk()
    {
        Debug.Log("执行了 Walk");
    }

    private void Shoot()
    {
        Debug.Log("执行了 Shoot");
    }

    private void Aim()
    {
        Debug.Log("执行了 Aim");
    }

    private bool TestVisibleTarget()
    {
        var isSuccess = UnityEngine.Random.Range(0, 2) == 1;
        Debug.Log("执行了 TestVisibleTarget    Result:" + isSuccess);

        return isSuccess;
    }

    private void Update()
    {
        aiRoot.Tick();
    }

    public Root GetAIRoot()
    {
        return aiRoot;
    }
}

using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 这只是脚本系统
/// 行为树会从Root节点开始遍历子节点。Update中执行
/// 每个节点都有相关的操作,但是基本上就是返回三种状态
/// ● Success​: 节点成功完成任务
/// ● Failure​: 节点未通过任务
/// ● Continue​:节点尚未完成任务。
/// 但是每个节点的父节点对子节点的结果处理方式还不同。  例如
/// ● Test 节点: 测试节点将调用其子节点并在测试为真时返回子节点状态,如果测试为假,则返回Failure而不调用其子节点。
/// 行为树的一种构造方式如下:
/// Root aiRoot = BT.Root(); 
/// aiRoot.Do(  
/// BT.If(TestVisibleTarget).Do(
///  BT.Call(Aim),
///  BT.Call(Shoot)
///  ),
///  BT.Sequence().Do(
///  BT.Call(Walk),
///  BT.Wait(5.0f),
///  BT.Call(Turn),
///  BT.Wait(1.0f),
///  BT.Call(Turn)
///  )
/// ); 
///然后在Update中 调用   ​aiRoot.Tick()​ 。  刚刚构造的行为树是怎么样的检查过程呢?  
///1、首先检查TestVisibleTarget是否返回Ture,如果是继续执行子节点执行Aim函数和Shoot函数
///2、TestVisibleTarget是否返回false,if节点将返回Failure, 然后Root 将转向下一个子节点。这是个Sequence节点,它从执行第一个子节点开始。
///   1)将调用Walk函数,直接返回 Success,以便Sequence将下一个子节点激活并执行它。
///   2)执行Wait 节点,只是要等待5秒,还是第一次调用,所以肯定返回Running状态, 当Sequence从子节点上得到Running状态时,不会更改激活的子节点索引,下次Update的时候还是从这个节点开始执行
///3、Update的执行,当Wait节点等待的时间到了的时候,将会返回Success, 以便序列将转到下一个孩子。
///脚本中的Node列表 
/// Sequence:
//一个接一个地执行子节点。如果子节点返回:
//●Success:Sequence将选择下一帧的下一个孩子开始。
//●Failure:Sequence将返回到下一帧的第一个子节点(从头开始)。
//●Continue:Sequence将在下一帧再次调用该节点。
//RandomSequence:
// 每次调用时,从子列表中执行一个随机子节点。您可以在构造函数中指定要应用于每个子项的权重列表作为int数组,以使某些子项更有可能被选中。
//Selector :
//按顺序执行所有子项,直到一个返回Success,然后退出而不执行其余子节点。如果没有返回Success,则此节点将返回Failure。

// Condition :
// 如果给定函数返回true,则此节点返回Success;如果为false,则返回Failure。
// 与其他依赖于子节点结果的节点链接时很有用(例如,Sequence,Selector等)
// If :
//调用给定的函数。
// ●如果返回true,则调用当前活动的子级并返回其状态。
// ●否则,它将在不调用其子项的情况下返回Failure
// While:
//只要给定函数返回true,就返回Continue(因此,下一帧将再次从该节点开始,而不会评估所有先前的节点)。
//子节点们将陆续被执行。
//当函数返回false并且循环中断时,将返回Failure。
// Call 
//调用给定的函数,它将始终返回Success。是动作节点!
//Repeat 
//将连续执行给定次数的所有子节点。
//始终返回Continue,直到达到计数,并返回Success。
//Wait
//将返回Continue,直到达到给定时间(首次调用时开始),然后返回Success。
//Trigger 
//允许在给定的动画师animator中设置Trigger参数(如果最后一个参数设置为false,则取消设置触发器)。始终返回成功。
//SetBool
//允许在给定的animator中设置布尔参数的值。始终返回成功
//SetActive 
//设置给定GameObject的活动/非活动状态。始终返回成功。
/// </summary>
namespace BTAI
{
    public enum BTState
    {
        Failure,
        Success,
        Continue,
        Abort
    }

    /// <summary>
    /// 节点 对象工厂
    /// </summary>
    public static class BT
    {
        public static Root Root() { return new Root(); }
        public static Sequence Sequence() { return new Sequence(); }
        public static Selector Selector(bool shuffle = false) { return new Selector(shuffle); }
        public static Action RunCoroutine(System.Func<IEnumerator<BTState>> coroutine) { return new Action(coroutine); }
        public static Action Call(System.Action fn) { return new Action(fn); }
        public static ConditionalBranch If(System.Func<bool> fn) { return new ConditionalBranch(fn); }
        public static While While(System.Func<bool> fn) { return new While(fn); }
        public static Condition Condition(System.Func<bool> fn) { return new Condition(fn); }
        public static Repeat Repeat(int count) { return new Repeat(count); }
        public static Wait Wait(float seconds) { return new Wait(seconds); }
        public static Trigger Trigger(Animator animator, string name, bool set = true) { return new Trigger(animator, name, set); }
        public static WaitForAnimatorState WaitForAnimatorState(Animator animator, string name, int layer = 0) { return new WaitForAnimatorState(animator, name, layer); }
        public static SetBool SetBool(Animator animator, string name, bool value) { return new SetBool(animator, name, value); }
        public static SetActive SetActive(GameObject gameObject, bo
  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值