做一個簡單敵人巡邏
導(dǎo)入資源后权悟,直接添加一個Tasks-> Actions->Patrol行為樹任務(wù)
Paste_Image.png
然后進入Inspector設(shè)置參數(shù)
Paste_Image.png
Paste_Image.png
接下來我們再給我們的敵人添加導(dǎo)航的組件這樣我們怪物的巡禮就完成了
Paste_Image.png
35分10秒.gif
會追擊所看到的敵人
下面是設(shè)置行為樹的執(zhí)行關(guān)系
Paste_Image.png
首先我們設(shè)置三個變量鹰霍,一個是游戲?qū)ο蟮乃俣?旋轉(zhuǎn)速度和所要追擊敵人的Transform挖炬。
Paste_Image.png
Paste_Image.png
下面我們設(shè)置看到目標敵人后就需要去追擊敵人逼庞。所以Target Transform就要設(shè)置敵人的Transform宵晚。
Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png
當離開了視野范圍的時候就會朝著它原來的目標前進
Paste_Image.png
自寫Seek任務(wù)
直接讓它繼承自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;
}
//當進入到這個任務(wù)的時候,會一直調(diào)用這個方法睁搭,一直到任務(wù)結(jié)束 一返回一個 成功或者失敗的狀態(tài)
//那么認為結(jié)束 如果返回一個running的狀態(tài)赶诊,那這個方法會繼續(xù)被調(diào)用
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;
}
}
我們可以看到我們自己寫的任務(wù)被Action 自動添加了進去
Paste_Image.png
自寫CanSeekObject任務(wù)
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//用來判斷目標是否在視野內(nèi)
public class MyCanSeeObject : Conditional {
public Transform[] targets;//判斷是否在視野內(nèi)的目標
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;
}
}
Paste_Image.png
自寫一個追擊敵人的行為任務(wù)
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;
}
//如果搶奪者在視野內(nèi)舔痪,就追,否則就認為防御成功
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;
}
}
行為樹局部變量與全局變量
Paste_Image.png
//行為樹局部變量遇伞,后面必須.Value才能獲取到(target.Value.position)
public SharedTransform target;
//行為樹全局變量
public BehaviorTree behaviortree;
//設(shè)置與獲取全局變量
behaviortree.SetVariable("MyVariable", target);
behaviortree.GetVariable("MyVariable");
某些任務(wù)的含義
Paste_Image.png
Paste_Image.png
多個行為樹的使用
一個游戲?qū)ο罂梢允褂枚鄠€行為樹辙喂。可相互切換行為樹的執(zhí)行
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) {//可根據(jù)行為樹的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();//啟用自身
}
}
}