做一个简单敌人巡逻
导入资源后,直接添加一个Tasks-> Actions->Patrol行为树任务

然后进入Inspector设置参数


接下来我们再给我们的敌人添加导航的组件这样我们怪物的巡礼就完成了


会追击所看到的敌人
下面是设置行为树的执行关系

首先我们设置三个变量,一个是游戏对象的速度/旋转速度和所要追击敌人的Transform。


下面我们设置看到目标敌人后就需要去追击敌人。所以Target Transform就要设置敌人的Transform。






当离开了视野范围的时候就会朝着它原来的目标前进

自写Seek任务
直接让它继承自Action。
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MySeek : Action {
public float speed;
public SharedTransform target;
public float arriveDistance = 0.1f;
private float sqrArriveDistance;
public override void OnStart()
{
sqrArriveDistance = arriveDistance * arriveDistance;
}
//当进入到这个任务的时候,会一直调用这个方法,一直到任务结束 一返回一个 成功或者失败的状态
//那么认为结束 如果返回一个running的状态,那这个方法会继续被调用
public override TaskStatus OnUpdate()
{
if (target == null||target.Value==null) {
return TaskStatus.Failure;
}
transform.LookAt(target.Value.position);
transform.position = Vector3.MoveTowards(transform.position, target.Value.position, speed * Time.deltaTime);
if ((target.Value.position-transform.position).sqrMagnitude<sqrArriveDistance) {
return TaskStatus.Success;//如果距离目标位置的距离比较小,认为达到目标文字,直接Return成功
}
return TaskStatus.Running;
}
}
我们可以看到我们自己写的任务被Action 自动添加了进去

自写CanSeekObject任务
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//用来判断目标是否在视野内
public class MyCanSeeObject : Conditional {
public Transform[] targets;//判断是否在视野内的目标
public float fildOfViewAngle = 90;
public float viewDistance = 7;
//行为树局部Transform变量
public SharedTransform tagret;
public override TaskStatus OnUpdate()
{
if (targets==null) return TaskStatus.Failure;
foreach (var target in targets)
{
float distance = (target.position - transform.position).magnitude;
float angle = Vector3.Angle(transform.forward, target.position - transform.position);
if (distance<viewDistance&&angle< fildOfViewAngle*0.5f) {
this.tagret.Value = target;
return TaskStatus.Success;
}
}
return TaskStatus.Failure;
}
}

自写一个追击敌人的行为任务
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
//用来追敌人直到敌人跑出视野范围外面
public class Defend : Action{
public SharedFloat viewDistance;
public SharedFloat fieldOfViewAngle;
public SharedFloat Speed;
public SharedFloat AngularSpeed;
public SharedTransform target;//要防御的目标
private float sqrViewDistance;
private NavMeshAgent navmeshAgent;
public override void OnAwake()
{
navmeshAgent = GetComponent<NavMeshAgent>();
}
public override void OnStart()
{
sqrViewDistance = viewDistance.Value * viewDistance.Value;
navmeshAgent.enabled = true;
navmeshAgent.speed = Speed.Value;
navmeshAgent.angularSpeed = AngularSpeed.Value;
navmeshAgent.destination = target.Value.position;
}
public override void OnEnd()
{
navmeshAgent.enabled = false;
}
//如果抢夺者在视野内,就追,否则就认为防御成功
public override TaskStatus OnUpdate()
{
if (target==null&&target.Value==null) {
return TaskStatus.Failure;
}
float sqrDistance = (target.Value.position - transform.position).sqrMagnitude;
float angle = Vector3.Angle(transform.forward, target.Value.position - transform.position);
if (sqrDistance<sqrViewDistance&&angle<fieldOfViewAngle.Value*0.5f) {
if (navmeshAgent.destination!=target.Value.position) {
navmeshAgent.destination = target.Value.position;
}
return TaskStatus.Running;
}
return TaskStatus.Success;
}
}
行为树局部变量与全局变量

//行为树局部变量,后面必须.Value才能获取到(target.Value.position)
public SharedTransform target;
//行为树全局变量
public BehaviorTree behaviortree;
//设置与获取全局变量
behaviortree.SetVariable("MyVariable", target);
behaviortree.GetVariable("MyVariable");
某些任务的含义


多个行为树的使用
一个游戏对象可以使用多个行为树。可相互切换行为树的执行
private static CTFGameMenager _instance;
public static CTFGameMenager Instance {
get{
return _instance;
}
}
private List<BehaviorTree> flagNotTakenBehaviorTrees=new List<BehaviorTree>();
private List<BehaviorTree> flagTakenBehaviorTrees=new List<BehaviorTree>();
private void Awake()
{
_instance = this;
}
private void Start()
{
BehaviorTree[] bts= FindObjectsOfType<BehaviorTree>();
foreach (var bt in bts)
{
if (bt.Group == 1) {//可根据行为树的Group来查找需要的行为树
flagNotTakenBehaviorTrees.Add(bt);
} else {
flagTakenBehaviorTrees.Add(bt);
}
}
}
//拿到旗帜
public void TakeFlag() {
foreach (var bt in flagNotTakenBehaviorTrees) {
if (BehaviorManager.instance.IsBehaviorEnabled(bt)) {//判断行为树是否启用
bt.DisableBehavior();//禁用自身的行为树
}
}
foreach (var bt in flagTakenBehaviorTrees)
{
if (BehaviorManager.instance.IsBehaviorEnabled(bt)==false) {
bt.EnableBehavior();//启用自身的行为树
}
}
}
//丢下旗帜
public void DropFlag() {
foreach (var bt in flagNotTakenBehaviorTrees)
{
if (BehaviorManager.instance.IsBehaviorEnabled(bt)==false)
{//判断行为树是否启用
bt.EnableBehavior();//启用自身
}
}
foreach (var bt in flagTakenBehaviorTrees)
{
if (BehaviorManager.instance.IsBehaviorEnabled(bt))
{
bt.DisableBehavior();//启用自身
}
}
}
网友评论