赞
踩
行为树(Behavior Trees)是一种在游戏开发中广泛使用的AI设计模式,主要用于描述AI的行为和决策过程,实现更加智能和自然的游戏AI。它由多个节点组成,每个节点代表一个行为或决策,按照特定的方式连接在一起,形成一个树状结构。
在行为树中,根节点是AI的起点,通过遍历子节点来决策AI的行为。节点有以下三种状态:成功(Success)、失败(Failure)和运行(Running)。前两个通知其父节点其操作是成功还是失败。第三种意味着尚未确定成功或失败,并且该节点仍在运行。下次树被选择时,该节点将再次被选择,此时它将再次有机会成功,失败或继续运行。一般行为树还会携带一个Blackboard,用于存储节点的共享数据。
行为树的节点有以下几种主要原型:
组合控制节点(Composite):一种将多个子节点组合在一起的节点,用于实现复杂的行为和决策逻辑。主要包括顺序节点(Sequencer)和选择节点(Selector)。顺序节点按顺序依次执行子节点,直到所有子节点都返回成功或者任意一个子节点返回失败为止,当有子节点返回失败则停止不再执行后续子节点。选择节点按照顺序执行子节点,当某个子节点返回成功时,停止执行并返回成功。
修饰节点(Decorator):一种特殊的节点,它不执行具体的行为或决策,而是修饰其它节点的行为或决策。主要包括逆变节点(Inverter)和重复节点(Repeater)。逆变节点可以将子节点的结果倒转,比如子节点返回了失败,则这个修饰节点会向上返回成功,以此类推。重复节点重复执行其子节点指定的次数或者一直重复执行,直到其子节点返回成功或者失败。
叶节点(Leaf):树的最末端,执行具体行为的节点。
行为树通过模拟树状结构来描述AI的行为和决策过程,使得AI的行为更加灵活、自然和智能。
代码实现
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { public class BehaviourTree : MonoBehaviour { private Node root = null; private Blackboard blackboard; public Node Root { get { return root; } set { root= value; } } void Start() { Init(); } void Update() { if(root!=null&& gameObject!=null) { root.Evaluate(gameObject.transform,blackboard); } } protected virtual void Init() { blackboard = new Blackboard(); } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { //行为树共享数据 public class Blackboard { private Dictionary<string,object> Data; public Blackboard() { Data = new Dictionary<string, object>(); } //获取数据 public T Get<T>(string key) { if(Data.ContainsKey(key)) { return (T)Data[key]; } return default; } //添加数据 public void Add<T>(string key,T value) { if(Data.ContainsKey(key)) { Data[key] = value; } else { Data.Add(key,value); } } //删除数据 public void Remove(string key) { if(Data.ContainsKey(key)) { Data.Remove(key); } else { Debug.Log("数据不存在 "+key); } } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { //状态类型 public enum Status { Running, //运行中 Failure, // 失败 Success, //成功 } //节点基类 public abstract class Node { protected Node parent; protected Status status; Status Status { get { return status; } set { status = value; } } public Node() { } //声明节点状态返回方法 public abstract Status Evaluate(Transform transform,Blackboard blackboard); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { //复合节点类 public abstract class Composite : Node { //子节点列表 protected List<Node> children = new List<Node>(); protected int index;//子节点下标计数 protected Composite(List<Node> children) { index = 0; foreach(var child in children) { this.children.Add(child); } } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { //修饰器节点 public abstract class Decorator : Node { //子节点列表 protected List<Node> children; protected Decorator(List<Node> children) { children = new List<Node>(){}; foreach(var child in children) { this.children.Add(child); } } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { //选择节点,所有子节点都为失败则失败 public class Selector : Composite { public Selector(List<Node> children) : base(children) { } //所有子节点都为失败则失败 public override Status Evaluate(Transform transform, Blackboard blackboard) { if(index>=children.Count) { index = 0; return Status.Success; } var status = children[index].Evaluate(transform,blackboard); switch(status) { case Status.Success: index = 0; return Status.Success; case Status.Failure: index+=1; if(index>=children.Count) { index = 0; return Status.Failure; } return Status.Running; case Status.Running: return Status.Running; default: return Status.Failure; } } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { //顺序节点,所有子节点成功才成功 public class Sequencer : Composite { public Sequencer(List<Node> children) : base(children) { } //所有子节点成功才成功 public override Status Evaluate(Transform transform, Blackboard blackboard) { if(index>=children.Count) { index = 0; return Status.Success; } var status = children[index].Evaluate(transform,blackboard); switch(status) { case Status.Success: index+=1; if(index>=children.Count) { index = 0; return Status.Success; } return Status.Running; case Status.Failure: return Status.Failure; case Status.Running: return Status.Running; default: return Status.Failure; } } } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
namespace BehaviourTree
{
//任务节点,这里会处理对象具体行为逻辑(叶节点)
public abstract class Task : Node
{
}
}
简单使用
实现敌人在两点之间巡逻,人物靠近会变红温并停止移动,人物远离时继续巡逻
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; using System.ComponentModel.Design.Serialization; using System.Linq; namespace BehaviourTree { public class EnemyBT : BehaviourTree { Vector3 aPos = new Vector3(4.07999992f,-2.21000004f,-2); Vector3 bPos = new Vector3(4.07999992f,1.65999997f,-2) protected override void Init() { //调用基类初始化 base.Init(); //创建变红节点 TurnRed turnRed = new TurnRed(); //创建巡逻节点 Patrol patrol = new Patrol(aPos,bPos); //创建查找节点 FindObject findObject = new FindObject(); //创建侦查节点子节点序列 Node[] spyChildren = {findObject,turnRed}; //创建顺序节点用于执行侦查行为 EnemySequencer enemySequencer = new EnemySequencer(spyChildren.ToList()); //创建根节点子节点序列 Node[] selectorChildren = {enemySequencer,patrol}; //创建选择节点用于处理侦查和巡逻行为 EnemySelector enemySelector = new EnemySelector(selectorChildren.ToList()); //将选择节点设置为根节点 Root = enemySelector; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { public class EnemySelector : Selector { public EnemySelector(List<Node> children) : base(children) { } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; namespace BehaviourTree { public class EnemySequencer : Sequencer { public EnemySequencer(List<Node> children) : base(children) { } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; using DG.Tweening; namespace BehaviourTree { public class FindObject : Task { float radius = 5f; int layer = 512; public override Status Evaluate(Transform transform, Blackboard blackboard) { Collider2D obj = Physics2D.OverlapCircle(transform.position,radius,layer); if(obj!=null) { return Status.Success; } transform.gameObject.GetComponent<SpriteRenderer>().DOColor(Color.white,1); return Status.Failure; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; using DG.Tweening; namespace BehaviourTree { //在aPoint和bPoint之间来回移动 public class Patrol : Task { Vector3 aPoint; Vector3 bPoint; float speed = 4f; Vector3 target; public Patrol(Vector3 aPos,Vector3 bPos) { aPoint = aPos; bPoint = bPos; target = aPoint; } public override Status Evaluate(Transform transform, Blackboard blackboard) { if(Vector2.Distance(transform.position,target)<0.1f) { if(target == aPoint) { target = bPoint; } else { target = aPoint; } } else { transform.position = Vector2.MoveTowards(transform.position,target,Time.deltaTime*speed); } return Status.Success; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using BehaviourTree; using DG.Tweening; namespace BehaviourTree { //变红 public class TurnRed : Task { Vector3 bPoint; public override Status Evaluate(Transform transform, Blackboard blackboard) { transform.gameObject.GetComponent<SpriteRenderer>().DOColor(Color.red,1); return Status.Success; } } }
总结
作为常用的AI设计模式,行为树相比有限状态机在实现复杂AI上更有优势。行为树可以模仿人类思维过程,先做什么,再在做什么。并且行为树拥有多种控制节点和修饰节点,节点之间相互组合可实现多种效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。