繼續昨天的工程,給Monster添加一個空物體命名為AI,在AI添加腳本BehaviorTree,然后就可以打開行為樹編輯器進行編輯了
先寫好自定義的節點腳本,下面是一個尋找漫游點的行為節點腳本
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyActions")] [TaskDescription("計算出更新的路徑")] public class ChooseWanderPosition : Action { [BehaviorDesigner.Runtime.Tasks.Tooltip("最長距離")] public float wanderDistance; [BehaviorDesigner.Runtime.Tasks.Tooltip("存放目標地的變量")] public SharedVector3 destination; [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")] public SharedGameObject monster; public override TaskStatus OnUpdate(){ Vector3 direction = new Vector3(Random.Range(-1f, 1f), 0f, UnityEngine.Random.Range(-1f, 1f)); direction *= wanderDistance; destination.Value = monster.Value.transform.position + direction; return TaskStatus.Success; } }
[TaskCategory("MyActions")]
指定文件的目錄為MyActions,我是在Actions下新建了一個MyActions的文件夾,所以指定目錄為MyActions
其實也可以不指定,但是添加節點時就會顯得雜亂
[TaskDescription("計算出更新的路徑")]
這可以提示腳本的功能
public的屬性將會顯示在面板上
既可使用int float GameObject這種unity的類型,但缺點在於無法和其他腳本共享變量
Shared xxx類型是插件提供的,他在整個行為樹中都能使用
使用Shared xxx類型前,必須在Variables先定義變量
之后點擊該按鈕切換后就能選擇全局的變量了
最后設置如下,該節點就完成了
[BehaviorDesigner.Runtime.Tasks.Tooltip("xxx")]是面板上變量的解釋,移動到面板變量上會顯示
作為行為節點必須繼承自Action並實現OnUpdate
OnUpdate()是節點執行時要運行的代碼
接下來貼出其他要用到的行為節點
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyActions")] [TaskDescription("轉向玩家")] public class FaceToPlayer : Action { [BehaviorDesigner.Runtime.Tasks.Tooltip("朝向的目標玩家")] public SharedGameObject player; [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")] public SharedGameObject monster; public override TaskStatus OnUpdate(){ Vector3 targetDir = player.Value.transform.position - monster.Value.transform.position; monster.Value.transform.rotation = Quaternion.LookRotation(targetDir); return TaskStatus.Success; } }
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyActions")] [TaskDescription("移動至漫游點")] public class MoveToWanderPoint : Action { [BehaviorDesigner.Runtime.Tasks.Tooltip("移動的速度")] public float speed = 3; [BehaviorDesigner.Runtime.Tasks.Tooltip("移動的目標點")] public SharedVector3 position; [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")] public SharedGameObject monster; public override TaskStatus OnUpdate(){ monster.Value.GetComponent<NavMeshAgent>().Move(position.Value); return TaskStatus.Success; } }
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyActions")] [TaskDescription("移動至玩家")] public class MoveToWanderPoint : Action { [BehaviorDesigner.Runtime.Tasks.Tooltip("移動的速度")] public float speed = 3; [BehaviorDesigner.Runtime.Tasks.Tooltip("移動的目標玩家")] public SharedGameObject player; [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")] public SharedGameObject monster; public override TaskStatus OnUpdate(){ monster.Value.GetComponent<NavMeshAgent>().Move(player.Value.transform.position); return TaskStatus.Success; } }
因為移動調用了NavMeshAgent,所以我們先烘焙下場景並給Monster添加NavMeshAgent控件
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyActions")] [TaskDescription("設置怪物的基本屬性")] public class SetInfo : Action { [BehaviorDesigner.Runtime.Tasks.Tooltip("玩家")] public SharedGameObject player; [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")] public SharedGameObject monster; public override TaskStatus OnUpdate(){ monster.Value = transform.parent.gameObject; player.Value = GameObject.FindWithTag("Player"); return TaskStatus.Success; } }
我們還需要自己寫一個判斷節點來判定玩家和怪物的距離,還需一個判斷節點判斷物體是否移動
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyConditionals")] [TaskDescription("判斷范圍內是否有玩家")] public class PlayerInRange : Conditional { [BehaviorDesigner.Runtime.Tasks.Tooltip("距離")] public float ranage; [BehaviorDesigner.Runtime.Tasks.Tooltip("判斷距離的玩家")] public SharedGameObject player; [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")] public SharedGameObject monster; public override TaskStatus OnUpdate(){ if(Vector3.Distance(player.Value.transform.position, monster.Value.transform.position) > ranage){ return TaskStatus.Failure; } return TaskStatus.Success; } }
using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyConditionals")] [TaskDescription("判斷對象是否移動")] public class NotMove : Conditional { [BehaviorDesigner.Runtime.Tasks.Tooltip("上一次的位置")] public Vector3 lastPosition; [BehaviorDesigner.Runtime.Tasks.Tooltip("判斷的對象")] public SharedGameObject obj; public override TaskStatus OnUpdate(){ if(obj.Value.transform.position == lastPosition){ return TaskStatus.Success; } lastPosition = obj.Value.transform.position; return TaskStatus.Failure; } }
依靠這些節點就可以拼出一顆行為樹,一運行就可以看到一個簡單的AI在運行,在攻擊范圍內它會攻擊,在追擊范圍內它會追擊敵人直到可以攻擊,否則漫游
紅圈位置可以改變節點顏色,更容易觀察行為樹結構
一些細節方面可以觀看Demo
http://git.oschina.net/yejinqi/BehaviorTreeDemo
如果的事:http://y.qq.com/#type=song&mid=0040ZKt52jxJ6Y&play=1