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

 

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

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

  1. export class BehaviorNode {
  2. private type: number = 0;
  3. private params: any = null;
  4. private retVal: any = null;
  5. private subBehaviors: Array<BehaviorNode> = [];
  6. }

  

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

 

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

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

  

  1. public execBehavior(b: BehaviorNode): void {
  2. if (!b) {
  3. return;
  4. }
  5.  
  6. switch(b.type) {
  7. case BehaviorType.WALK:
  8. this.execWalk(b);
  9. break;
  10. }
  11. }

  

  1. private _execWalk(b: BehaviorNode): void {
  2. let actorId = b.params.id;
  3. let destGridX = b.params.destGridX;
  4. let destGridY = b.params.destGridY;
  5. let actor = map.getActor(actorId);
  6. let curGridX = actor.gridX;
  7. let curGridY = actor.gridY;
  8. let loadGrids = AStar.findLoad(curGridX, curGridY, destGridX, destGridY);
  9. actor.setLoad(loadGrids);
  10. }

  

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

 

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

版权声明:本文为niudanshui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/niudanshui/p/10464786.html