Behavior Designer---创建一个发现,追踪,攻击目标的行为树

最近项目可能需要用到一些简单的AI,就看了下Behavior Designer的使用,记录一下。

这里做了一个敌人发现目标,并且追击攻击目标的行为树,其中包括视野范围,是否有障碍物等

行为树的节点介绍可以看这里:

Action行为动作节点

Composites复合任务节点

Conditionals条件任务节点

Decorators装饰任务节点

下面是我制作的行为树:

Behavior Designer---创建一个发现,追踪,攻击目标的行为树_第1张图片

行为树挂在一个Cube上面:

Behavior Designer---创建一个发现,追踪,攻击目标的行为树_第2张图片

先看下效果:

Behavior Designer---创建一个发现,追踪,攻击目标的行为树_第3张图片

首先是视野范围用的是上篇讲到的四元数右乘,LineRenderer画线,就不做赘述了。代码:

using UnityEngine;

public class CubeViewDrawLine : MonoBehaviour
{

    private LineRenderer lineLeft;
    private LineRenderer lineRight;
    private Vector3 leftLineEndPoint;
    private Vector3 rightLinEndPoint;

    private void Start()
    {
        CreateLine(ref lineLeft, "LeftLine");
        CreateLine(ref lineRight, "RightLine");
    }

    private void Update()
    {
        GetLineEndPoint(leftLineEndPoint, lineLeft, -40);
        GetLineEndPoint(rightLinEndPoint, lineRight, 40);
    }

    /// 
    /// 获取范围的两个终点,并画线
    /// 
    /// 
    /// 
    /// 
    public void GetLineEndPoint(Vector3 v, LineRenderer line, float angle)
    {
        v = (Quaternion.Euler(0, angle, 0) * transform.forward) * 10 + transform.position;
        line.SetPosition(0, transform.position);
        line.SetPosition(1, v);
    }

    /// 
    ///创建LineRenedere并且赋值设置属性,需要传递引用
    /// 
    /// 
    /// 
    public void CreateLine(ref LineRenderer line, string name)
    {
        GameObject go = new GameObject();
        go.name = name;
        line = go.AddComponent();
        line.sharedMaterial = Resources.Load("Line");
        line.startWidth = 0.1f;
        line.endWidth = 0.1f;
        line.material.color = Color.red;
    }
}

上面的Conditions条件节点和aAction行为节点都是手动创建的,代码如下:

using UnityEngine;
using BehaviorDesigner.Runtime.Tasks;
using BehaviorDesigner.Runtime;

/// 
/// 创建检测距离的条件节点
/// 
public class CheckDistance : Conditional
{
    public SharedFloat Distance;
    public SharedTransform Target;

    public override TaskStatus OnUpdate()
    {
        if (Vector3.Distance(transform.position, Target.Value.position) <= Distance.Value)
        {
            return TaskStatus.Success;
        }
        return TaskStatus.Running;
    }
}

/// 
/// 创建检测视野范围的条件节点
/// 
public class CheckView : Conditional
{

    public SharedTransform Target;
    public SharedFloat Angle;

    public override TaskStatus OnUpdate()
    {
        float tempAngle = Vector3.Angle(transform.forward, Target.Value.position - transform.position);
        if (tempAngle < (Angle.Value / 2f))//目标和自身正前方的夹角小于视野范围的一般就认为在视野范围内
        {
            return TaskStatus.Success;
        }
        return TaskStatus.Running;
    }
}

/// 
/// 创建检测目标的条件节点
/// 
public class CheckTag : Conditional
{

    public SharedString PlayerTag;
    public SharedTransform Target;
    public SharedBool RayHitPlayer;//是否检测到目标

    public override void OnStart()
    {
        transform.LookAt(Target.Value.position);//第一进入视野范围就看向目标
    }

    public override TaskStatus OnUpdate()
    {
        if(RayHitPlayer.Value)//如果检测到目标就看向目标
        {
            transform.LookAt(Target.Value.position);
        }       
        Ray ray = new Ray(transform.position, transform.forward);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 20))
        {
            if (hit.collider.tag == (string)PlayerTag.GetValue())//射线检测到目标
            {
                RayHitPlayer.SetValue(true);
                return TaskStatus.Success;
            }
            else//检测到的不是目标
            {
                RayHitPlayer.SetValue(false);
                return TaskStatus.Running;
            }

        }
        else//射线什么也没检测到那么也默认为检测到目标,因为在这个节点里面,此时目标肯定是在视野范围内的并且没有被障碍物遮挡视野
        {
            RayHitPlayer.SetValue(true);
        }        
        return TaskStatus.Running;
    }

}

/// 
/// 创建目标移动的事件节点
/// 
public class MoveToTarget : Action
{
    public SharedTransform Target;
   
    public override TaskStatus OnUpdate()
    {
        if (Vector3.Distance(transform.position, Target.Value.position) <= 1f)//表示已经移动到目标身边
        {
            return TaskStatus.Success;

        }
        else if (Vector3.Distance(transform.position, Target.Value.position) <= 10)//判断是目标的距离
        {
            transform.position = Vector3.MoveTowards(transform.position, Target.Value.position, 1.5f * Time.deltaTime);
        }
        else//超过距离认为目标逃离,那么返回失败
        {
            return TaskStatus.Failure;
        }
       
        return TaskStatus.Running;
    }
}

/// 
/// 创建检测攻击距离的条件节点
/// 
public class CheckAttackDistance:Conditional
{
    public SharedTransform Target;
    public override TaskStatus OnUpdate()
    {
        if (Vector3.Distance(transform.position, Target.Value.position) <= 1)
        {
            return TaskStatus.Success;
        }
        else
        {
            return TaskStatus.Failure;
        }
    }
}

/// 
/// 创建攻击目标的事件节点
/// 
public class AttackTarget : Action
{
    public SharedTransform Target;

    public override TaskStatus OnUpdate()
    {
        if (Target.Value.localScale.x <= 0.1f)
        {
            return TaskStatus.Success;
        }
        else 
        {
            Target.Value.localScale -= Vector3.one * 0.2f * Time.deltaTime;
        }           
        return TaskStatus.Running;
    }
}

然后我们添加对应的节点并进行设置,首先点击箭头位置,添加代码里面需要的参数并复制:

Behavior Designer---创建一个发现,追踪,攻击目标的行为树_第4张图片

然后节点的设置:

Behavior Designer---创建一个发现,追踪,攻击目标的行为树_第5张图片

我们点击对应的节点,在Inspector面板,点击参数后面的小圆点,选择对应的参数即可,类似的节点都是这种操作

最后我们需要对Composites复合节点进行打断设置,打断机制的说明请移步这里:节点打断

这里做一个简单的说明:

Behavior Designer---创建一个发现,追踪,攻击目标的行为树_第6张图片

首先设置打断机制。我这个设置的是可以打断自身和比自己优先级低的。

优先级是从左到右的顺序执行,并且是深度优先,上图已经数字代码执行顺序。

比如上面的3,4,5,6条件,当在执行5条件时,如果检测到距离超出检测距离就会直接打断5跳到3条件重新进行检测,然后3条件完成在执行4条件,同样的,如果在执行6的事件,判断超出距离也会打断6.跳到3重新执行.

具体怎么设置得看逻辑和需求来,到这里就完成了

你可能感兴趣的:(Behavior,Designer,Behavior,Designer,范围检测)