上一篇已经介绍了怎么用Brainiac Designer做行为树,这一篇将会介绍怎么把生成的ai结合到untiy里
首先导出的ai代码拷到untiy里,然后新建一个行为树框加BehaviorTree.cs,定义各种节点,代码比较简单,根本的注释也有了,就不详细讲了,代码如下
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace GameAi
{
public interface IBehaviorTreeNode
{
bool Process(AiController theOwner);
}
/// <summary>
/// 行为框架,具体实现要继承DecoratorNode, ConditionNode, ActionNode, ImpulseNode
/// </summary>
public class BehaviorTreeRoot : IBehaviorTreeNode
{
public IBehaviorTreeNode root = null;
public BehaviorTreeRoot()
{
}
public bool Process(AiController theOwner)
{
return root.Process(theOwner);
}
public void AddChild(IBehaviorTreeNode root)
{
this.root = root;
}
}
/// <summary>
/// 复合节点,不能为叶子节点
/// </summary>
public class CompositeNode : IBehaviorTreeNode
{
protected List<IBehaviorTreeNode> children = new List<IBehaviorTreeNode>();
/// <summary>
/// 由子树实现
/// </summary>
/// <param name="theOwner"></param>
/// <returns></returns>
public virtual bool Process(AiController theOwner)
{
return true;
}
public void AddChild(IBehaviorTreeNode _node)
{
children.Add(_node);
}
public void DelChild(IBehaviorTreeNode _node)
{
children.Remove(_node);
}
public void ClearChildren()
{
children.Clear();
}
}
/// <summary>
/// 修饰类
/// </summary>
public class DecoratorNode : IBehaviorTreeNode
{
protected IBehaviorTreeNode child = null;
/// <summary>
/// 由子类实现
/// </summary>
/// <param name="theOwner"></param>
/// <returns></returns>
public virtual bool Process(AiController theOwner)
{
return child.Process(theOwner);
}
public void Proxy(IBehaviorTreeNode _child)
{
child = _child;
}
}
/// <summary>
/// 脉冲类
/// </summary>
public class ImpulseNode : IBehaviorTreeNode
{
protected IBehaviorTreeNode child = null;
/// <summary>
/// 由子类实现
/// </summary>
/// <param name="theOwner"></param>
/// <returns></returns>
public virtual bool Process(AiController theOwner)
{
return child.Process(theOwner);
}
public void Proxy(IBehaviorTreeNode _child)
{
child = _child;
}
}
/// <summary>
/// 叶子节点,条件判断类
/// </summary>
public class ConditionNode : IBehaviorTreeNode
{
/// <summary>
/// 由子类实现
/// </summary>
/// <param name="theOwner"></param>
/// <returns></returns>
public virtual bool Process(AiController theOwner)
{
return false;
}
}
/// <summary>
/// 叶子节点,具体行为实现类
/// </summary>
public class ActionNode : IBehaviorTreeNode
{
/// <summary>
/// 由子类实现
/// </summary>
/// <param name="theOwner"></param>
/// <returns></returns>
public virtual bool Process(AiController theOwner)
{
return false;
}
}
/// <summary>
/// 选择节点
/// 遇到一个child执行后返回true,停止迭代
/// 本node向自己的父节点返回true
/// 如果所有的child都返回false,本node向自己父节点返回false
/// </summary>
public class SelectorLinear : CompositeNode
{
public override bool Process(AiController theOwner)
{
foreach (IBehaviorTreeNode _node in children)
{
if (_node.Process(theOwner))
{
return true;
}
}
return false;
}
}
/// <summary>
/// 遇到一个child执行后返回false,停止迭代
/// 本node向自己的父节点返回false
/// 如果所有的child都返回true,本node向自己父节点返回true
/// </summary>
public class SequenceLinear : CompositeNode
{
public override bool Process(AiController theOwner)
{
foreach (IBehaviorTreeNode _node in children)
{
if (!_node.Process(theOwner))
{
return false;
}
}
return true;
}
}
/// <summary>
/// 修饰类取反
/// </summary>
public class DecoratorNot : DecoratorNode
{
public override bool Process(AiController theOwner)
{
return !base.Process(theOwner);
}
}
}
打开Brainiac Designer导出的代码可以看到,里面只是添加一些节点,但是节点要干什么,里面没有实现了,所以我们要在untiy里实现各个节点的行为
首先是Attack.cs
using UnityEngine;
using System.Collections;
namespace GameAi
{
public class Attack : ActionNode
{
public Attack()
{
}
public override bool Process(AiController theOwner)
{
theOwner.Attack();
return true;
}
}
}
CanNotFindPlayer.cs
using UnityEngine;
using System.Collections;
namespace GameAi
{
public class CanNotFindPlayer : ConditionNode
{
public CanNotFindPlayer()
{
}
public override bool Process(AiController theOwner)
{
return theOwner.CanNotFindPlayer();
}
}
}
Chase.cs
using UnityEngine;
using System.Collections;
namespace GameAi
{
public class Chase : ActionNode
{
public Chase()
{
}
public override bool Process(AiController theOwner)
{
theOwner.Chase();
return true;
}
}
}
FindPlayer.cs
using UnityEngine;
using System.Collections;
namespace GameAi
{
public class FindPlayer : ConditionNode
{
public FindPlayer()
{
}
public override bool Process(AiController theOwner)
{
return theOwner.FindPlayer();
}
}
}
IsPlayerInAttackRange.cs
using UnityEngine;
using System.Collections;
namespace GameAi
{
public class IsPlayerInAttackRange : ConditionNode
{
public IsPlayerInAttackRange()
{
}
public override bool Process(AiController theOwner)
{
return theOwner.IsPlayerInAttackRange();
}
}
}
Patrol.cs
using UnityEngine;
using System.Collections;
namespace GameAi
{
public class Patrol : ActionNode
{
public int PatrolRange = 0;
public Patrol()
{
}
public override bool Process(AiController theOwner)
{
theOwner.Patrol(PatrolRange);
return true;
}
}
}
行为树的各个节点已经定义好, 我们还需要定义一个Ai控制器AiController,Ai的的具体逻辑都是写在这里,根据名称用反射去决定调用哪个ai行为树,行为树的节点的具体行为只是调用这里的方法
AiController.cs
using UnityEngine;
using System.Collections;
using GameAi.Manager;
namespace GameAi
{
public class AiController : MonoBehaviour
{
private BehaviorTreeRoot _aiBehaviorTree;
private string _aiBTreeName = "ai_1";
private float _aiIntervalTick = 0f;
private float _aiIntervalTime = 0.5f;
private void RegisterAiBehaviorTree()
{
_aiBehaviorTree = BTreeManager.instance.GetBTree(_aiBTreeName);
}
// Use this for initialization
void Start()
{
RegisterAiBehaviorTree();
}
void FixedUpdate()
{
//ai执行时间间隔处理
if (_aiIntervalTick == -1f)
{
_aiBehaviorTree.Process(this);
_aiIntervalTick = 0f;
}
else
{
_aiIntervalTick += Time.deltaTime;
if (_aiIntervalTick >= _aiIntervalTime)
{
_aiBehaviorTree.Process(this);
_aiIntervalTick = 0f;
}
}
}
public void Chase()
{
Debug.Log("==========Chase======= ");
}
public void Attack()
{
Debug.Log("=========Attack========");
}
public void Patrol(int patrolRange)
{
Debug.Log("=========Patrol========" + patrolRange);
}
public bool FindPlayer()
{
Debug.Log("=========FindPlayer========");
if (Random.Range(0, 10) > 5)
{
return false;
}
return true;
}
public bool IsPlayerInAttackRange()
{
Debug.Log("=========IsPlayerInAttackRange========");
if (Random.Range(0, 10) > 5)
{
return false;
}
return true;
}
public bool CanNotFindPlayer()
{
Debug.Log("=========CanNotFindPlayer========");
if (Random.Range(0, 10) > 5)
{
return false;
}
return true;
}
}
}
整个Ai框架到这里已经定义好了,最后把AiController拖到一个GameObject上,执行就可以看到运行结果了
最后附上整个工程文件:源码
简单的Ai也可以用FSM实现,这里不细讲附上一个用FSM实现的Ai工程:源码