行为树行为树行为树

行为树由一个个节点组成

  • 结构:树状结构
  • 运行流程:从根节点开始自顶向下往下遍历,每经过一个节点就执行节点对应的功能。

我们规定,每个节点都提供自己的excute函数,返还执行失败/成功结果。
然后根据不同节点的执行结果,遍历的路径随之改变,而这个过程中遍历到什么节点就执行excute函数。

主流的行为树实现,将节点主要分为四种类型。
下面列举四种节点类型及其对应excute函数的行为:

  • 控制节点(非叶节点),用于控制如何执行子节点(控制遍历路径的走向)。
  • 条件节点(叶节点),行为是提供条件的判断结果。
  • 行为节点(叶节点):

    行为节点是代表智能体行为的叶节点,其执行函数一般位该节点代表的行为。

    行为节点的类型是比较多的,毕竟一个智能体的行为是多种多样的,而且都得根据自己的智能体模型定制行为节点类型。
    这里列举一些行为:站立,射击,移动,跟随,远离,保持距离....

  • 装饰节点 :行为是修饰(辅助)其他三类节点。例如执行结果取反/并/或,重复执行若干次等辅助修饰节点的作用,均可做成装饰节点。

持续行为

一些行为是可以瞬间执行完的(例如转身?),
而另外一些动作则是执行持续一段时间才能完成的(例如攻击从启动攻击行为到攻击结算要1秒左右的时间)。

因此,这些持续行为节点的excute函数里,应先启动智能体的持续行为,然后挂起该行为树(更通俗地说是暂停行为树),等到持续时间结束才允许退出excute函数并继续遍历该行为树。
为了支持挂起行为树而不影响其他CPU代码执行,我们往往需要利用协程等待该其行为完成而不产生CPU阻塞,而且开销远低于真正的线程。
此外,一般是一个行为树对应维护一个协程。

条件节点:

执行节点不会总是一帆风顺的,有成功也总会有失败的结果。
这就是引入前提条件的作用——
满足前提条件,才能成功执行行为,返还执行成功结果。否则不能执行行为,返还执行失败结果。

但是每个节点的前提总会不同,或有些没有前提(换句话说总是能满足前提)。

一个可行的做法是:让行为节点含有bool函数对象(或函数接口)。这样对于不同的逻辑条件,就可以写成不同的bool函数,绑定给相应的行为节点。

现在比较成熟的做法是把前提条件抽象分离成新的节点类型,称之为条件节点
将其作为叶节点混入行为树,提供条件的判断结果,交给控制节点决策。

它相当模块化,更加方便适用。

这里的Sequence节点是上面控制节点的一种:能够让其所有子节点依次运行,若运行到其中一个子节点失败则不继续往下运行。
这样可以实现出不满足条件则失败的效果。

相比较传统的有限状态机:

  • 易脚本化/可视化的决策逻辑
  • 逻辑和实现的低耦合,可复用的节点
  • 可以迅速而便捷的组织较复杂的行为决策

这里并不是说有限状态机一无所用:

  • 状态机可以搭配行为树:状态机负责智能体的身体状态,行为树则负责智能体的智能决策。这样在行为树做决策前,得考虑状态机的状态。
  • 状态机适用于简单的AI:对于区区需两三个状态的智能,状态机解决绰绰有余。
  • 状态机运行效率略高于行为树:因为状态机的运行总是在当前状态开始,而行为树的运行总在根开始,这样就额外多了一些要遍历的节点(也就多了一些运行开销)。

在《杀手:赦免》的人群系统里,人群的状态机AI只有简单的3种状态,由于人群的智能体数量较多,若采取行为树AI,则会大大影响性能。

代码示例:

enum Status {
    SUCCESS,
    FAILURE,
    RUNNING
}

// 基础节点类
abstract class Node {
    abstract execute(): Status;
}

// 非叶节点类,用于容纳子节点
abstract class CompositeNode extends Node {
    protected children: Node[] = [];

    addChild(child: Node): void {
        this.children.push(child);
    }
}

// 选择器节点:依次执行子节点,直到其中一个成功为止
class SelectorNode extends CompositeNode {
    execute(): Status {
        for (const child of this.children) {
            const status = child.execute();
            if (status === Status.SUCCESS) {
                return Status.SUCCESS;
            }
        }
        return Status.FAILURE;
    }
}

// 序列节点:依次执行子节点,直到其中一个失败为止
class SequenceNode extends CompositeNode {
    execute(): Status {
        for (const child of this.children) {
            const status = child.execute();
            if (status === Status.FAILURE) {
                return Status.FAILURE;
            }
        }
        return Status.SUCCESS;
    }
}

// 条件节点:判断某个条件是否满足,并返回结果
abstract class ConditionNode extends Node {
    abstract check(): boolean;

    execute(): Status {
        return this.check() ? Status.SUCCESS : Status.FAILURE;
    }
}

// 行为节点:执行具体的动作,并返回结果
abstract class ActionNode extends Node {
    abstract performAction(): boolean;

    execute(): Status {
        return this.performAction() ? Status.SUCCESS : Status.FAILURE;
    }
}

// 装饰节点:用于修改其他节点的行为,通常只有一个子节点
abstract class DecoratorNode extends Node {
    protected child: Node;

    constructor(child: Node) {
        super();
        this.child = child;
    }
}

// 反转节点:将子节点的结果反转
class InverterNode extends DecoratorNode {
    execute(): Status {
        const status = this.child.execute();
        if (status === Status.SUCCESS) {
            return Status.FAILURE;
        } else if (status === Status.FAILURE) {
            return Status.SUCCESS;
        } else {
            return status;
        }
    }
}

// 重复执行装饰节点:重复执行子节点指定的次数,或直到满足某个条件
class RepeaterNode extends DecoratorNode {
    private maxRepeats: number;
    private stopOnSuccess: boolean;
    private stopOnFailure: boolean;

    constructor(child: Node, maxRepeats: number, stopOnSuccess: boolean = false, stopOnFailure: boolean = false) {
        super(child);
        this.maxRepeats = maxRepeats;
        this.stopOnSuccess = stopOnSuccess;
        this.stopOnFailure = stopOnFailure;
    }

    execute(): Status {
        let count = 0;
        while (this.maxRepeats === -1 || count < this.maxRepeats) {
            const status = this.child.execute();
            if (this.stopOnSuccess && status === Status.SUCCESS) {
                return Status.SUCCESS;
            }
            if (this.stopOnFailure && status === Status.FAILURE) {
                return Status.FAILURE;
            }
            count++;
        }
        return Status.SUCCESS;
    }
}

// 判断敌人是否在范围内的条件节点
class IsEnemyInRange extends ConditionNode {
    check(): boolean {
        // 判断敌人是否在范围内
        return Math.random() < 0.5; // 50% 概率敌人在范围内
    }
}

// 追击敌人的行为节点
class ChaseEnemy extends ActionNode {
    performAction(): boolean {
        console.log("Chasing the enemy!");
        return true; // 假设追击成功
    }
}

// 攻击敌人的行为节点
class AttackEnemy extends ActionNode {
    performAction(): boolean {
        console.log("Attacking the enemy!");
        return true; // 假设攻击成功
    }
}

// 创建行为树
const root = new SelectorNode();

const sequence = new SequenceNode();
root.addChild(sequence);

const condition = new IsEnemyInRange();
sequence.addChild(condition);

const chase = new ChaseEnemy();
const repeater = new RepeaterNode(chase, 3); // 重复执行ChaseEnemy 3次
sequence.addChild(repeater);

const attack = new AttackEnemy();
sequence.addChild(attack);

// 执行行为树
const status = root.execute();
console.log(`Behavior tree execution status: ${Status[status]}`);


 

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值