当前位置: 首页 > news >正文

2024-07-12 Unity AI状态机1 —— 框架介绍

文章目录

  • 1 有限状态机
  • 2 状态机实现框架
    • 2.1 StateMachine
    • 2.2 BaseState
    • 2.3 ...State
    • 2.4 IAIObject
  • 3 框架类图

本文章参考 B 站唐老狮 2023 年直播内容。点击前往唐老狮 B 站主页。

1 有限状态机

​ 有限状态机(Finite - State Machine,FSM),又称有限状态自动机,简称状态机。是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

  • 有限:有限度,不是无限的。

  • 状态:指所拥有的所有状态。

举例说明:

​ 人会做很多个动作,即有很多种状态,包括站立、走路、跑步、攻击、防守、睡觉等等。我们每天都会在这些状态中切换,而且这些状态虽然多但是是有限的。当达到某种条件时,就会在这些状态中进行切换,且这种切换时随时可能发生。

​ 游戏中的怪物 AI 表现一般为巡逻、朝玩家移动、攻击、逃跑、格挡等等状态。即使怪物 AI 表现看起来比较复杂,但是深入观察和分析,它们的状态一般是有限的,只是在不同条件下切换不同状态,由于状态的多样性和美术表现的多样性,让我们觉得它是比较智能的。

​ 因此,“有限”和“行为状态”这两个特点,使得游戏 AI 适用于使用有限状态机实现。

2 状态机实现框架

  1. StateMachine(状态机类,用于统一管理各个状态)。

  2. BaseState(状态基类,抽象出状态的共有内容)。

  3. …State(各状态类,有多少个状态就有几个状态类,均继承状态基类)。

  4. IAIObject(怪物 AI 接口,用于规范所有 AI 的共同行为)。

2.1 StateMachine

​ 有限状态机类,用于管理各个状态之间的切换。同时需要记录所有状态,因此需要如下成员:

  1. StateDictionay:记录所有状态。
  2. NowState:当前处于的状态。
  3. AIObject:附属在哪个 AI 对象上。
  4. AddState():向外部提供添加状态的方法(执行一帧)。
  5. ChangeState():向外部提供切换状态的方法(执行一帧)。
  6. UpdateState():向外部提供更新状态的方法(每帧调用)。

​ 基本结构如下:

using System;
using System.Collections.Generic;/// <summary>
/// 有限状态机类,用于管理各个状态之间的切换
/// </summary>
public class StateMachine
{/// <summary>/// 管理所有状态的字典容器/// </summary>private Dictionary<EAIState, BaseState> _stateDic = new Dictionary<EAIState, BaseState>();private BaseState _nowState; // 当前状态public IAIObject AIObject; // 管理的 AI 对象/// <summary>/// 初始化方法/// </summary>/// <param name="aiObject">待管理的 AI 对象</param>public void Init(IAIObject aiObject) {AIObject = aiObject;}/// <summary>/// 添加 AI 状态/// </summary>public void AddState(EAIState state) { ... }/// <summary>/// 切换状态/// </summary>/// <param name="state"></param>public void ChangeState(EAIState state) { ... }/// <summary>/// 更新当前状态/// </summary>public void UpdateState() { ... }
}

2.2 BaseState

​ 状态基类负责提取所有状态共有的特性,并声明为抽象类(Abstract),规范每个状态的共同行为。其共有特性基本包括如下:

  1. AIState:状态类型(所有状态需要告诉外面自己是哪种类型)。
  2. StateMachine:附属的状态机。
  3. OnStateEnter():进入状态时执行的逻辑(执行一帧)。
  4. OnStateUpdate():处于该状态时不断更新的逻辑(每帧更新)。
  5. OnStateExist():离开状态时执行的逻辑(执行一帧)。

​ 基本结构如下:

using UnityEngine;/// <summary>
/// 状态基类
/// </summary>
public abstract class BaseState
{public virtual EAIState AIState { get; } // 状态类型protected StateMachine _stateMachine; // 附属的状态机public BaseState(StateMachine stateMachine) {_stateMachine = stateMachine;}/// <summary>/// 进入状态/// </summary>public abstract void OnStateEnter();/// <summary>/// 保持状态/// </summary>public abstract void OnStateUpdate();/// <summary>/// 离开状态/// </summary>public abstract void OnStateExit();
}

2.3 …State

​ 在各个具体状态中,可以有独立的数据或逻辑,但每个状态都需要实现由基类规范的共同逻辑。

​ 以 PatrolState(巡逻状态)为例,其基本结构如下:

using System;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;/// <summary>
/// 巡逻状态类,处理巡逻逻辑
/// </summary>
public class PatrolState : BaseState
{// 巡逻数据...public override EAIState AIState { get => EAIState.Patrol; } // 表示自己是巡逻状态public PatrolState(StateMachine stateMachine) : base(stateMachine) {// 初始化...}public override void OnStateEnter() { ... }  // 进入巡逻状态的逻辑实现public override void OnStateUpdate() { ... } // 处于巡逻状态的逻辑实现public override void OnStateExit() { ... }   // 退出巡逻状态的逻辑实现// 其他逻辑、方法封装等...
}

2.4 IAIObject

​ AI 对象接口,规定 AI 对象必须继承该接口,用于规范 AI 对象的行为。

​ 在 StateMachine 中,不会存储具体的 AI 对象,而是存储 IAIObject,指向对应的 AI 对象。不同的 AI 对象均需要实现 IAIObject 中规范的逻辑,从而使 StateMachine 能够适用于具有不同逻辑的不同 AI 对象。

​ 基本实现如下:

using UnityEngine;/// <summary>
/// AI 对象接口,用于规范 AI 对象的行为
/// </summary>
public interface IAIObject
{public Transform Transform { get; } // AI 对象的 Transformpublic Transform TargetTransform { get; } // 目标监测对象的 Transformpublic float AttackRange { get; } // 攻击范围public Vector3 BornPos { get; } // 出生位置public void Move(Vector3 targetPos); // 移动public void StopMove(); // 停止移动public void Attack(); // 攻击public void ChangeAction(EAction action); // 切换指定动作// 等等...
}

3 框架类图

StateMachine_AI 框架介绍

相关文章:

  • 案例|LabVIEW连接S7-1200PLC
  • pytorch说明
  • Java 实验三:数组操作以及Java中的方法
  • 解决方案架构师系列 - AWS - AWS Amplify 服务功能介绍
  • 【Linux取经之路】Linux常见指令
  • 关于windows下编译xLua插件的流程记录
  • 【Parallel SSH】Ubuntu系统配置pssh实现多主机并行执行Master分发的命令
  • 突破与创新:Vue.js 创始人 尤雨溪 2024 年度技术前瞻
  • Python - Word转TXT文本,或TXT文本转Word
  • AI大模型探索之旅:深潜大语言模型的训练秘境
  • 【Linux系列】TEE 命令:同时输出到终端和文件
  • C语言之qsort函数
  • Go语言 切片slice
  • mindspore打卡22天之基于MindSpore通过GPT实现情感分类
  • Java---SpringBoot详解一
  • [PHP内核探索]PHP中的哈希表
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • 5、React组件事件详解
  • dva中组件的懒加载
  • ES6语法详解(一)
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • python学习笔记-类对象的信息
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • vue 配置sass、scss全局变量
  • 理清楚Vue的结构
  • 前端工程化(Gulp、Webpack)-webpack
  • 入门到放弃node系列之Hello Word篇
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 温故知新之javascript面向对象
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • ​香农与信息论三大定律
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #HarmonyOS:基础语法
  • #QT(QCharts绘制曲线)
  • #宝哥教你#查看jquery绑定的事件函数
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (剑指Offer)面试题34:丑数
  • (接口封装)
  • (南京观海微电子)——示波器使用介绍
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (转)scrum常见工具列表
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .Net 基于MiniExcel的导入功能接口示例
  • .net 连接达梦数据库开发环境部署
  • .NET单元测试使用AutoFixture按需填充的方法总结
  • /bin/bash^M: bad interpreter: No such file or directory
  • ??eclipse的安装配置问题!??
  • [ SNOI 2013 ] Quare
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网