五邑隐侠,本名关健昌,10年游戏生涯,现隐居五邑。本系列文章以TypeScript为介绍语言。

本篇介绍行为树。在RPG游戏中,地图上存在一些剧情NPC,不同的剧情下,NPC的行为会不一样。这些NPC的行为可以通过行为树进行管理。行为树是在固有行为集下,进行行为抉择的AI算法。行为树包括数据解析、逻辑控制、行为执行三部分。

行为树数据由节点组成,每个节点有对应的行为类型、参数、返回值。节点有一个子节点数组,通过这种方式将节点组织成树状。

export class BehaviorNode {
    private type: number = 0;
    private params: any = null;
    private retVal: any = null;
    private subBehaviors: Array<BehaviorNode> = [];
}

  

逻辑控制节点都有子节点,逻辑控制指的是跟编程类似的if条件判断、while循环、串行执行、并行执行等。if行为如果返回true,执行子节点行为,子行为结束则整体行为结束。while行为如果返回true,执行子节点行为,如果子节点结束,重置子节点重新执行。串行行为,子节点一条一条的依次执行,子节点结束则整体结束。并行行为,子节点同时执行,子节点结束则整体结束。

cocos creator主程入门教程(十一)—— 行为树-LMLPHP

行为树的叶节点是实际行为执行的节点,在开发一款RPG游戏时,需要根据剧情需要,提炼出角色的细粒行为,例如行走、对话、播放表情、切换动画、触发战斗等。一般地,RPG都会开发一个对应的剧情编辑器,对地图上的NPC进行行为设定,导出对应行为的参数。游戏加载这些数据,解析生成行为树,NPC每帧执行行为树,叶节点行为有对应的执行方法,方法的参数为行为节点的参数。

private _parseWalkData(): BehaviorNode {
    // TODO 二进制数据解析为json
}

  

public execBehavior(b: BehaviorNode): void {
    if (!b) {
        return;
    }

    switch(b.type) {
        case BehaviorType.WALK:
            this.execWalk(b);
            break;
    }
}

  

private _execWalk(b: BehaviorNode): void {
    let actorId = b.params.id;
    let destGridX = b.params.destGridX;
    let destGridY = b.params.destGridY;

    let actor = map.getActor(actorId);
    let curGridX = actor.gridX;
    let curGridY = actor.gridY;
    let loadGrids = AStar.findLoad(curGridX, curGridY, destGridX, destGridY);
    actor.setLoad(loadGrids);
}

  

一般地,游戏地图中的物件都可以挂载行为树,地图本身、角色、地图物品等,将一个剧情的复杂行为,分拆到每一个地图物件上,通过剧情任务作为条件区分触发,简化行为的组织。程序员只负责将策划的设定提取出细粒行为,编写对应的数据解析和执行方法,由策划使用编辑器编辑数据,由数据驱动剧情的推进。

行为树先说到这里,下一篇我们将介绍有限状态机。

03-03 17:34