Quantcast
Channel: Cocos中文社区 - 最新主题
Viewing all articles
Browse latest Browse all 90494

Behavior Creator 行为树可视化编辑器

$
0
0

Behavior Creator 行为树可视化编辑器

  • 这是一款为 CocosCreator 深度定制的行为树可视化编辑器插件
  • 已实现 SelectorSequenceParallel 三种组合节点
  • 已实现 ConditionalDecorator 两种装饰器
  • 已实现 Service 服务类型
  • 已实现 Task 任务类型
  • 支持自定义节点注册到行为树编辑器
  • 支持类属性差异化更新
  • 支持节点生命周期 onEnableonUpdateonDisable 等通用事件委托

注意

  • 仅支持在 CocosCreator v3.3.0 及以上版本中使用

效果预览

快速开始

  • CocosCreator 编辑器菜单 扩展 --> 商城 中搜索 BehaviorCreator 即可找到该插件,购买后下载到本地

  • 导入插件 oreo-behavior-creator 并启用

    image-20220427172931847

  • 资源管理器 面板中看到 oreo-behavior-creator 运行时 已载入,则表示插件导入成功

    image-20220427173208187

  • 注意,因插件需要导入运行时脚本,在CocosCreator编辑器已打开状态下可能会出现以下错误,此时需要重启编辑器

插件入口

  • 行为树编辑器是由 json 数据驱动的,其入口已集成到 BehaviorTree 组件的属性检查器面板,可通过以下方式启动

    1. 新建空节点,在节点上挂载 BehaviorTree 组件

    2. 新建内容为空{}json资源,并关联到 BehaviorTreeJsonAsset 属性。点击 Edit Behavior 即可打开行为树编辑器

加载示例

  • 在运行时目录extensions\oreo-behavior-creator\runtime\examples\data 中提供了一些简单示例,可以通过 Load 菜单加载到行为树编辑区,Save 保存后下一步运行查看效果。

运行效果

  • BehaviorTree 组件默认是没有启用 LogTaskChanges 属性的,我们先勾选以便在控制台输出 log。

    注:当行为树某次执行结果不是 Running 状态时,本次运行结束。如果需要重新开始,需要勾选 RestartWhenComplete

示例分析

巡逻行为分析

  • 我们设定一次巡逻主要包括以下逻辑

    1. 在指定区域目标点之间来回移动

      通用 Task 任务节点

    2. 到达指定点后原地休息等待一段时间

      Wait 任务节点

  • 由于上述是一个连续有序的行为,因此需要将它们挂载到 Sequence 父节点

    Sequence 序列节点

  • 整体巡逻行为如图所示

场景搭建

代码逻辑

  • 随机移动

    在巡逻行为树结构中,随机移动 节点是一个通用 Task 任务节点,需要我们定制 onUpdate 任务更新逻辑。

    新建 AIEnemy.ts 组件类并实现找点随机移动逻辑,挂载到 AIEnemy 场景节点上。主要逻辑包含两点:

    1、到达目标点时返回 Success 表示成功,由父节点 Sequence 顺序执行下一个子节点的行为,即 原地休息

    2、未到达目标点时返回 Running 表示任务还在持续,由父节点 Sequence 下一次 tick 继续执行

    具体实现如下:

    onRandomMove(){
        this._playAnim("run", 1);
    
        //这里为了方便,只是按点索引顺序移动
        let point = this.patrolPoints[this._index];
        //自身点位置
        pos1.set(this.target.position);
        //目标点位置
        pos2.set(point.position);
    	//朝向
        this.target.lookAt(pos2);
    
        //目标点达标与否阈值判断
        if(Vec3.distance(pos1, pos2) < 0.1){
            this._index++;
            if(this._index>=this.patrolPoints.length){
                this._index = 0;
            }
    
            this._playAnim("idle");
            //到达目标点时返回成功,由父节点 `Sequence` 顺序执行下一个子节点的行为,即 `原地休息`
            return bt.BehaviorStatus.Success;
        }
        else{
            let pos = this.lerp(out, pos1, pos2, 0.02);
            this.target.setPosition(pos);  
    
    		//未到达目标点时返回 Running ,由父节点 `Sequence` 下一次 tick 继续执行
            return bt.BehaviorStatus.Running;  
        }
    }
    
  • 原地休息

    这是一个内置 Wait 任务节点,主要作用就是在指定时间内任务直接返回 Running 状态,表示任务还在持续,时间到达后返回 Success 表示任务完成。

    Wait 任务有一个 duration 属性,表示任务持续时间。这是一个 SharedVariable 共享变量属性,与Blackboard黑板变量关联。

逻辑绑定

  • 我们先来指定 原地休息 时间

    新建一个 SharedNumber 数字类型的黑板共享变量,值设定为 2,并指定给 duration 属性,表示原地休息 2 秒

  • 绑定 随机移动 任务的 onUpdate 委托逻辑。

    如图,将 onUpdate 逻辑绑定到 AIEnemy 组件的 onRandomMove 方法

    Delegate 委托逻辑绑定与 CocosCreator 内置按钮事件绑定过程相似

运行效果

  • 首次运行效果如下

  • 我们发现AI 移动到指定目标点且原地休息结束后,并没有继续移动到下一个目标点。这是因为,对于本次行为来说,Wait 执行结束并返回 Success 状态,表示行为树已经全部执行完毕。如果需要重新开始,只需勾选 BehaviorTree 组件上的 RestartWhenComplete

    image-20220428000209459

  • 最终效果如下

追逐行为分析

  • 我们设定一次追逐主要包括以下逻辑

    1. 当玩家出现在 AIEnemy 的感应区域内时,AIEnemy 立即移动并靠近玩家

      通用 Task 任务节点

    2. 当玩家被追逐达到受击范围时,AIEnemy 发动一次攻击。我们设定一次攻击包含实际攻击和技能CD两个任务。

      Sequence 序列节点,通用 Task 任务节点、Wait 任务节点

  • 由于靠近一次攻击 是区分条件执行(不在受击范围就靠近,在受在范围就攻击),即一次只会执行一个分支,因此需要将它们挂载到 Selector 父节点

    Selector 序列节点

  • 此时追逐玩家行为如图所示

场景搭建

代码逻辑

  • 靠近

    靠近 节点也是一个通用 Task 任务节点,需要我们定制 onUpdate 任务更新逻辑。

    更新 AIEnemy.ts 组件类并实现相关逻辑。主要逻辑包含:

    1、判断玩家是否在受击范围内

    2、不在范围内则靠近

    3、在范围内则攻击

    范围判断:

    canAttack(){
        //当前位置
        pos1.set(this.target.position);
        //玩家位置
        pos2.set(this.player.position);
    
        //受击范围判断
        if(Vec3.distance(pos1, pos2) < 1){
            return bt.BehaviorStatus.Success;
        }
    
        return bt.BehaviorStatus.Failure;
    }
    

    移动到攻击范围

    onMoveToAttack(){
        if(this.canAttack()==bt.BehaviorStatus.Success){
            return bt.BehaviorStatus.Failure;
        }
        else{
            pos1.set(this.target.position);
            pos2.set(this.player.position);
            this.target.lookAt(pos2);
    
            let pos = this.lerp(out, pos1, pos2, 0.03);
            this.target.setPosition(pos);
    
            this._playAnim("runHit");
            return bt.BehaviorStatus.Running;
        }
    }
    

    发动攻击

    onAttack(){
        this._playAnim("attackLeft");
        //一次攻击结束后等待技能冷却,所以在攻击动作结束后播放防御动画 'fightIdel'
        this.anim.once(AnimationComponent.EventType.LASTFRAME, ()=>{
            this._playAnim("fightIdle");
        })
        //主角受击
        this.aiPlayer.beAttacked();
        return bt.BehaviorStatus.Success;
    }
    

    技能CD

    这也是一个内置 Wait 任务节点,与上一节中 巡逻 行为的 原地休息 节点类似,只需指定持续时间 duration 即可

逻辑绑定

  • 分别绑定 靠近攻击 任务的 onUpdate 委托逻辑。

    image-20220427233042108

  • 本次运行效果如下

    我们看到,AI 启动后立即向玩家靠近,这不太科学。我们给 AI 添加一个感应区域作为 AI 的视野,当玩家出现在感应区域范围内时 AI 才奔向玩家。

    1. 我们使用内置的 Conditional 条件元素来实现条件判断

    2. 视野判断代码实现

      onHasSight(){
          //当前位置
          pos1.set(this.target.position);
          //玩家位置
          pos2.set(this.player.position);
      
          //视野范围
          if(Vec3.distance(pos1, pos2) < 8){
              return bt.BehaviorStatus.Success;
          }
      
          return bt.BehaviorStatus.Failure;
      }
      
    3. 绑定 onUpdate 逻辑

运行效果

  • 增加视野判断后,运行效果如下

    圆形区域为 AI 视野,当玩家进入视野时,AI 开始追逐,当追逐到玩家受击范围时,展开攻击。

下一步

加入

  • BehaviorCreator QQ交流群:
  • 659064495

说明

  • 压缩包内包含完整运行时源码以及示例项目工程,详见包内 Readme.md 文档

4 个帖 - 3 位参与者

阅读整个主题


Viewing all articles
Browse latest Browse all 90494

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>