行为树简易敌人AI
前言:
有些天没更新新文章了,主要是最近科一有些头疼,而且最近琢磨这个行为树代码有些难受,但是终于熬出头了,MonoGame的系列会继续更新的,今天不说别的就说困扰我两三天的行为树
有限状态机 -》分层状态机 -》 行为树:
首先我们得先理解一个概念:有限状态机,在游戏开发中因为团队协作开发,和编程效率的缘故,人们在游戏编程模式中发明了一种编程模式:有限状态机,他的逻辑简单而且编写起来也很优雅,我非常喜欢这种游戏编程模式,在我早期接触游戏开发的时候百分之九十九的项目都是使用有限状态机来编写玩家操控和怪物AI,但是很快就会遇到难题,普通小怪倒还好,简单的行为模式时的有限状态机来编写逻辑清晰没什么缺点,但是一旦到了Boss级别敌人逻辑复杂,技能繁多,如果用有限状态机来处理的话机会面临以下问题:状态切换太过复杂,状态切换条件繁多,从逻辑上来说这个有限状态机变不再适合开发这种技能繁多的BossAI了,聪明的你想到:欸!要是把意思相同的逻辑封装成一个集合,比如:移动,站立归为Move层,魔法攻击,普通攻击,等等攻击归为战斗层,跳跃,下落归为跳跃层等等,这样我们的逻辑就清晰了很多了,把所有状态设为二级节点,但是这样依旧不是最佳选择,那么我们本篇文章的:行为树
行为树:
1.行为树是为了简化游戏的逻辑,在很多游戏开发过程中人们都会选择行为树来开发这款游戏的AI,甚至可以说一款游戏的大多数时间和代码都是来源游戏AI,行为树都是由一个个节点组成的主要包括:
- 叶子节点(Node)
- 顺序节点(SequenceNode)
- 选择节点 (SelectorNode)
- 装饰节点 (DecoratorNode)
以上这些节点都是在游戏开发中常用的节点,当然不妨还有一些扩展节点但最为常用的还是这些节点的状态,每个节点都由三种状态:
- Success
- Failure
- Running
叶子节点(Node):
所谓叶子节点也是树的最底部,也就是他没有子节点,叶子节点没有子节点,这也就意味着叶子节点必须得执行游戏中Boss/Monster的具体逻辑,因为他没有子节点无法再继续往下遍历了,所以我们必须得使用叶子节点来实现Boss的具体功能;
顺序节点(SequenceNode):
顺序节点是一个父级节点,他会一次从左向右遍历所有的子树,一旦遍历到返回失败节点返回失败,就意味着这个节点失败了。
选择节点 (SelectorNode):
这种节点和顺序节点一样是一种父级节点,但是不同的是这个节点会选择,从左往右数的子树中第一个返回成功或者运行的节点。
装饰节点 (DecoratorNode):
这种节点通常都是再Sequence节点下的前置节点,通常用来判断条件,一条条件不满足直接返回失败,那么相应的Sequence节点也会返回失败;
代码部分:
首先我们得先完成一个示例的简单AI逻辑来实践一下,这个AI逻辑代码很简单就是一个Boss在Idle, Walk, Attack三个形态之间的切换,会了这个就相当与只要你画出行为树的逻辑图,那么搞定这个也就简单起来了:
演示:

首先我们得先写一下基础的节点代码:
BTNode
using System.Collections.Generic;
namespace ETFramework
{
public class BTNode
{
protected NodeState state;
public BTNode parent;
public List<BTNode> children = new List<BTNode>();
public BTNode()
{
parent = null;
}
public BTNode(List<BTNode> children)
{
foreach (BTNode child in children)
AddNode(child);
}
private void AddNode(BTNode node)
{
node.parent = this;
children.Add(node);
}
public virtual NodeState Evaluate() => NodeState.Failure;
}
}
SelectorNode
using System.Collections;
using System.Collections.Generic;
namespace ETFramework
{
public class SelectorNode : BTNode
{
public SelectorNode() : base() {
}
public SelectorNode(List<BTNode> children) : base(children) {
}
public override NodeState Evaluate()
{
foreach (BTNode node in children)
{
switch (node.Evaluate())
{
case NodeState.Failure:
continue;
case NodeState.Success:
state = NodeState.Success;
return state;
case NodeState.Running:
state = NodeState.

最低0.47元/天 解锁文章
3233

被折叠的 条评论
为什么被折叠?



