Skip to content

需求文档

云却 edited this page Sep 21, 2023 · 1 revision

开发自己的AI插件,需要满足什么功能?

工作流程

常见工作流程是创建一块黑板,添加一些黑板键,然后创建一个使用黑板资源的行为树,业务代码的一些值改变时,将新值设置到黑板中。例如UE行为树。

基本需求

  • AI工程可与实际项目工程分离解耦。
  • AI设计师视角?
    • 可以自定义参数,自定义Task
  • MOD开发第三方视角?
    • 不需要自定义参数,自定义Task/Action
    • 能够读取到游戏支持的参数,Task。根据已有的参数列表制作AI。
  • 游戏项目使用AI文件视角?
    • 参数绑定
    • 实现AI文件所需要的Task。

需求示例 游戏工程

class Dog Move Attack1, Name,Age

class Cat Move Attack2,Name,Height

实现IAgent,并且关联参数。

接口拆分:

参数接口IParams可以是一个,角色类实现参数接口,没有用到就是默认值。

IAgent应该每个函数拆分一个接口,AI工程每个Task使用最小接口。

例如Dog应该实现IMoveable和IAttack1able接口,不用实现IAttack2able和IAgent接口。

即使Dog使用一个需要执行Attack2 Task的AI,也会因为转型失败得到Task失败,最大程度AI文件复用。

AI工程

AIFile1:

AIFile2:

IAgent:Move Attack1,Attack2, Name,Age,Height

或者 参数和Task定义分开

IParams: Name,Age,Height 参数是可读可写的。等价于Blackboard。

IAgent:Move Attack1,Attack2

IMoveable,IAttack1able,IAttack2able

Mod工程

mod工程不能访问 Dog Cat等运行时类,这些代码是不能对第三方开发者公开的。

应该有一组标准接口,描述了游戏已经支持的参数,Task

可以访问IAgent

特殊需求

特殊需求决定了行为树的实现架构。 设想的需求,可能无法实现,可以作为Feature。

  • AI控制对象 切换 AI文件,比如一个Boss,进化成另一个Boss
  • AI调度器切换 目标角色,比如一个AI调度器正在控制 NPC1,切换到控制NPC2。一个NPC夺舍另一个NPC。(本质是切换AI文件,并参数继承)
  • AI参数表复用,多个AI文件基于用一个参数表。
  • AI文件片段复用, 多个BOSS的巡逻逻辑是一样的,多个AI文件复用 巡逻子树。
  • AI子树调用,运行时调用一个子树,子树使用父树的参数表。
  • 因为可以自定义频率,OnUpdate需要提供deltatime 参数, 通常是个ITimer/IDeltaTimeable 接口。

求解型AI框架兼容性:

笔记

  • AI文件应该控制行为,基本上不应该去修改控制对象的属性。 控制对象和黑板的属性,是执行行为带来的后果。

  • 玩家死亡时关闭清理行为树,复活时重新启动行为树,应该写在 AI调度器/执行器/AIController 里,不应该在 行为树内检测控制对象死亡,除非死亡后仍需要执行特殊逻辑

  • 可以先用硬编码方式写行为树。后期在做Editor。先把框架搭好。 行为树文件也应该可以生成代码。前期手动编码验证框架。 手动编码可以更好的利用泛型。

    参考playable api的连接方法参数。

    • 泛型手动编写行为树文件/类型
    • 回滚 当游戏回滚时,应该可以回滚树的执行栈
    • 菱形连接
    • 自动公开参数到Controller/Inspector
    • 泛型序列化
    • 为了行为树的纯粹性,条件不应该支持表达式数学运算。
    • 使用异步API,比如父节点调用子节点等待结果,使用异步代替事件。Running可以使用异步代替。增加一个开关,异步模式还是Running模式。
    • 继承
    • 可以公开自定义事件到Inspector,由行为树触发事件调用外部绑定事件。
    • 支持泛型任务添加到行为树(除了保存Task名字,在保存一个泛型填充类型参数,默认也可以是泛型树的类型。)。反正反序列化都是反射构造,没有什么区别。
    • Data Binding / (Instance|Static) Member Binding / TypeConvert / Prefab Override 预制体重写行为树公开的参数。/Late Binding后期绑定,设置绑定字符串,运行时解析到绑定对象。解决 unity资产不能保存场景对象引用的问题。
    • 代码行为树文件生成Asset文件,文本文件。以供编辑器打开。
    • setroot,可标记的根节点,根节点不是固定的,可以将树的任何一个节点标记为根节点。但同时只能有一个根节点。方便调试树的任何一个子区域。
    • 为了兼容第三方插件,尽量不要声明自己的特性,使用.net 原生特性,或者unity特性。 第三方插件与行为树做兼容时就不必引用你的包。使用反射先做个所有特性列表,看名字那个顺眼用哪个。
    • 装饰锁,BD提供了监控任务(Guard Task)来保证多个节点执行的互斥性,类似于多线程编程中的信号量(Semaphore)。比如有两个不同的任务,一个播放声音,另一个播放特效。这两个任务在行为树里是两个不同的分支,所以它们之间并不知道对方的状态,有可能同一时间这两个任务被同时执行。但可能并不希望这种情况发生。在这种情况下,通过使用监控任务来保证当前要么播放音效,要么播放特效。只有当第一个播放完毕,才会播放第二个。 可以设置锁的行为,遇到锁被其他任务使用返回成功失败还是等待。
    • 变体。 很难实现。有限的变体,只支持参数修改。
    • 当Unity MonoBehaviour 含有符合Task签名的方法,那么行为树应该可以自动感知到,并允许添加到树中。而不用特意去写一个Task。- Documentation (paradoxnotion.com)
    • 当Unity MonoBehaviour 含有符合条件签名的方法,即返回值是一个bool,就应该允许添加到条件装饰节点中。而不用特意去写一个Candition。- Documentation (paradoxnotion.com)

    行为树与阵法技,玩家设置一个阵法区域,里面预设一个AI行为树,Npc进入后AI一个分分支加载这个子树。按照抗性执行子树,干扰AI行为。 区域内含有一个环境参数表。Npc进入后替换默认的环境参数表。

    AI感知 主动感知 配置文件显示范围 OnGizmos(Transform)

问题

如果想要客户端服务器复用 [SliderField(float min, float max)] 显示特性标签怎么解决?服务端是没有这种标签的。源码复用还是dll复用。Task源码复用,还可以用条件编译解决。Unity中避免不了自定义Task没怎么导出给服务器使用?同一个Task unity 和服务器两套实现?行为树文件按照Task类名,或者GUID反序列化。

常见问题

AI控制移动,移动速度。真实位移不应该由动画决定,应该由代码计算决定,让动画播放去匹配真实位移。
滑步只能尽可能避免,不可能永远避免,不必太过于执着。

节点编辑器框架选择