第7章 行为树技术在游戏AI复杂决策中的应用
本文摘要: 行为树(Behavior Tree)是游戏AI中构建复杂决策系统的树状模型,相比有限状态机具有模块化、可读性强、灵活扩展等优势。文章介绍了行为树的核心概念和基础架构实现,包括节点状态枚举(NodeStatus)、节点基类(BTNode)和行为树主类(BehaviorTree)的设计。该系统支持节点执行状态追踪、树运行控制(启动/停止/暂停/恢复)以及事件回调机制,为游戏AI提供了可重用
第七章 行为树技术在游戏AI复杂决策中的应用
7.1 行为树系统的基本原理与架构设计
7.1.1 行为树核心概念解析
行为树(Behavior Tree)是游戏AI领域中用于构建复杂决策系统的树状结构模型。与有限状态机相比,行为树提供了更直观、更模块化的方式来组织和控制AI行为。行为树通过节点之间的层次关系和执行流程来定义AI的决策逻辑,每个节点都有特定的功能和执行结果。
行为树的核心优势在于:
- 模块化设计:行为可以分解为可重用的子任务
- 可读性强:树状结构直观展示AI决策流程
- 灵活扩展:容易添加新的行为而不影响现有逻辑
- 并行处理:支持多个行为同时执行
- 易于调试:可以可视化追踪行为执行路径
下面是行为树系统的基础架构实现:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace BehaviorTreeSystem
{
/// <summary>
/// 节点执行状态
/// </summary>
public enum NodeStatus
{
Success, // 成功
Failure, // 失败
Running // 执行中
}
/// <summary>
/// 行为树节点基类
/// </summary>
public abstract class BTNode
{
protected string nodeName;
protected BehaviorTree behaviorTree;
protected Blackboard blackboard;
public string NodeName
{
get { return nodeName; }
}
public BTNode(string name)
{
nodeName = name;
}
public virtual void Initialize(BehaviorTree tree, Blackboard bb)
{
behaviorTree = tree;
blackboard = bb;
}
public abstract NodeStatus Evaluate();
public virtual void OnEnter() { }
public virtual void OnExit() { }
public virtual void OnReset() { }
public virtual void OnAbort() { }
}
/// <summary>
/// 行为树
/// </summary>
public class BehaviorTree
{
private BTNode rootNode;
private Blackboard blackboard;
private GameObject owner;
private BTNode currentRunningNode;
private List<BTNode> nodeHistory;
private bool isRunning;
private bool isPaused;
private int maxHistorySize = 100;
public GameObject Owner
{
get { return owner; }
}
public Blackboard Blackboard
{
get { return blackboard; }
}
public bool IsRunning
{
get { return isRunning; }
}
public event Action<string, NodeStatus> OnNodeExecuted;
public event Action<string> OnTreeStarted;
public event Action<string> OnTreeStopped;
public event Action<string, string> OnNodeChanged;
public BehaviorTree(GameObject owner, BTNode root, Blackboard bb = null)
{
this.owner = owner;
rootNode = root;
blackboard = bb ?? new Blackboard();
nodeHistory = new List<BTNode>();
// 初始化根节点
rootNode.Initialize(this, blackboard);
}
public void Start()
{
if (isRunning)
{
Debug.LogWarning("行为树已经在运行");
return;
}
isRunning = true;
isPaused = false;
nodeHistory.Clear();
OnTreeStarted?.Invoke(owner.name);
Debug.Log($"行为树开始执行: {owner.name}");
}
public void Stop()
{
if (!isRunning)
{
return;
}
isRunning = false;
// 中止当前运行节点
if (currentRunningNode != null)
{
currentRunningNode.OnAbort();
currentRunningNode = null;
}
// 重置所有节点
ResetTree();
OnTreeStopped?.Invoke(owner.name);
Debug.Log($"行为树停止执行: {owner.name}");
}
public void Pause()
{
if (!isRunning || isPaused)
{
return;
}
isPaused = true;
if (currentRunningNode != null)
{
currentRunningNode.OnAbort();
}
Debug.Log($"行为树暂停: {owner.name}");
}
public void Resume()
{
if (!isRunning || !isPaused)
{
return;
}
isPaused = false;
Debug.Log($"行为树恢复执行: {owner.name}");
}
public void Update()
{
if (!isRunning || isPaused)
{
return;
}
if (rootNode == null)
{
Debug.LogError("行为树没有根节点");
return;
}
// 执行根节点
NodeStatus status = rootNode.Evaluate();
// 记录执行状态
if (status != NodeStatus.Running)
{
// 非运行状态表示树执行完成
// 在实际应用中,行为树通常持续运行,这里可以根据需要处理
}
}
public void SetRunningNode(BTNode node)
{
BTNode previousNode = currentRunningNode;
currentRunningNode = node;
OnNodeChanged?.Invoke(
previousNode?.NodeName ?? "None",
node?.NodeName ?? "None"
);
}
public void RecordNodeExecution(BTNode node, NodeStatus status)
{
// 记录节点执行历史
nodeHistory.Add(node);
// 限制历史记录大小
if (nodeHistory.Count > maxHistorySize)
{
nodeHistory.RemoveAt(0);
}
OnNodeExecuted?.Invoke(node.NodeName, status);
}
private void ResetTree()
{
// 递归重置所有节点
ResetNode(rootNode);
}
private void ResetNode(BTNode node)
{
if (node == null)
{
return;
}
node.OnReset();
// 如果是组合节点,递归重置子节点
if (node is CompositeNode composite)
{
foreach (BTNode child in composite.GetChildren())
{
ResetNode(child);
}
}
// 如果是装饰节点,重置子节点
else if (node is DecoratorNode decorator)
{
if (decorator.HasChild())
{
ResetNode(decorator.GetChild());
}
}
}
public List<string> GetExecutionHistory(int count = 20)
{
List<string> history = new List<string>();
int startIndex = Mathf.Max(0, nodeHistory.Count - count);
for (int i = startIndex; i < nodeHistory.Count; i++)
{
history.Add(nodeHistory[i].NodeName);
}
return history;
}
public BTNode FindNode(string nodeName)
{
return FindNodeRecursive(rootNode, nodeName);
}
private BTNode FindNodeRecursive(BTNode node, string nodeName)
{
if (node == null)
{
return null;
}
if (node.NodeName == nodeName)
{
return node;
}
if (node is CompositeNode composite)
{
foreach (BTNode child in composite.GetChildren())
{
BTNode found = FindNodeRecursive(child, nodeName);
if (found != null)
{
return found;
}
}
}
else if (node is DecoratorNode decorator && decorator.HasChild())
{
return FindNodeRecursive(decorator.GetChild(), nodeName);
}
return null;
}
}
/// <summary>
/// 黑板系统 - 用于节点间数据共享
/// </summary>
public class Blackboard
{
private Dictionary<string, object> data;
private Dictionary<string, List<Action<object>>> listeners;
public Blackboard()
{
data = new Dictionary<string, object>();
listeners = new Dictionary<string, List<Action<object>>>();
}
public void SetValue<T>(string key, T value)
{
data[key] = value;
// 通知监听者
if (listeners.ContainsKey(key))
{
foreach (Action<object> listener in listeners[key])
{
listener(value);
}
}
}
public T GetValue<T>(string key, T defaultValue = default(T))
{
if (data.ContainsKey(key) && data[key] is T)
{
return (T)data[key];
}
return defaultValue;
}
public bool HasValue(string key)
{
return data.ContainsKey(key);
}
public void RemoveValue(string key)
{
if (data.ContainsKey(key))
{
data.Remove(key);
}
}
public void AddListener(string key, Action<object> listener)
{
if (!listeners.ContainsKey(key))
{
listeners[key] = new List<Action<object>>();
}
if (!listeners[key].Contains(listener))
{
listeners[key].Add(listener);
}
}
public void RemoveListener(string key, Action<object> listener)
{
if (listeners.ContainsKey(key))
{
listeners[key].Remove(listener);
}
}
public void Clear()
{
data.Clear();
listeners.Clear();
}
public Dictionary<string, object> GetAllData()
{
return new Dictionary<string, object>(data);
}
}
}
7.1.2 叶节点:行为与条件的实现
叶节点是行为树的终端节点,负责执行具体的任务或检查条件。叶节点分为两种类型:动作节点(Action Node)和条件节点(Condition Node)。动作节点执行具体行为,如移动、攻击等;条件节点检查特定条件并返回成功或失败。
下面是叶节点的具体实现:
namespace BehaviorTreeSystem
{
/// <summary>
/// 动作节点基类 - 执行具体行为
/// </summary>
public abstract class ActionNode : BTNode
{
protected float executionTime;
protected float startTime;
protected bool isRunning;
public ActionNode(string name) : base(name)
{
executionTime = 0f;
isRunning = false;
}
public override void OnEnter()
{
startTime = Time.time;
isRunning = true;
Debug.Log($"动作节点进入: {nodeName}");
}
public override void OnExit()
{
isRunning = false;
executionTime = Time.time - startTime;
Debug.Log($"动作节点退出: {nodeName},执行时间: {executionTime:F2}s");
}
public override void OnReset()
{
isRunning = false;
executionTime = 0f;
}
public override void OnAbort()
{
if (isRunning)
{
OnExit();
}
}
public abstract NodeStatus Execute();
public override NodeStatus Evaluate()
{
if (!isRunning)
{
OnEnter();
}
NodeStatus status = Execute();
if (status != NodeStatus.Running)
{
OnExit();
behaviorTree.SetRunningNode(null);
}
else
{
behaviorTree.SetRunningNode(this);
}
behaviorTree.RecordNodeExecution(this, status);
return status;
}
}
/// <summary>
/// 条件节点基类 - 检查条件
/// </summary>
public abstract class ConditionNode : BTNode
{
public ConditionNode(string name) : base(name) { }
public abstract bool CheckCondition();
public override NodeStatus Evaluate()
{
bool conditionMet = CheckCondition();
NodeStatus status = conditionMet ? NodeStatus.Success : NodeStatus.Failure;
behaviorTree.RecordNodeExecution(this, status);
return status;
}
}
/// <summary>
/// 组合节点基类 - 管理子节点
/// </summary>
public abstract class CompositeNode : BTNode
{
protected List<BTNode> children;
protected int currentChildIndex;
public CompositeNode(string name) : base(name)
{
children = new List<BTNode>();
currentChildIndex = 0;
}
public void AddChild(BTNode child)
{
if (child != null)
{
children.Add(child);
child.Initialize(behaviorTree, blackboard);
}
}
public void RemoveChild(BTNode child)
{
if (children.Contains(child))
{
children.Remove(child);
}
}
public void RemoveChildAt(int index)
{
if (index >= 0 && index < children.Count)
{
children.RemoveAt(index);
}
}
public BTNode GetChild(int index)
{
if (index >= 0 && index < children.Count)
{
return children[index];
}
return null;
}
public List<BTNode> GetChildren()
{
return new List<BTNode>(children);
}
public int ChildCount
{
get { return children.Count; }
}
public override void OnReset()
{
currentChildIndex = 0;
foreach (BTNode child in children)
{
child.OnReset();
}
}
public override void OnAbort()
{
// 中止当前执行的子节点
if (currentChildIndex < children.Count)
{
children[currentChildIndex].OnAbort();
}
}
}
/// <summary>
/// 顺序节点 - 按顺序执行子节点,所有成功则成功,任何一个失败则失败
/// </summary>
public class SequenceNode : CompositeNode
{
public SequenceNode(string name) : base(name) { }
public override NodeStatus Evaluate()
{
if (children.Count == 0)
{
return NodeStatus.Failure;
}
// 从当前索引开始执行
while (currentChildIndex < children.Count)
{
BTNode child = children[currentChildIndex];
NodeStatus status = child.Evaluate();
if (status == NodeStatus.Running)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else if (status == NodeStatus.Failure)
{
// 失败则重置并返回失败
currentChildIndex = 0;
behaviorTree.SetRunningNode(null);
return NodeStatus.Failure;
}
else if (status == NodeStatus.Success)
{
// 成功则继续下一个子节点
currentChildIndex++;
}
}
// 所有子节点执行成功
currentChildIndex = 0;
behaviorTree.SetRunningNode(null);
return NodeStatus.Success;
}
}
/// <summary>
/// 选择节点(Fallback) - 执行子节点直到一个成功,所有失败则失败
/// </summary>
public class SelectorNode : CompositeNode
{
public SelectorNode(string name) : base(name) { }
public override NodeStatus Evaluate()
{
if (children.Count == 0)
{
return NodeStatus.Failure;
}
// 从当前索引开始执行
while (currentChildIndex < children.Count)
{
BTNode child = children[currentChildIndex];
NodeStatus status = child.Evaluate();
if (status == NodeStatus.Running)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else if (status == NodeStatus.Success)
{
// 成功则重置并返回成功
currentChildIndex = 0;
behaviorTree.SetRunningNode(null);
return NodeStatus.Success;
}
else if (status == NodeStatus.Failure)
{
// 失败则继续下一个子节点
currentChildIndex++;
}
}
// 所有子节点执行失败
currentChildIndex = 0;
behaviorTree.SetRunningNode(null);
return NodeStatus.Failure;
}
}
/// <summary>
/// 并行节点 - 同时执行所有子节点
/// </summary>
public class ParallelNode : CompositeNode
{
public enum ParallelPolicy
{
AllSuccess, // 所有子节点成功才算成功
AllFailure, // 所有子节点失败才算失败
OneSuccess, // 一个子节点成功就算成功
OneFailure // 一个子节点失败就算失败
}
private ParallelPolicy successPolicy;
private ParallelPolicy failurePolicy;
private Dictionary<BTNode, NodeStatus> childStatuses;
public ParallelNode(string name, ParallelPolicy successPolicy = ParallelPolicy.AllSuccess,
ParallelPolicy failurePolicy = ParallelPolicy.OneFailure) : base(name)
{
this.successPolicy = successPolicy;
this.failurePolicy = failurePolicy;
childStatuses = new Dictionary<BTNode, NodeStatus>();
}
public override void OnEnter()
{
base.OnEnter();
// 初始化子节点状态
childStatuses.Clear();
foreach (BTNode child in children)
{
childStatuses[child] = NodeStatus.Running;
}
}
public override NodeStatus Evaluate()
{
if (children.Count == 0)
{
return NodeStatus.Failure;
}
int successCount = 0;
int failureCount = 0;
int runningCount = 0;
// 执行所有子节点
foreach (BTNode child in children)
{
if (childStatuses[child] == NodeStatus.Running)
{
NodeStatus status = child.Evaluate();
childStatuses[child] = status;
}
// 统计结果
switch (childStatuses[child])
{
case NodeStatus.Success:
successCount++;
break;
case NodeStatus.Failure:
failureCount++;
break;
case NodeStatus.Running:
runningCount++;
break;
}
}
// 根据策略判断结果
bool isSuccess = false;
bool isFailure = false;
switch (successPolicy)
{
case ParallelPolicy.AllSuccess:
isSuccess = (successCount == children.Count);
break;
case ParallelPolicy.OneSuccess:
isSuccess = (successCount > 0);
break;
}
switch (failurePolicy)
{
case ParallelPolicy.AllFailure:
isFailure = (failureCount == children.Count);
break;
case ParallelPolicy.OneFailure:
isFailure = (failureCount > 0);
break;
}
// 返回结果
if (isSuccess)
{
behaviorTree.SetRunningNode(null);
return NodeStatus.Success;
}
else if (isFailure)
{
behaviorTree.SetRunningNode(null);
return NodeStatus.Failure;
}
else if (runningCount > 0)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else
{
// 默认情况
behaviorTree.SetRunningNode(null);
return NodeStatus.Failure;
}
}
public override void OnReset()
{
base.OnReset();
childStatuses.Clear();
}
}
/// <summary>
/// 随机节点 - 随机选择一个子节点执行
/// </summary>
public class RandomNode : CompositeNode
{
private System.Random random;
private int selectedChildIndex;
private bool hasSelected;
public RandomNode(string name, int seed = 0) : base(name)
{
random = seed == 0 ? new System.Random() : new System.Random(seed);
selectedChildIndex = -1;
hasSelected = false;
}
public override void OnEnter()
{
base.OnEnter();
// 随机选择一个子节点
if (children.Count > 0)
{
selectedChildIndex = random.Next(0, children.Count);
hasSelected = true;
}
else
{
selectedChildIndex = -1;
hasSelected = false;
}
}
public override NodeStatus Evaluate()
{
if (children.Count == 0 || selectedChildIndex == -1)
{
return NodeStatus.Failure;
}
BTNode selectedChild = children[selectedChildIndex];
NodeStatus status = selectedChild.Evaluate();
if (status == NodeStatus.Running)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else
{
// 执行完成,重置选择状态
hasSelected = false;
behaviorTree.SetRunningNode(null);
return status;
}
}
public override void OnReset()
{
base.OnReset();
selectedChildIndex = -1;
hasSelected = false;
}
}
}
7.1.3 装饰节点与组合节点的扩展实现
装饰节点用于修改或增强子节点的行为,它们只有一个子节点。装饰节点可以实现循环、限制、条件检查等功能。
namespace BehaviorTreeSystem
{
/// <summary>
/// 装饰节点基类 - 修饰单个子节点的行为
/// </summary>
public abstract class DecoratorNode : BTNode
{
protected BTNode child;
public DecoratorNode(string name, BTNode child = null) : base(name)
{
this.child = child;
}
public void SetChild(BTNode newChild)
{
child = newChild;
if (child != null && behaviorTree != null)
{
child.Initialize(behaviorTree, blackboard);
}
}
public BTNode GetChild()
{
return child;
}
public bool HasChild()
{
return child != null;
}
public override void Initialize(BehaviorTree tree, Blackboard bb)
{
base.Initialize(tree, bb);
if (child != null)
{
child.Initialize(tree, bb);
}
}
public override void OnReset()
{
if (child != null)
{
child.OnReset();
}
}
public override void OnAbort()
{
if (child != null)
{
child.OnAbort();
}
}
}
/// <summary>
/// 逆变节点 - 反转子节点的执行结果
/// </summary>
public class InverterNode : DecoratorNode
{
public InverterNode(string name, BTNode child = null) : base(name, child) { }
public override NodeStatus Evaluate()
{
if (child == null)
{
return NodeStatus.Failure;
}
NodeStatus status = child.Evaluate();
switch (status)
{
case NodeStatus.Success:
return NodeStatus.Failure;
case NodeStatus.Failure:
return NodeStatus.Success;
case NodeStatus.Running:
return NodeStatus.Running;
default:
return NodeStatus.Failure;
}
}
}
/// <summary>
/// 重复节点 - 重复执行子节点指定次数或无限重复
/// </summary>
public class RepeaterNode : DecoratorNode
{
private int repeatCount;
private int currentCount;
private bool infinite;
public RepeaterNode(string name, int repeatCount = -1, BTNode child = null) : base(name, child)
{
this.repeatCount = repeatCount;
currentCount = 0;
infinite = repeatCount < 0;
}
public override void OnEnter()
{
base.OnEnter();
currentCount = 0;
}
public override NodeStatus Evaluate()
{
if (child == null)
{
return NodeStatus.Failure;
}
// 检查是否达到重复次数
if (!infinite && currentCount >= repeatCount)
{
return NodeStatus.Success;
}
NodeStatus status = child.Evaluate();
if (status != NodeStatus.Running)
{
currentCount++;
if (infinite)
{
// 无限重复,重置子节点并继续
child.OnReset();
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else if (currentCount < repeatCount)
{
// 还有剩余次数,重置子节点并继续
child.OnReset();
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else
{
// 达到指定次数
return NodeStatus.Success;
}
}
else
{
// 子节点还在执行中
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
}
public override void OnReset()
{
base.OnReset();
currentCount = 0;
}
}
/// <summary>
/// 直到成功节点 - 重复执行直到子节点成功
/// </summary>
public class UntilSuccessNode : DecoratorNode
{
public UntilSuccessNode(string name, BTNode child = null) : base(name, child) { }
public override NodeStatus Evaluate()
{
if (child == null)
{
return NodeStatus.Failure;
}
NodeStatus status = child.Evaluate();
if (status == NodeStatus.Success)
{
return NodeStatus.Success;
}
else if (status == NodeStatus.Failure)
{
// 失败则重置并重试
child.OnReset();
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else
{
// 执行中
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
}
}
/// <summary>
/// 条件装饰节点 - 只有条件满足时才执行子节点
/// </summary>
public class ConditionalDecoratorNode : DecoratorNode
{
private Func<bool> condition;
private bool checkOnTick;
public ConditionalDecoratorNode(string name, Func<bool> condition,
BTNode child = null, bool checkOnTick = true)
: base(name, child)
{
this.condition = condition;
this.checkOnTick = checkOnTick;
}
public override NodeStatus Evaluate()
{
if (child == null)
{
return NodeStatus.Failure;
}
bool conditionMet = condition != null ? condition() : false;
if (!conditionMet)
{
// 条件不满足,直接返回失败
return NodeStatus.Failure;
}
NodeStatus status = child.Evaluate();
if (checkOnTick && status == NodeStatus.Running)
{
// 在每次tick时检查条件
conditionMet = condition != null ? condition() : false;
if (!conditionMet)
{
// 条件不再满足,中止子节点
child.OnAbort();
return NodeStatus.Failure;
}
}
return status;
}
}
/// <summary>
/// 超时节点 - 限制子节点的执行时间
/// </summary>
public class TimeoutNode : DecoratorNode
{
private float timeoutDuration;
private float startTime;
private bool isTimedOut;
public TimeoutNode(string name, float timeoutDuration, BTNode child = null)
: base(name, child)
{
this.timeoutDuration = timeoutDuration;
isTimedOut = false;
}
public override void OnEnter()
{
base.OnEnter();
startTime = Time.time;
isTimedOut = false;
}
public override NodeStatus Evaluate()
{
if (child == null || isTimedOut)
{
return NodeStatus.Failure;
}
// 检查超时
if (Time.time - startTime > timeoutDuration)
{
isTimedOut = true;
child.OnAbort();
return NodeStatus.Failure;
}
NodeStatus status = child.Evaluate();
if (status != NodeStatus.Running)
{
// 子节点执行完成(成功或失败)
return status;
}
else
{
// 子节点仍在执行中
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
}
public override void OnReset()
{
base.OnReset();
isTimedOut = false;
}
}
/// <summary>
/// 强制成功节点 - 无论子节点结果如何,都返回成功
/// </summary>
public class ForceSuccessNode : DecoratorNode
{
public ForceSuccessNode(string name, BTNode child = null) : base(name, child) { }
public override NodeStatus Evaluate()
{
if (child == null)
{
return NodeStatus.Success;
}
NodeStatus status = child.Evaluate();
if (status == NodeStatus.Running)
{
return NodeStatus.Running;
}
else
{
return NodeStatus.Success;
}
}
}
/// <summary>
/// 强制失败节点 - 无论子节点结果如何,都返回失败
/// </summary>
public class ForceFailureNode : DecoratorNode
{
public ForceFailureNode(string name, BTNode child = null) : base(name, child) { }
public override NodeStatus Evaluate()
{
if (child == null)
{
return NodeStatus.Failure;
}
NodeStatus status = child.Evaluate();
if (status == NodeStatus.Running)
{
return NodeStatus.Running;
}
else
{
return NodeStatus.Failure;
}
}
}
}
7.1.4 子树的复用与模块化设计
子树复用是行为树的重要特性,允许将复杂的行为模式封装为可重用的子树。这大大提高了行为树的可维护性和可扩展性。
namespace BehaviorTreeSystem
{
/// <summary>
/// 子树节点 - 引用另一个行为树
/// </summary>
public class SubtreeNode : BTNode
{
private BehaviorTree subtree;
private string subtreeAssetPath; // 用于从资源加载
public SubtreeNode(string name, BehaviorTree subtree = null) : base(name)
{
this.subtree = subtree;
}
public SubtreeNode(string name, string subtreeAssetPath) : base(name)
{
this.subtreeAssetPath = subtreeAssetPath;
}
public override void Initialize(BehaviorTree tree, Blackboard bb)
{
base.Initialize(tree, bb);
if (subtree == null && !string.IsNullOrEmpty(subtreeAssetPath))
{
// 从资源加载子树
LoadSubtreeFromAsset();
}
if (subtree != null)
{
// 共享黑板或创建子黑板
Blackboard subtreeBlackboard = bb; // 共享同一个黑板
// 或者: Blackboard subtreeBlackboard = new Blackboard();
subtree.Initialize(tree.Owner, subtree.GetRootNode(), subtreeBlackboard);
}
}
private void LoadSubtreeFromAsset()
{
// 在实际项目中,这里会从AssetBundle或Resources加载行为树资产
// 这里简化实现
Debug.Log($"加载子树资产: {subtreeAssetPath}");
}
public void SetSubtree(BehaviorTree newSubtree)
{
subtree = newSubtree;
if (subtree != null && behaviorTree != null)
{
subtree.Initialize(behaviorTree.Owner, subtree.GetRootNode(), blackboard);
}
}
public BehaviorTree GetSubtree()
{
return subtree;
}
public override NodeStatus Evaluate()
{
if (subtree == null)
{
return NodeStatus.Failure;
}
// 执行子树
subtree.Update();
// 判断子树状态
// 这里简化处理,实际可能需要更复杂的逻辑来判断子树状态
if (subtree.IsRunning)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else
{
// 子树执行完成
// 在实际实现中,可能需要获取子树的具体执行结果
return NodeStatus.Success;
}
}
public override void OnReset()
{
if (subtree != null)
{
subtree.Stop();
subtree.Start();
}
}
public override void OnAbort()
{
if (subtree != null)
{
subtree.Stop();
}
}
// 扩展方法:获取子树根节点(用于调试和可视化)
public BTNode GetSubtreeRoot()
{
return subtree?.GetRootNode();
}
}
/// <summary>
/// 行为树管理器 - 管理多个行为树和子树
/// </summary>
public class BehaviorTreeManager : MonoBehaviour
{
private static BehaviorTreeManager instance;
private Dictionary<string, BehaviorTree> registeredTrees;
private Dictionary<string, BTNode> registeredSubtrees;
private Dictionary<GameObject, List<BehaviorTree>> activeTrees;
public static BehaviorTreeManager Instance
{
get
{
if (instance == null)
{
GameObject go = new GameObject("BehaviorTreeManager");
instance = go.AddComponent<BehaviorTreeManager>();
DontDestroyOnLoad(go);
}
return instance;
}
}
private void Awake()
{
if (instance != null && instance != this)
{
Destroy(gameObject);
return;
}
instance = this;
Initialize();
}
private void Initialize()
{
registeredTrees = new Dictionary<string, BehaviorTree>();
registeredSubtrees = new Dictionary<string, BTNode>();
activeTrees = new Dictionary<GameObject, List<BehaviorTree>>();
}
private void Update()
{
// 更新所有活动行为树
foreach (var kvp in activeTrees)
{
foreach (BehaviorTree tree in kvp.Value)
{
if (tree.IsRunning)
{
tree.Update();
}
}
}
}
public void RegisterTree(string treeId, BehaviorTree tree)
{
if (!registeredTrees.ContainsKey(treeId))
{
registeredTrees[treeId] = tree;
Debug.Log($"注册行为树: {treeId}");
}
else
{
Debug.LogWarning($"行为树已存在: {treeId}");
}
}
public void UnregisterTree(string treeId)
{
if (registeredTrees.ContainsKey(treeId))
{
registeredTrees.Remove(treeId);
Debug.Log($"注销行为树: {treeId}");
}
}
public BehaviorTree GetTree(string treeId)
{
return registeredTrees.ContainsKey(treeId) ? registeredTrees[treeId] : null;
}
public void RegisterSubtree(string subtreeId, BTNode subtreeRoot)
{
if (!registeredSubtrees.ContainsKey(subtreeId))
{
registeredSubtrees[subtreeId] = subtreeRoot;
Debug.Log($"注册子树: {subtreeId}");
}
else
{
Debug.LogWarning($"子树已存在: {subtreeId}");
}
}
public BTNode GetSubtree(string subtreeId)
{
return registeredSubtrees.ContainsKey(subtreeId) ? registeredSubtrees[subtreeId] : null;
}
public void ActivateTree(GameObject owner, BehaviorTree tree)
{
if (!activeTrees.ContainsKey(owner))
{
activeTrees[owner] = new List<BehaviorTree>();
}
if (!activeTrees[owner].Contains(tree))
{
activeTrees[owner].Add(tree);
tree.Start();
Debug.Log($"激活行为树: {owner.name} -> {tree.GetRootNode()?.NodeName}");
}
}
public void DeactivateTree(GameObject owner, BehaviorTree tree)
{
if (activeTrees.ContainsKey(owner) && activeTrees[owner].Contains(tree))
{
tree.Stop();
activeTrees[owner].Remove(tree);
Debug.Log($"停用行为树: {owner.name} -> {tree.GetRootNode()?.NodeName}");
if (activeTrees[owner].Count == 0)
{
activeTrees.Remove(owner);
}
}
}
public void DeactivateAllTrees(GameObject owner)
{
if (activeTrees.ContainsKey(owner))
{
foreach (BehaviorTree tree in activeTrees[owner])
{
tree.Stop();
}
activeTrees.Remove(owner);
Debug.Log($"停用所有行为树: {owner.name}");
}
}
public List<BehaviorTree> GetActiveTrees(GameObject owner)
{
return activeTrees.ContainsKey(owner) ?
new List<BehaviorTree>(activeTrees[owner]) :
new List<BehaviorTree>();
}
public Dictionary<string, BehaviorTree> GetAllRegisteredTrees()
{
return new Dictionary<string, BehaviorTree>(registeredTrees);
}
public Dictionary<string, BTNode> GetAllRegisteredSubtrees()
{
return new Dictionary<string, BTNode>(registeredSubtrees);
}
// 保存行为树到文件(序列化)
public void SaveTreeToFile(string treeId, string filePath)
{
// 在实际项目中,这里会实现序列化逻辑
Debug.Log($"保存行为树到文件: {treeId} -> {filePath}");
}
// 从文件加载行为树
public BehaviorTree LoadTreeFromFile(string filePath)
{
// 在实际项目中,这里会实现反序列化逻辑
Debug.Log($"从文件加载行为树: {filePath}");
return null;
}
// 导出子树为预制资源
public void ExportSubtreeAsAsset(string subtreeId, string assetPath)
{
if (registeredSubtrees.ContainsKey(subtreeId))
{
// 在实际项目中,这里会实现资源导出逻辑
Debug.Log($"导出子树为资源: {subtreeId} -> {assetPath}");
}
}
private void OnDestroy()
{
// 清理所有活动行为树
foreach (var kvp in activeTrees)
{
foreach (BehaviorTree tree in kvp.Value)
{
tree.Stop();
}
}
activeTrees.Clear();
registeredTrees.Clear();
registeredSubtrees.Clear();
}
}
}
7.1.5 行为树与有限状态机的对比分析
行为树和有限状态机都是游戏AI中常用的决策系统,各有优缺点。理解它们的差异对于选择合适的技术方案至关重要。
namespace BehaviorTreeSystem
{
/// <summary>
/// 行为树与有限状态机对比分析器
/// </summary>
public class FSMvsBTComparator : MonoBehaviour
{
[System.Serializable]
public class ComparisonCriteria
{
public string criteriaName;
public string fsmDescription;
public string btDescription;
public float fsmScore; // 0-10分
public float btScore; // 0-10分
public string recommendation;
}
[Header("对比标准")]
[SerializeField]
private List<ComparisonCriteria> comparisonCriteria = new List<ComparisonCriteria>();
[Header("案例分析")]
[SerializeField]
private string caseStudyName;
[SerializeField]
[TextArea(5, 10)]
private string caseDescription;
[SerializeField]
private GameObject fsmImplementation;
[SerializeField]
private GameObject btImplementation;
private void Awake()
{
InitializeComparisonCriteria();
}
private void InitializeComparisonCriteria()
{
comparisonCriteria.Clear();
// 1. 复杂度管理
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "复杂度管理",
fsmDescription = "状态数量增多时,状态转换逻辑变得复杂,难以维护",
btDescription = "树状结构自然表达层次关系,易于管理复杂行为",
fsmScore = 6f,
btScore = 9f,
recommendation = "复杂行为系统推荐使用行为树"
});
// 2. 可扩展性
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "可扩展性",
fsmDescription = "添加新状态需要修改多个转换条件,容易引入错误",
btDescription = "可以轻松添加新节点或子树,不影响现有逻辑",
fsmScore = 5f,
btScore = 9f,
recommendation = "需要频繁扩展的系统推荐行为树"
});
// 3. 可读性
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "可读性",
fsmDescription = "状态图直观,但状态转换逻辑分散在代码中",
btDescription = "树状结构清晰展示行为层次,易于理解和调试",
fsmScore = 7f,
btScore = 9f,
recommendation = "团队协作项目推荐行为树"
});
// 4. 执行效率
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "执行效率",
fsmDescription = "状态切换开销小,适合实时性要求高的场景",
btDescription = "节点遍历需要时间,但优化后效率可接受",
fsmScore = 9f,
btScore = 7f,
recommendation = "对性能要求极高的场景推荐有限状态机"
});
// 5. 并行处理
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "并行处理",
fsmDescription = "传统FSM难以处理并行状态,需要特殊设计",
btDescription = "原生支持并行节点,易于实现并发行为",
fsmScore = 4f,
btScore = 9f,
recommendation = "需要并发行为的系统推荐行为树"
});
// 6. 条件检查
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "条件检查",
fsmDescription = "条件检查集中在状态转换逻辑中",
btDescription = "条件可以作为独立节点,实现关注点分离",
fsmScore = 6f,
btScore = 8f,
recommendation = "条件逻辑复杂的系统推荐行为树"
});
// 7. 复用性
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "复用性",
fsmDescription = "状态逻辑难以复用,容易产生代码重复",
btDescription = "子树机制支持高度复用,减少重复代码",
fsmScore = 5f,
btScore = 9f,
recommendation = "需要大量复用行为的系统推荐行为树"
});
// 8. 调试支持
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "调试支持",
fsmDescription = "当前状态明确,但转换历史难以追踪",
btDescription = "可以记录完整执行路径,便于问题定位",
fsmScore = 6f,
btScore = 8f,
recommendation = "调试需求高的项目推荐行为树"
});
// 9. 学习曲线
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "学习曲线",
fsmDescription = "概念简单,易于初学者理解和实现",
btDescription = "概念较多,需要时间掌握各种节点类型",
fsmScore = 9f,
btScore = 6f,
recommendation = "新手团队或简单AI推荐有限状态机"
});
// 10. 适用场景
comparisonCriteria.Add(new ComparisonCriteria
{
criteriaName = "适用场景",
fsmDescription = "适合状态明确、转换简单的AI(如门、开关、简单敌人)",
btDescription = "适合复杂、层次化的AI(如NPC、BOSS、策略单位)",
fsmScore = 7f,
btScore = 8f,
recommendation = "根据AI复杂度选择合适技术"
});
}
public void AnalyzeAndCompare()
{
Debug.Log("=== 行为树 vs 有限状态机 对比分析 ===");
Debug.Log($"案例分析: {caseStudyName}");
Debug.Log($"案例描述: {caseDescription}");
float totalFsmScore = 0f;
float totalBtScore = 0f;
int criteriaCount = comparisonCriteria.Count;
foreach (ComparisonCriteria criteria in comparisonCriteria)
{
Debug.Log($"\n[{criteria.criteriaName}]");
Debug.Log($"FSM: {criteria.fsmDescription} (评分: {criteria.fsmScore})");
Debug.Log($"BT: {criteria.btDescription} (评分: {criteria.btScore})");
Debug.Log($"推荐: {criteria.recommendation}");
totalFsmScore += criteria.fsmScore;
totalBtScore += criteria.btScore;
}
float avgFsmScore = totalFsmScore / criteriaCount;
float avgBtScore = totalBtScore / criteriaCount;
Debug.Log($"\n=== 总结 ===");
Debug.Log($"FSM平均评分: {avgFsmScore:F1}/10");
Debug.Log($"BT平均评分: {avgBtScore:F1}/10");
if (avgBtScore > avgFsmScore + 1f)
{
Debug.Log("推荐使用: 行为树 (Behavior Tree)");
Debug.Log("理由: 行为树在复杂度管理、可扩展性、可读性和并行处理方面优势明显");
}
else if (avgFsmScore > avgBtScore + 1f)
{
Debug.Log("推荐使用: 有限状态机 (Finite State Machine)");
Debug.Log("理由: 有限状态机在执行效率和学习曲线方面更有优势,适合简单AI");
}
else
{
Debug.Log("推荐: 根据具体需求选择");
Debug.Log("理由: 两种技术各有优势,可以考虑混合使用或根据团队经验选择");
}
// 显示具体实现
ShowImplementations();
}
private void ShowImplementations()
{
if (fsmImplementation != null)
{
Debug.Log($"\n有限状态机实现示例: {fsmImplementation.name}");
// 这里可以展示FSM的具体实现代码
}
if (btImplementation != null)
{
Debug.Log($"\n行为树实现示例: {btImplementation.name}");
// 这里可以展示BT的具体实现代码
}
}
public void RunCaseStudy()
{
Debug.Log($"运行案例研究: {caseStudyName}");
// 在实际项目中,这里会运行两种实现的对比测试
// 测量性能、内存使用、代码复杂度等指标
RunFSMTest();
RunBTTest();
CompareResults();
}
private void RunFSMTest()
{
Debug.Log("运行有限状态机测试...");
if (fsmImplementation != null)
{
// 激活FSM组件并测试
MonoBehaviour[] fsmComponents = fsmImplementation.GetComponents<MonoBehaviour>();
foreach (MonoBehaviour component in fsmComponents)
{
if (component.GetType().Name.Contains("FSM") ||
component.GetType().Name.Contains("State"))
{
Debug.Log($"找到FSM组件: {component.GetType().Name}");
// 运行测试逻辑
}
}
}
}
private void RunBTTest()
{
Debug.Log("运行行为树测试...");
if (btImplementation != null)
{
// 激活行为树组件并测试
BehaviorTreeController btController = btImplementation.GetComponent<BehaviorTreeController>();
if (btController != null)
{
Debug.Log($"找到行为树控制器: {btController.name}");
// 运行测试逻辑
}
}
}
private void CompareResults()
{
Debug.Log("对比测试结果...");
// 在实际项目中,这里会比较两种实现的性能数据
// 包括帧率、内存占用、CPU时间等
Debug.Log("测试完成,详细报告已生成");
}
public List<ComparisonCriteria> GetComparisonResults()
{
return new List<ComparisonCriteria>(comparisonCriteria);
}
public void ExportReport(string filePath)
{
// 生成并导出对比报告
string report = GenerateComparisonReport();
System.IO.File.WriteAllText(filePath, report);
Debug.Log($"报告已导出到: {filePath}");
}
private string GenerateComparisonReport()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("行为树 vs 有限状态机 对比分析报告");
sb.AppendLine($"生成时间: {System.DateTime.Now}");
sb.AppendLine($"案例名称: {caseStudyName}");
sb.AppendLine($"案例描述: {caseDescription}");
sb.AppendLine();
sb.AppendLine("=== 详细对比 ===");
foreach (ComparisonCriteria criteria in comparisonCriteria)
{
sb.AppendLine($"\n[{criteria.criteriaName}]");
sb.AppendLine($"FSM: {criteria.fsmDescription}");
sb.AppendLine($"评分: {criteria.fsmScore}/10");
sb.AppendLine($"BT: {criteria.btDescription}");
sb.AppendLine($"评分: {criteria.btScore}/10");
sb.AppendLine($"推荐: {criteria.recommendation}");
}
// 计算总分
float totalFsmScore = 0f;
float totalBtScore = 0f;
foreach (ComparisonCriteria criteria in comparisonCriteria)
{
totalFsmScore += criteria.fsmScore;
totalBtScore += criteria.btScore;
}
sb.AppendLine("\n=== 总结 ===");
sb.AppendLine($"FSM总分: {totalFsmScore}/{(comparisonCriteria.Count * 10)}");
sb.AppendLine($"BT总分: {totalBtScore}/{(comparisonCriteria.Count * 10)}");
if (totalBtScore > totalFsmScore)
{
sb.AppendLine("总体推荐: 行为树 (Behavior Tree)");
}
else if (totalFsmScore > totalBtScore)
{
sb.AppendLine("总体推荐: 有限状态机 (Finite State Machine)");
}
else
{
sb.AppendLine("总体推荐: 根据具体需求选择");
}
return sb.ToString();
}
}
/// <summary>
/// 混合系统 - 结合FSM和BT的优势
/// </summary>
public class HybridAISystem : MonoBehaviour
{
[System.Serializable]
public class FSMState
{
public string stateName;
public BehaviorTree behaviorTree;
public List<Transition> transitions;
[System.Serializable]
public class Transition
{
public string targetState;
public ConditionNode condition;
}
}
[Header("混合系统配置")]
[SerializeField]
private List<FSMState> states = new List<FSMState>();
[SerializeField]
private string initialState;
[Header("当前状态")]
[SerializeField]
private string currentState;
[SerializeField]
private FSMState currentStateData;
private Blackboard sharedBlackboard;
private bool isActive;
private void Awake()
{
InitializeHybridSystem();
}
private void InitializeHybridSystem()
{
sharedBlackboard = new Blackboard();
isActive = true;
// 初始化所有状态的行为树
foreach (FSMState state in states)
{
if (state.behaviorTree != null)
{
state.behaviorTree.Initialize(gameObject, state.behaviorTree.GetRootNode(), sharedBlackboard);
}
}
// 设置初始状态
if (!string.IsNullOrEmpty(initialState))
{
ChangeState(initialState);
}
else if (states.Count > 0)
{
ChangeState(states[0].stateName);
}
Debug.Log("混合AI系统初始化完成");
}
private void Update()
{
if (!isActive || currentStateData == null)
{
return;
}
// 执行当前状态的行为树
if (currentStateData.behaviorTree != null)
{
currentStateData.behaviorTree.Update();
}
// 检查状态转换
CheckStateTransitions();
}
private void CheckStateTransitions()
{
if (currentStateData == null || currentStateData.transitions == null)
{
return;
}
foreach (FSMState.Transition transition in currentStateData.transitions)
{
if (transition.condition != null)
{
// 初始化条件节点(如果尚未初始化)
if (transition.condition.behaviorTree == null)
{
BehaviorTree tempTree = new BehaviorTree(gameObject, transition.condition, sharedBlackboard);
transition.condition.Initialize(tempTree, sharedBlackboard);
}
// 检查条件
NodeStatus conditionStatus = transition.condition.Evaluate();
if (conditionStatus == NodeStatus.Success)
{
ChangeState(transition.targetState);
break;
}
}
}
}
private void ChangeState(string newStateName)
{
if (currentState == newStateName)
{
return;
}
// 退出当前状态
if (currentStateData != null && currentStateData.behaviorTree != null)
{
currentStateData.behaviorTree.Stop();
}
// 查找新状态
FSMState newState = states.Find(s => s.stateName == newStateName);
if (newState == null)
{
Debug.LogError($"状态不存在: {newStateName}");
return;
}
// 进入新状态
currentState = newStateName;
currentStateData = newState;
if (currentStateData.behaviorTree != null)
{
currentStateData.behaviorTree.Start();
}
Debug.Log($"混合系统状态转换: {currentState} -> {newStateName}");
}
public void SetActive(bool active)
{
isActive = active;
if (isActive && currentStateData != null && currentStateData.behaviorTree != null)
{
currentStateData.behaviorTree.Start();
}
else if (!isActive && currentStateData != null && currentStateData.behaviorTree != null)
{
currentStateData.behaviorTree.Stop();
}
}
public void AddState(string stateName, BehaviorTree behaviorTree)
{
FSMState newState = new FSMState
{
stateName = stateName,
behaviorTree = behaviorTree,
transitions = new List<FSMState.Transition>()
};
states.Add(newState);
if (string.IsNullOrEmpty(initialState))
{
initialState = stateName;
ChangeState(stateName);
}
}
public void AddTransition(string fromState, string toState, ConditionNode condition)
{
FSMState state = states.Find(s => s.stateName == fromState);
if (state != null)
{
state.transitions.Add(new FSMState.Transition
{
targetState = toState,
condition = condition
});
}
}
public string CurrentState
{
get { return currentState; }
}
public Blackboard SharedBlackboard
{
get { return sharedBlackboard; }
}
private void OnDrawGizmosSelected()
{
if (!Application.isPlaying)
{
return;
}
// 绘制当前状态信息
#if UNITY_EDITOR
string info = $"混合AI系统\n";
info += $"当前状态: {currentState}\n";
info += $"状态数量: {states.Count}";
UnityEditor.Handles.Label(
transform.position + Vector3.up * 2.5f,
info
);
#endif
}
}
}
7.1.6 行为树的协同执行机制
协同程序(Coroutine)是Unity中实现异步操作的重要机制,在行为树中可以用来处理需要时间的动作,如移动、等待、动画播放等。
namespace BehaviorTreeSystem
{
/// <summary>
/// 协同动作节点基类 - 支持协同程序的动作
/// </summary>
public abstract class CoroutineActionNode : ActionNode
{
protected Coroutine executionCoroutine;
protected MonoBehaviour coroutineOwner;
public CoroutineActionNode(string name) : base(name)
{
}
public override void Initialize(BehaviorTree tree, Blackboard bb)
{
base.Initialize(tree, bb);
// 获取协同程序的所有者
coroutineOwner = tree.Owner.GetComponent<MonoBehaviour>();
if (coroutineOwner == null)
{
coroutineOwner = tree.Owner.AddComponent<EmptyMonoBehaviour>();
}
}
public override void OnEnter()
{
base.OnEnter();
// 启动协同程序
if (coroutineOwner != null)
{
executionCoroutine = coroutineOwner.StartCoroutine(ExecuteCoroutine());
}
}
public override void OnExit()
{
base.OnExit();
// 停止协同程序
if (executionCoroutine != null && coroutineOwner != null)
{
coroutineOwner.StopCoroutine(executionCoroutine);
executionCoroutine = null;
}
}
public override void OnAbort()
{
base.OnAbort();
// 中止时也停止协同程序
if (executionCoroutine != null && coroutineOwner != null)
{
coroutineOwner.StopCoroutine(executionCoroutine);
executionCoroutine = null;
}
}
public override NodeStatus Execute()
{
// 协同程序模式下,Execute方法只返回当前状态
return isRunning ? NodeStatus.Running : NodeStatus.Success;
}
protected abstract IEnumerator ExecuteCoroutine();
// 完成协同程序的回调
protected void OnCoroutineCompleted(NodeStatus status)
{
if (isRunning)
{
// 设置最终状态并退出
isRunning = false;
// 通知行为树
behaviorTree.RecordNodeExecution(this, status);
OnExit();
}
}
}
/// <summary>
/// 空MonoBehaviour类,用于没有MonoBehaviour的GameObject
/// </summary>
public class EmptyMonoBehaviour : MonoBehaviour
{
// 空类,仅用于承载协同程序
}
/// <summary>
/// 等待节点 - 等待指定时间
/// </summary>
public class WaitNode : CoroutineActionNode
{
private float waitDuration;
private float randomVariance;
public WaitNode(string name, float duration, float variance = 0f) : base(name)
{
waitDuration = duration;
randomVariance = variance;
}
protected override IEnumerator ExecuteCoroutine()
{
// 计算实际等待时间
float actualWaitTime = waitDuration;
if (randomVariance > 0f)
{
actualWaitTime += UnityEngine.Random.Range(-randomVariance, randomVariance);
actualWaitTime = Mathf.Max(0f, actualWaitTime);
}
Debug.Log($"{nodeName}: 等待 {actualWaitTime:F2} 秒");
yield return new WaitForSeconds(actualWaitTime);
OnCoroutineCompleted(NodeStatus.Success);
}
}
/// <summary>
/// 移动到位置节点
/// </summary>
public class MoveToPositionNode : CoroutineActionNode
{
private Vector3 targetPosition;
private float moveSpeed;
private float stoppingDistance;
private string positionKey; // 黑板中位置数据的键名
public MoveToPositionNode(string name, Vector3 position, float speed = 3f,
float stopDistance = 0.5f) : base(name)
{
targetPosition = position;
moveSpeed = speed;
stoppingDistance = stopDistance;
}
public MoveToPositionNode(string name, string positionKey, float speed = 3f,
float stopDistance = 0.5f) : base(name)
{
this.positionKey = positionKey;
moveSpeed = speed;
stoppingDistance = stopDistance;
}
protected override IEnumerator ExecuteCoroutine()
{
// 获取目标位置
Vector3 finalTarget = targetPosition;
if (!string.IsNullOrEmpty(positionKey) && blackboard.HasValue(positionKey))
{
finalTarget = blackboard.GetValue<Vector3>(positionKey);
}
Transform transform = behaviorTree.Owner.transform;
Debug.Log($"{nodeName}: 移动到位置 {finalTarget}");
// 移动循环
while (true)
{
Vector3 direction = (finalTarget - transform.position).normalized;
float distance = Vector3.Distance(transform.position, finalTarget);
if (distance <= stoppingDistance)
{
// 到达目标
OnCoroutineCompleted(NodeStatus.Success);
yield break;
}
// 移动
transform.position += direction * moveSpeed * Time.deltaTime;
// 面向移动方向
if (direction.magnitude > 0.1f)
{
Quaternion targetRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
5f * Time.deltaTime
);
}
yield return null;
}
}
}
/// <summary>
/// 播放动画节点
/// </summary>
public class PlayAnimationNode : CoroutineActionNode
{
private string animationName;
private float animationSpeed;
private bool waitForCompletion;
private Animator animator;
public PlayAnimationNode(string name, string animationName,
float speed = 1f, bool wait = true) : base(name)
{
this.animationName = animationName;
animationSpeed = speed;
waitForCompletion = wait;
}
public override void Initialize(BehaviorTree tree, Blackboard bb)
{
base.Initialize(tree, bb);
// 获取Animator组件
animator = behaviorTree.Owner.GetComponent<Animator>();
}
protected override IEnumerator ExecuteCoroutine()
{
if (animator == null)
{
Debug.LogError($"{nodeName}: 没有找到Animator组件");
OnCoroutineCompleted(NodeStatus.Failure);
yield break;
}
Debug.Log($"{nodeName}: 播放动画 {animationName}");
// 设置动画参数
animator.speed = animationSpeed;
animator.Play(animationName);
if (waitForCompletion)
{
// 等待动画播放完成
yield return new WaitForSeconds(0.1f); // 等待动画开始
while (animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 1f)
{
yield return null;
}
OnCoroutineCompleted(NodeStatus.Success);
}
else
{
// 不等待动画完成
yield return null;
OnCoroutineCompleted(NodeStatus.Success);
}
}
}
/// <summary>
/// 等待条件节点 - 等待某个条件满足
/// </summary>
public class WaitUntilConditionNode : CoroutineActionNode
{
private Func<bool> condition;
private float timeout;
private float checkInterval;
public WaitUntilConditionNode(string name, Func<bool> condition,
float timeout = -1f, float interval = 0.1f) : base(name)
{
this.condition = condition;
this.timeout = timeout;
checkInterval = interval;
}
protected override IEnumerator ExecuteCoroutine()
{
float startTime = Time.time;
Debug.Log($"{nodeName}: 等待条件满足");
while (true)
{
// 检查超时
if (timeout > 0 && Time.time - startTime > timeout)
{
Debug.Log($"{nodeName}: 等待超时");
OnCoroutineCompleted(NodeStatus.Failure);
yield break;
}
// 检查条件
if (condition != null && condition())
{
Debug.Log($"{nodeName}: 条件满足");
OnCoroutineCompleted(NodeStatus.Success);
yield break;
}
// 等待一段时间再检查
yield return new WaitForSeconds(checkInterval);
}
}
}
/// <summary>
/// 并行协同节点 - 同时执行多个协同动作
/// </summary>
public class ParallelCoroutineNode : CompositeNode
{
private List<Coroutine> coroutines;
private MonoBehaviour coroutineOwner;
private Dictionary<BTNode, NodeStatus> childResults;
private bool allChildrenStarted;
public ParallelCoroutineNode(string name) : base(name)
{
coroutines = new List<Coroutine>();
childResults = new Dictionary<BTNode, NodeStatus>();
}
public override void Initialize(BehaviorTree tree, Blackboard bb)
{
base.Initialize(tree, bb);
// 获取协同程序的所有者
coroutineOwner = tree.Owner.GetComponent<MonoBehaviour>();
if (coroutineOwner == null)
{
coroutineOwner = tree.Owner.AddComponent<EmptyMonoBehaviour>();
}
}
public override void OnEnter()
{
base.OnEnter();
childResults.Clear();
allChildrenStarted = false;
// 启动所有子节点的协同程序
foreach (BTNode child in children)
{
if (child is CoroutineActionNode coroutineNode)
{
// 启动协同程序
Coroutine coroutine = coroutineOwner.StartCoroutine(
ExecuteChildCoroutine(coroutineNode)
);
coroutines.Add(coroutine);
childResults[child] = NodeStatus.Running;
}
}
allChildrenStarted = true;
}
private IEnumerator ExecuteChildCoroutine(CoroutineActionNode childNode)
{
// 手动调用子节点的OnEnter来启动协同程序
childNode.OnEnter();
// 等待子节点完成
while (childNode.IsRunning)
{
yield return null;
}
// 获取结果(这里简化处理,实际需要从子节点获取状态)
NodeStatus status = NodeStatus.Success; // 假设成功
childResults[childNode] = status;
}
public override NodeStatus Evaluate()
{
if (!allChildrenStarted)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
// 检查所有子节点的状态
int successCount = 0;
int failureCount = 0;
int runningCount = 0;
foreach (BTNode child in children)
{
NodeStatus status;
if (childResults.ContainsKey(child))
{
status = childResults[child];
}
else
{
status = NodeStatus.Running;
}
switch (status)
{
case NodeStatus.Success:
successCount++;
break;
case NodeStatus.Failure:
failureCount++;
break;
case NodeStatus.Running:
runningCount++;
break;
}
}
// 判断结果
if (runningCount > 0)
{
behaviorTree.SetRunningNode(this);
return NodeStatus.Running;
}
else if (failureCount > 0)
{
// 有子节点失败
return NodeStatus.Failure;
}
else
{
// 所有子节点成功
return NodeStatus.Success;
}
}
public override void OnExit()
{
base.OnExit();
// 停止所有协同程序
foreach (Coroutine coroutine in coroutines)
{
if (coroutineOwner != null)
{
coroutineOwner.StopCoroutine(coroutine);
}
}
coroutines.Clear();
childResults.Clear();
}
public override void OnAbort()
{
base.OnAbort();
// 中止所有子节点
foreach (BTNode child in children)
{
child.OnAbort();
}
}
}
/// <summary>
/// 顺序协同节点 - 按顺序执行协同动作
/// </summary>
public class SequenceCoroutineNode : CompositeNode
{
private Coroutine sequenceCoroutine;
private MonoBehaviour coroutineOwner;
public SequenceCoroutineNode(string name) : base(name)
{
}
public override void Initialize(BehaviorTree tree, Blackboard bb)
{
base.Initialize(tree, bb);
// 获取协同程序的所有者
coroutineOwner = tree.Owner.GetComponent<MonoBehaviour>();
if (coroutineOwner == null)
{
coroutineOwner = tree.Owner.AddComponent<EmptyMonoBehaviour>();
}
}
public override void OnEnter()
{
base.OnEnter();
// 启动顺序执行协同程序
if (coroutineOwner != null)
{
sequenceCoroutine = coroutineOwner.StartCoroutine(ExecuteSequence());
}
}
private IEnumerator ExecuteSequence()
{
for (int i = 0; i < children.Count; i++)
{
BTNode child = children[i];
if (child is CoroutineActionNode coroutineNode)
{
// 执行子节点
coroutineNode.OnEnter();
// 等待子节点完成
while (coroutineNode.IsRunning)
{
yield return null;
}
// 检查子节点状态
// 这里简化处理,假设总是成功
// 实际需要处理失败情况并中断序列
}
else if (child is ActionNode actionNode)
{
// 非协同动作节点,直接执行
NodeStatus status = actionNode.Evaluate();
if (status == NodeStatus.Failure)
{
// 失败则中断序列
break;
}
}
}
// 序列执行完成
// 这里需要通知行为树节点完成
}
public override NodeStatus Evaluate()
{
// 协同程序模式下,Evaluate只返回当前状态
// 实际状态由协同程序控制
return NodeStatus.Running;
}
public override void OnExit()
{
base.OnExit();
// 停止协同程序
if (sequenceCoroutine != null && coroutineOwner != null)
{
coroutineOwner.StopCoroutine(sequenceCoroutine);
sequenceCoroutine = null;
}
}
public override void OnAbort()
{
base.OnAbort();
// 中止所有子节点
foreach (BTNode child in children)
{
child.OnAbort();
}
}
}
}
通过以上完整的行为树系统实现,我们建立了一个功能齐全、模块化、可扩展的行为树框架。这个框架包含了行为树的所有核心组件:节点基类、各种类型的节点(动作、条件、组合、装饰)、黑板系统、子树复用、协同程序支持以及与有限状态机的对比和混合系统。
在接下来的章节中,我们将使用这个框架来构建具体的AI行为树实例,展示如何在商业游戏项目中应用行为树技术。
更多推荐


所有评论(0)