=====================行为树(Behavior Tree)框架代码======================
父节点:
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 父节点
/// </summary>
public class BehaviorTreeNode : MonoBehaviour, IBehaviourTreeNode
{
public int weight; //加权
[HideInInspector]
protected RunStatus runStatus = RunStatus.Success;
public virtual RunStatus Run()
{
return runStatus;
}
public void Success()
{
runStatus = RunStatus.Success;
}
public void Failure()
{
runStatus = RunStatus.Failure;
}
public void Running()
{
runStatus = RunStatus.Running;
}
public RunStatus GetRunStatus()
{
return runStatus;
}
protected static void RandSortList(List<BehaviorTreeNode> list)
{
int size = list.Count;
int seed = 10000;
System.Random rand = new System.Random();
for (int i = 0; i < size; i++)
{
int randIndex = (int)(rand.Next(seed) % (size - i)) + i;
BehaviorTreeNode j = list[i];
list[i] = list[randIndex];
list[randIndex] = j;
}
}
}
根节点:
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 根结点
/// </summary>
public class BehaviorTreeRoot : MonoBehaviour {
public List<BehaviorTreeNode> childList;
// 每隔多少帧驱动一次行为树
public int updatePerFrame = 0;
private int frame = 0;
void Update () {
if (updatePerFrame <= 0)
{
Run();
}
else
{
frame = frame++ % updatePerFrame;
if(frame == 0)
Run();
}
}
void Run()
{
for (int i = 0; i < childList.Count; i++)
{
childList[i].Run();
}
}
}
组合节点:
(1) 顺序节点
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 决策节点: 顺序结点 (逻辑与)
/// </summary>
public class SequenceNode : BehaviorTreeNode
{
public enum SequenceType
{
NormalSequence, //按标准顺序迭代子节点
RandomSequence //按随机顺序迭代子节点
}
public SequenceType sequenceType;
public List<BehaviorTreeNode> childList;
private int currentIndex = 0;
public override RunStatus Run()
{
if (null == childList)
return RunStatus.Success;
if (sequenceType == SequenceType.RandomSequence)
{
if (runStatus != RunStatus.Running)
RandSortList(childList);
}
IterateChilds();
return runStatus;
}
private void IterateChilds()
{
for (int i = currentIndex; i < childList.Count; i++)
{
runStatus = childList[i].Run();
if (runStatus == RunStatus.Success)
{
currentIndex = 0;
}
else if (runStatus == RunStatus.Failure)
{
currentIndex = 0;
break;
}
else if (runStatus == RunStatus.Running)
{
currentIndex = i;
break;
}
}
}
}
(2) 选择节点
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 决策节点: 选择结点 (逻辑或)
/// </summary>
public class SelectorNode : BehaviorTreeNode
{
public enum SelectorType
{
NormalSelector, //标准选择器
WeightRandomSelector, //加权随机选择器 (第一个子节点随机选择)
WeightRandomSequence //序列随机选择器 (每次按不同的顺序执行子节点)
}
public SelectorType selectorType;
public List<BehaviorTreeNode> childList;
private int weightSum = -1;
private int currentIndex = 0;
public override RunStatus Run()
{
if (null == childList)
return RunStatus.Success;
switch (selectorType)
{
case SelectorType.NormalSelector:
NormalSelector();
break;
case SelectorType.WeightRandomSelector:
WeightRandomSelector();
break;
case SelectorType.WeightRandomSequence:
WeightRandomSequence();
break;
}
return runStatus;
}
private void WeightRandomSelector()
{
if (CurrentNodeRunning())
return;
if (weightSum == -1)
{
for (int i = 0; i < childList.Count; i++)
weightSum += childList[i].weight;
}
// 按加权随机执行第一个子节点
System.Random rand = new System.Random();
int randWeight = rand.Next(weightSum);
int ignoreIndex = -1;
for (int i = 0; i < childList.Count; i++)
{
if (randWeight <= childList[i].weight)
{
if (runStatus == RunStatus.Success)
{
currentIndex = 0;
return;
}
else if (runStatus == RunStatus.Failure)
{
currentIndex = 0;
ignoreIndex = i;
break;
}
else if (runStatus == RunStatus.Running)
{
currentIndex = i;
return;
}
}
}
// 按顺序执行其他子节点
IterateChilds(ignoreIndex);
}
private void WeightRandomSequence()
{
if (runStatus != RunStatus.Running)
RandSortList(childList);
IterateChilds();
}
private void NormalSelector()
{
IterateChilds();
}
private bool CurrentNodeRunning()
{
// 如果处于Running状态,则继续调用当前节点。
if (runStatus == RunStatus.Running)
{
runStatus = childList[currentIndex].Run();
if (runStatus == RunStatus.Running)
return true;
}
return false;
}
private void IterateChilds(int ignoreIndex = -1)
{
for (int i = currentIndex; i < childList.Count; i++)
{
if (i == ignoreIndex)
continue;
runStatus = childList[i].Run();
if (runStatus == RunStatus.Success)
{
currentIndex = 0;
break;
}
else if (runStatus == RunStatus.Failure)
{
currentIndex = 0;
}
else if (runStatus == RunStatus.Running)
{
currentIndex = i;
break;
}
}
}
}
(3) 并行节点
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 决策节点: 并行结点
/// 返回值由返回策略决定
/// </summary>
public class ParallelNode : BehaviorTreeNode
{
// 返回策略
public enum Strategy
{
Sequence, //有一个子节点返回False则返回False,否则返回True。
Selector, //有一个子节点返回True则返回True,否则返回False。
FailureAll, //所有子节点False才返回False,否则返回True。
SuccessAll, //所有子节点True才返回True,否则返回False。
Hybird //指定数量的子节点返回True或False后,才决定结果。
}
public Strategy strategy;
//有hybirdCount个子节点返回hybird,则返回True,否则返回False
public RunStatus hybird = RunStatus.Success;
public int hybirdCount = 1;
public List<BehaviorTreeNode> childList;
public override RunStatus Run()
{
switch (strategy)
{
case Strategy.Sequence: runStatus = Sequence(); break;
case Strategy.Selector: runStatus = Selector(); break;
case Strategy.FailureAll: runStatus = FailureAll(); break;
case Strategy.SuccessAll: runStatus = SuccessAll(); break;
case Strategy.Hybird: runStatus = Hybird(); break;
}
return runStatus;
}
private RunStatus Sequence()
{
RunStatus status = RunStatus.Success;
for (int i = 0; i < childList.Count; i++)
{
if (childList[i].Run() == RunStatus.Failure)
status = RunStatus.Failure;
}
return status;
}
private RunStatus Selector()
{
RunStatus status = RunStatus.Success;
for (int i = 0; i < childList.Count; i++)
{
if (childList[i].Run() == RunStatus.Success)
status = RunStatus.Success;
}
return status;
}
private RunStatus FailureAll()
{
RunStatus status = RunStatus.Success;
for (int i = 0; i < childList.Count; i++)
{
if (childList[i].Run() == RunStatus.Success)
status = RunStatus.Failure;
}
return status;
}
private RunStatus SuccessAll()
{
RunStatus status = RunStatus.Success;
for (int i = 0; i < childList.Count; i++)
{
if (childList[i].Run() == RunStatus.Failure)
status = RunStatus.Failure;
}
return status;
}
private RunStatus Hybird()
{
int num = 0;
for (int i = 0; i < childList.Count; i++)
{
if (childList[i].Run() == hybird)
num++;
}
return num >= hybirdCount ? RunStatus.Success : RunStatus.Failure;
}
}
行为节点:
using UnityEngine;
/// <summary>
/// 行为结点 (叶节点)
/// </summary>
public class ActionNode : BehaviorTreeNode
{
public GameObject eventReceiver;
public string functionName = "OnAction";
public override RunStatus Run()
{
eventReceiver.SendMessage(functionName, this, SendMessageOptions.DontRequireReceiver);
return runStatus;
}
}
条件节点:
(1) 一般条件节点
using UnityEngine;
using System.Collections;
/// <summary>
/// 行为结点 (叶节点)
/// 返回判断结果
/// </summary>
public class ConditionNode : BehaviorTreeNode
{
public GameObject eventReceiver;
public string functionName = "OnCondition";
public override RunStatus Run()
{
eventReceiver.SendMessage(functionName, this, SendMessageOptions.DontRequireReceiver);
return runStatus;
}
}
(2) 前置条件节点
using UnityEngine;
using System.Collections;
/// <summary>
/// 前置条件 (只有当前置条件返回Success时,下面的行为结点才会被调用)
/// </summary>
public class WithPrecondition : BehaviorTreeNode
{
public GameObject eventReceiver;
public string functionName = "OnWithPrecondition";
public BehaviorTreeNode actionNode;
public override RunStatus Run()
{
runStatus = RunStatus.Failure;
eventReceiver.SendMessage(functionName, this, SendMessageOptions.DontRequireReceiver);
if (runStatus == RunStatus.Success)
runStatus = actionNode.Run();
return runStatus;
}
}
装饰结点: 这类节点有很多,可根据项目需要自行增加。
(1) 等待节点
using UnityEngine;
using System.Collections;
/// <summary>
/// 等待结点
/// </summary>
public class WaitNode : BehaviorTreeNode
{
public float waitSecond;//等待时间(单位: 秒)
public BehaviorTreeNode node;
private float lastTime;
public override RunStatus Run()
{
if (Time.time - lastTime < waitSecond)
return RunStatus.Failure;
lastTime = Time.time;
runStatus = node.Run();
return runStatus;
}
}
(2) 逻辑非节点
using UnityEngine;
using System.Collections;
/// <summary>
/// 装饰节点
/// 逻辑非
/// </summary>
public class DecoratorNode : BehaviorTreeNode
{
public override RunStatus Run()
{
//TODO:: 待实现
return runStatus;
}
}
(3) 计数节点
using UnityEngine;
using System.Collections;
/// <summary>
/// 装饰节点
/// 计数
/// </summary>
public class DecoratorCounter : BehaviorTreeNode
{
public override RunStatus Run()
{
//TODO:: 待实现
return runStatus;
}
}
(4) 直到失败节点
using UnityEngine;
using System.Collections;
/// <summary>
/// 装饰节点
/// 直到子结点返回失败才返回True
/// </summary>
public class DecoratorFailUtil : BehaviorTreeNode
{
public override RunStatus Run()
{
//TODO:: 待实现
return runStatus;
}
}
NPC示例脚本:
using UnityEngine;
using System.Collections;
public class NPCAction : MonoBehaviour {
#region 巡逻
// 前置条件
void PreconditionPatrol(IBehaviourTreeNode node)
{
if (Input.GetKeyDown(KeyCode.P))
node.Success();
else
node.Failure();
}
// 行为
void Patrol(IBehaviourTreeNode node)
{
node.Running();
Debug.Log("Patrol: RunStatus=" + node.GetRunStatus());
}
#endregion
#region 逃跑
// 前置条件
void PreconditionEscape(IBehaviourTreeNode node)
{
if (Input.GetKeyDown(KeyCode.E))
node.Success();
else
node.Failure();
}
// 行为
void Escape(IBehaviourTreeNode node)
{
node.Running();
Debug.Log("Escape: RunStatus=" + node.GetRunStatus());
}
#endregion
#region 攻击
// 前置条件
void PreconditionAttack(IBehaviourTreeNode node)
{
if (Input.GetKeyDown(KeyCode.A))
node.Success();
else
node.Failure();
}
// 行为
void Attack(IBehaviourTreeNode node)
{
node.Running();
Debug.Log("Attack: RunStatus=" + node.GetRunStatus());
}
#endregion
#region 回血
void AddHP1(IBehaviourTreeNode node)
{
node.Success();
Debug.Log("AddHP1");
}
void AddHP2(IBehaviourTreeNode node)
{
node.Success();
Debug.Log("AddHP2");
}
void AddHP3(IBehaviourTreeNode node)
{
node.Success();
Debug.Log("AddHP3");
}
#endregion
#region 条件检查
// 是否满足死忘条件
void ConditionDie(IBehaviourTreeNode node)
{
if (Input.GetKeyDown(KeyCode.D))
{
node.Success();
Debug.Log("ConditionDie: RunStatus=" + node.GetRunStatus());
}
node.Failure();
}
// 是否满足复活条件
void ConditionRelive(IBehaviourTreeNode node)
{
if (Input.GetKeyDown(KeyCode.R))
{
node.Success();
Debug.Log("ConditionRelive: RunStatus=" + node.GetRunStatus());
}
node.Failure();
}
#endregion
}
附上Demo源文件
360网盘下载
https://yunpan.cn/cxqTN8Ns4syam 访问密码 0079