ET介绍——浅谈AI框架

这篇具有很好参考价值的文章主要介绍了ET介绍——浅谈AI框架。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

AI框架

1. 几种AI的设计

AI在游戏中很多,但是为什么大家总是感觉ai编写起来十分困难,我后来思考了一番,主要原因是使用的方法不当。之前大家编写ai主要有几种方案:

a. 状态机

我是不知道谁想出来这个做法的,真是无力吐槽。本来对象身上任何数据都是状态,这种方法又要把一些状态定义成一种新的节点,对象身上状态变化会引起节点之间的转换,执行对应的方法,比如OnEnter OnExit等等。这里以怪物来举例,怪物可以分为多种状态,巡逻,攻击,追逐,返回。怪物的状态变化有:

巡逻->追逐 巡逻状态发现远处有敌人变追逐状态
巡逻->攻击 巡逻发现可以攻击敌人变攻击状态
攻击->追逐 攻击状态发现敌人有段距离于是去追逐
攻击->返回 攻击状态发现距离敌人过远变返回状态
追逐->返回 追逐状态发现距离敌人过远变返回状态

太多状态转换了,这里有没有漏掉我已经难以发现了。一旦节点更多,任何两个节点都可能需要连接,将成为超级复杂的网状结构,复杂度是N的平方级,维护起来十分困难。为了解决网状结构变复杂的问题于是又升级为分层状态机等等。当然各种打补丁的方法还是没能解决本质的问题。用不好状态机不是你们的问题,是状态机的问题。

b. 行为树

可能大家都觉得状态机解决复杂ai实在太困难了,于是有人想出了行为树来做ai。行为树的ai是响应式ai,这棵树从上往下(或者从左往右执行,这里以从上往下举例)实际上是把action节点排了个优先级,上面的action最先判断是否满足条件,满足则执行。这里就不详细讲了。行为树的复杂度是N,比状态机大大简化了,但是仍然存在不少缺陷,ai太复杂的时候,树会变得非常大,而且难以重构。比如我们自己项目,要做一个跟人差不多的机器人ai,自动做任务,打怪,玩游戏中的系统,跟人聊天,甚至攻击别人。想象一下,这颗树将变得多复杂!行为树的另外一个缺陷是某些action节点是个持久的过程,也就是说是个协程,行为树管理起协程起来不太好处理,比如上面的例子,需要移动到目标身边,这个移动究竟是做成协程呢,还是每帧move呢?这是个难题,怎么做都不舒服。

2. 我的做法

ai是什么呢?很简单啊,ai就是不停的根据当前的状态,执行相应的行为。记住这两句话,很重要,这就是ai的本质!这两句话分成两部分,一是状态判断,二是执行行为。状态判断好理解,行为是啥?以上面状态机的怪物举例子,怪物的行为就是 巡逻,攻击敌人,返回巡逻点。比如:

巡逻 (当怪物在巡逻范围内,周围没有敌人,选择下一个巡逻点,移动)
攻击敌人 (当怪物发现警戒范围内有敌人,如果攻击距离够就攻击,不够就移动过去攻击)
返回 (当怪物发现离出生点超过一定距离,加上无敌buff,往出生点移动,到了出生点,删除无敌buff)

跟状态机不一样的是,这3个状态的变化完全不关心上一个状态是啥,只关心当前的条件是否满足,满足就执行行为。行为可能能瞬间执行,也可能是一段持续的过程,比如巡逻,选下一个巡逻点移动过去,走到了再选一个点,不停的循环。比如攻击敌人,可能需要移动到目标去攻击。

怎么设计这个ai框架呢?到这里就十分简单了,抽象出ai节点,每个节点包含条件判断,跟执行行为。行为方法应该是一个协程

public class AINode
{
    public virtual bool Check(Unit unit) // 检测条件是否满足
    {        
    }

    public virtual ETTask Run(Unit unit)
    {        
    }
}

 

进一步思考,假如怪物在巡逻过程中,发现敌人,那么怪物应该要打断当前的巡逻,转而去执行攻击敌人的行为。因此我们行为应该需要支持被打断,也就是说行为协程应该支持取消,这点特别需要注意,行为Run方法中任何协程都要支持取消操作!

public class AINode
{
    public virtual bool Check(Unit unit)
    {        
    }

    public virtual ETVoid Run(Unit unit, ETCancelToken cancelToken)
    {
    }
}

 

实现三个ai节点 XunLuoNode(巡逻) GongjiNode(攻击) FanHuiNode(返回)

public class XunLuoNode: AINode
{
    public virtual bool Check(Unit unit)
    {
        if (不在巡逻范围)
        {
            return false;
        }
        if (周围有敌人)
        {
            return false;
        }
        return true;
    }

    public virtual ETVoid Run(Unit unit, ETCancelToken cancelToken)
    {
        while (true)
        {
            Vector3 nextPoint = FindNextPoint();
            bool ret = await MoveToAsync(nextPoint, cancelToken); // 移动到目标点, 返回false表示协程取消
            if (!ret)
            {
                return;
            }
            // 停留两秒, 注意这里要能取消,任何协程都要能取消
            bool ret = await TimeComponent.Instance.Wait(2000, cancelToken);
            if (!ret)
            {
                return;
            }
        }
    }
}

 

同理可以实现另外两个节点。光设计出节点还不行,还需要把各个节点串起来,这样ai才能转动

AINode[] aiNodes = {xunLuoNode, gongjiNode, fanHuiNode};
AINode current;
ETCancelToken cancelToken;
while(true)
{
    // 每秒中需要重新判断是否满足新的行为了,这个时间可以自己定
    await TimeComponent.Instance.Wait(1000);

    AINode next;
    foreach(var node in aiNodes)
    {
        if (node.Check())
        {
            next = node;
            break;
        }
    }

    if (next == null)
    {
        continue;
    }

    // 如果下一个节点跟当前执行的节点一样,那么就不执行
    if (next == current)
    {
        continue;
    }

    // 停止当前协程
    cancelToken.Cancel();

    // 执行下一个协程
    cancelToken = new ETCancelToken();
    next.Run(unit, cancelToken).Coroutine();
}

 

这段代码十分简单,意思就是每秒钟遍历节点,直到找到一个满足条件的节点就执行,等下一秒再判断,执行下一个节点之前,先打断当前执行的协程。 几个使用误区:

  1. 行为中如果有协程必须能够取消,并且传入cancelToken,否则会出大事,因为怪物一旦满足执行下个节点,需要取消当前协程。
  2. 跟行为树与状态机不同,节点的作用只是一块逻辑,节点并不需要共享。共享的是协程方法,比如MoveToAsync,怪物巡逻节点可以使用,怪物攻击敌人节点中追击敌人也可以使用。
  3. 节点可以做的非常庞大,比如自动做任务节点,移动到npc,接任务,根据任务的子任务做子任务,比如移动到怪点打怪,移动到采集物去采集等等,做完所有子任务,移动到交任务npc交任务。所有的一切都是写在一个while循环中,利用协程串起来。

思考一个大问题,怎么设计一个压测机器人呢?压测机器人需要做到什么?自动做任务,自动玩各种系统,自动攻击敌人,会反击,会找人聊天等等。把上面说的每一条做成一个ai节点即可。兄弟们,AI简不简单?

ET开源地址地址:egametang/ET: Unity3D Client And C# Server Framework (github.com)   qq群:474643097文章来源地址https://www.toymoban.com/news/detail-451249.html

到了这里,关于ET介绍——浅谈AI框架的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity常见框架探索-ET框架探索

    简介 ET框架是类ECS的一个Unity前后端框架 论坛地址为:https://et-framework.cn Git地址为:https://github.com/egametang/ET Unity程序集的使用 本文将会以7.2版本进行分析。所以直接clone github上的仓库,将工程导入到本地,之后将分支切换到最新的release分支,\\\"release7.2\\\" ET-ChangeDefine-ADD_ENABLE

    2024年02月09日
    浏览(37)
  • ET框架解读其一

    版本属于5.0 ECS? 真正的ECS属于是entity-component-system 组件里面只有数据没有方法,system里面是针对组件的方法,system通过查找只需要关注自己想关注的组件集合就可以。 但是ET框架的代码在组件里面写满了方法,有数据又有方法的组件,随时可拆卸,像什么?没错 是Unity的组

    2024年02月09日
    浏览(53)
  • ET框架(一)

    cmd 输入验证  dotnet --version   path :添加  cmd  输入mongo 验证 Unity 2020.3.35f1c2 安装Rider =》取消波浪线 show context action=》configtion ispection sevity 运行: 重新编译Unity mono和Client-Server 服务器日志: 打开Unity项目 设置为Mono 使用Tool-Buidl Code 重新编译  打包运行 发现打包报错: 安装

    2024年02月12日
    浏览(38)
  • ET 7.2框架学习(2)

    打开ET.sln开始阅读源代码。我们先来学习客户端的代码,打开ET工程后,此时可以看到如下的目录结构: 其中,红色框圈起来的部分为我们平时开发时使用的工程,由于默认为打包模式,其工程并未生成和加载,故我们需要将开发模式打开,回到Unity中,在菜单栏选中 ET → C

    2024年02月09日
    浏览(34)
  • 02-ET框架的ECS编程思想

    TIPS: 本系列贴仅用于博主学习ET框架的记录 今天来学习OOP以外的另一种编程思想—ECS。 ECS:实体(Entity)、组件(Component)、系统(System),同时在框架中(实体即组件、组件即实体)类似电脑是一个实体,键盘是电脑的一个组件,但同时键盘也是一个实体,因为其下面还有按键这种

    2024年02月08日
    浏览(34)
  • ET框架6.0分析二、异步编程

    ET框架很多地方都用到了异步,例如资源加载、AI、Actor模型等等。ET框架对C#的异步操作进行了一定程度的封装和改造,有一些特点: 显式的或者说强调了使用C#异步实现协程机制(其实C#的异步编程天生就能实现这种用法) 强制单线程异步 没有使用C#库的Task,自己实现了E

    2024年02月04日
    浏览(31)
  • ET框架6.0分析三、网络通信

    ET框架的消息机制贯彻始终,包含Entity消息(Awake,Update ...),自定义(Customer)消息,网络消息等。而ET系统的进程包含了客户端、Gate等各种类型的服务器,进程包含各种服务器客户端之间通过网络消息进行通信进行工作。 结构图为了更加明确整体关系,进行了一定程度的简化

    2024年02月08日
    浏览(33)
  • ET框架6.0分析一、ECS架构

    ET框架的ECS架构是从ECS原生设计思想变形而来的(关于ECS架构的分析可以参考跳转链接:《ECS架构分析》),其特点是: Entity:实体可以作为组件挂载到其他实体上,Entity之间可以有父子嵌套关系,和其他ECS架构一样,Entity只允许是纯数据的(除了基本接口) System:和其他

    2024年02月04日
    浏览(32)
  • ET介绍——CSharp协程

    说到协程,我们先了解什么是异步,异步简单说来就是,我要发起一个调用,但是这个被调用方(可能是其它线程,也可能是IO)出结果需要一段时间,我不想让这个调用阻塞住调用方的整个线程,因此传给被调用方一个回调函数,被调用方运行完成后回调这个回调函数就能

    2024年02月05日
    浏览(33)
  • ET介绍——单线程异步

    前面几个例子都是多线程实现的异步,但是异步显然不仅仅是多线程的。我们在之前的例子中使用了Sleep来实现时间的等待,每一个计时器都需要使用一个线程,会导致线程切换频繁,这个实现效率很低,平常是不会这样做的。一般游戏逻辑中会设计一个单线程的计时器,我

    2024年02月05日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包