尝试自主打造一个有限状态机(二)

前言

        上一篇文章我们从理论角度去探索了状态机的定义、组成、作用以及设计,对状态机有了一个基本的认识,这么做有利于我们更好地去分析基于实际应用的状态机,以及在自主设计状态机时也能更加地有条不紊。本篇文章将从状态机的实际应用出发,分析基于角色控制的状态机是如何进行设计的。

声明

        本系列文章要求读者具备一定的C#编程基础,同时对接口和抽象类、继承关系、设计模式以及面向对象等知识有所了解,在文章中我会对这些知识进行简要的阐述,对于描述有误的地方敬请指正。

基于角色控制的状态机

1.定义

        基于角色控制的状态机是用于管理一个角色的状态的,在动作类游戏中角色的状态往往比较多,并且状态之间的过渡关系也比较繁杂,那么我们就可以为此打造一个状态机来更好地开发和维护这个部分。

        从Unity3D的Animator去分析,首先一个角色通常是通过一个.controller文件来管理角色的状态的,这个. controller文件就像一个系统,从Animator的界面可以看到这个系统中包括了定义的状态、状态之间的连接以及状态过渡的条件参数等,而每个状态和状态之间的连接都有一些属性可以进行设置,由于状态机的应用不仅限于像Animator那样用于动画,所以这些属性应该根据状态机的实际应用场景去定义,如果用于动画,那么状态的属性可以是动画源文件和动画播放速度等。

2.组成

        通常一个角色只需要使用一个状态机去控制即可,这个状态机属于角色控制的一部分,它至少应该包括角色状态类、角色状态转换路径类和角色状态机类三个部分,除此之外我们还可以把角色状态的执行逻辑与角色状态分离将其单独作为一个类,但是它仍然属于状态机。同时角色控制是与输入相关联的,所以角色状态的转换将由当前状态与输入共同决定,输入不属于角色控制,所以也就不作为状态机的组成部分,除此之外还有一些不属于状态机但是必要的部分,例如角色控制的参数、角色的消息机制和角色实体类等。那么综上所述,我们明确了基于角色控制的状态机应该包括角色状态类、角色状态转换路径类、角色状态机类和角色状态执行逻辑类四个部分。

3.需求

        接下来较为复杂的就是设计这四个类中具体的方法,这首先需要我们明确角色控制的需求,基于需求去设计才能尽可能避免偏离实际。

组成部分

必要属性

可选属性

必要方法

可选方法

角色状态

状态名称、状态优先级、角色控制参数、动画组件或系统、输入检测集合

未知

初始化方法、动画播放方法、重置方法

未知

角色状态转换路径

源状态、目标状态、状态机、角色控制参数

未知

初始化方法、重置方法

未知

角色状态机

未知

未知

初始化方法、重置方法

未知

角色状态执行逻辑

角色控制参数

未知

刷新方法、初始化方法、重置方法

未知

        角色状态最基本的功能需求是记录角色各个状态的信息,例如状态名称和状态优先级等,与角色状态对应的动画播放是采用Unity3D的Animator或Animation组件还是自定义的动画系统,这也可以作为角色状态的一部分,在角色状态中可能需要调用一些角色控制的参数,那么角色状态中还需要维护一个相关的变量,同时并非所有输入都需要在当前角色状态进行检测,例如角色跳跃的时候不一定需要检测攻击的输入,所以可以在角色状态中规定需要检测或不可检测的输入。除此之外角色状态还可以配备重置方法、初始化方法、动画播放的方法等。

        角色状态转换路径需要记录源状态到目标状态的转换信息和状态转换的检测逻辑,如果需要调用状态机或角色控制参数就加上对应的变量即可,还可以配置初始化方法、重置方法等。

        角色状态机需要管理各个角色状态和角色状态转换路径,向外提供调用接口,同时也可以配置初始化方法、重置方法等。角色状态机应该继承自基本的状态机,所以角色状态机中仅需要添加或重写一些特有的方法即可,具体的方法根据角色状态机的需求进行添加。

        角色状态执行逻辑用于记录某个角色状态的执行逻辑,例如与某些组件一起完成当前状态的角色控制的实现或者当前状态下某些角色控制参数的改变,可以配备刷新的方法、初始化的方法以及重置方法等。

        对于首次开发,我们无法非常完整地确定需求,所以我们可以边开发边改进,后续通过不断地优化来完善这个基于角色控制的状态机。

4.设计

        基于上述需求,基于角色控制的状态机分为角色状态、角色状态机、角色状态转换路径以及角色状态执行逻辑,四个部分分别对应PlayerState类、PlayerStateMachine类、PlayerStateTransition类以及PlayerStateRule类,且四个类分别继承自CSFState类、CSFStateMachine类、CSFStateTransition类以及CSFStateRule类。而对于PlayerState、PlayerStateMachine、PlayerStateTransition以及PlayerStateRule四个类具体的设计则需要根据角色控制的具体需求去完成,在接下来的实际示例UML图中可以看到对于这四个部分的具体类设计。

       我们可以先结合每个部分的功能来明确一些对应的属性和方法,然后逐渐修改完善,不断贴合需求进行优化。

实际示例(UML)

        如图1所示,AnimationEvents是属于动画事件类,用于管理角色各个状态的动画中的事件。PlayerState是角色状态类,继承自CSFState这个通用状态类。PlayerStateMachine是角色状态机类,继承自CSFStateMachine这个通用状态机类。PlayerStateTransition是角色状态转换路径类,继承自CSFStateTransition这个通用状态转换路径类。PlayerStateRule是角色状态执行逻辑类,继承自CSFStateRule这个通用状态执行逻辑类。PlayerTransitionMediator是角色状态转换路径中介者类,继承自CSFTransitionMediator这个通用状态转换路径中介者类,这个中介者类负责某个状态对应的所有状态转换路径的过渡检测。

        实际运转则是首先调用PlayerStateMachine中的Init方法对所有的PlayerState、PlayerStateTransition以及PlayerStateRule进行初始化,为每个PlayerState设置输入配置以及添加对应的PlayerStateRule,为每个PlayerState对应的PlayerTransitionMediator添加对应的PlayerStateTransition,最后将所有的PlayerState和PlayerStateTransition添加到PlayerStateMachine中,然后设置PlayerStateMachine的初始状态。

        每个PlayerState都具备一个OnEnter、OnUpdate和OnExit方法,在角色控制类中分别调用PlayerStateMachine的接口方法StateUpdate和StateRuleUpdate,StateUpdate方法负责PlayerStateMachine中当前状态对应的OnUpdate方法的执行,当前状态的OnUpdate方法中执行PlayerTransitionMediator中的StateCheck方法用于对当前状态对应的PlayerStateTransition的过渡进行检测,由于这个示例我们借助Animator播放动画,所以对应状态的动画播放则放在了OnEnter方法中执行,PlayerTransitionMediator中的StateCheck方法则是对每个PlayerStateTransition的按照优先级进行排序,优先级高的先进行检测,这个过渡检测的逻辑则对应着PlayerStateTransition中的CanTransitionTo方法,若通过了过渡检测,则PlayerStateMachine的当前状态将过渡到指定的状态,然后继续重复上述过程,在每一次StateUpdate方法执行后都会执行一次StateRuleUpdate方法,StateRuleUpdate负责当前状态的PlayerStateRule中的Update方法的调用,进而完成对应的角色状态执行逻辑的工作。每个状态都配置着一个PlayerState、PlayerStateTransition、PlayerStateRule和PlayerTransitionMediator的派生类,在这些派生类中只需要完成对应功能具体逻辑的编写即可,不需要关注各自之间的合作和调用问题。

图1

  

如果这篇文章对你有帮助,请给作者点个赞吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/54636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows11不允许安装winpcap4.1.3

问题:下载安装包后在安装时显示与电脑系统不兼容,不能安装。 原因:winpcap是一个用于Windows操作系统的网络抓包库,有一些安全漏洞,存在被黑客攻击的风险。Windows11为了加强系统安全而禁用了这个库,因此不…

opencv/C++ 人脸检测

前言 本文使用的测试资源说明: opencv版本:opencv 4.6.0 人脸检测算法 Haar特征分类器 Haar特征分类器是一个XML文件,描述了人体各个部位的Haar特征值。包括:人脸、眼睛、鼻子、嘴等。 opencv 4.6.0自带的Haar特征分类器&…

2023中国算力大会 | 中科驭数加入DPU推进计划,探讨DPU如何激活算网融合新基建

8月18日,由工业和信息化部、宁夏回族自治区人民政府共同主办的2023中国算力大会在宁夏银川隆重召开。作为DPU算力基础设施领军企业,中科驭数产品运营部副总经理曹辉受邀在中国信通院承办的算网融合分论坛发表主题演讲《释放极致算力 DPU激活算网融合新基…

计算机竞赛 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于大数据…

代码随想录算法训练营之JAVA|第三十八天|494. 目标和

今天是第38天刷leetcode,立个flag,打卡60天。 算法挑战链接 494. 目标和https://leetcode.cn/problems/target-sum/ 第一想法 题目理解:题目给出一个数组,使用 或 - 算术符号,有多少种组合可以得到target的值。 拿…

【头歌】构建哈夫曼树及编码

构建哈夫曼树及编码 第1关:构建哈夫曼树 任务描述 本关任务:构建哈夫曼树,从键盘读入字符个数n及这n个字符出现的频率即权值,构造带权路径最短的最优二叉树(哈夫曼树)。 相关知识 哈夫曼树的定义 设二叉树具有n个带权值的叶子结点{w1,w2,...,wn},从根结点到每个叶…

FreeSWITCH 1.10.10 简单图形化界面4 - 腾讯云NAT设置

FreeSWITCH 1.10.10 简单图形化界面4 - 腾讯云NAT设置 0、 界面预览1、 查看IP地址2、 修改协议配置3、 开放腾讯云防火墙4、 设置ACL5、 设置协议中ACL,让PBX匹配内外网6、 重新加载SIP模块7、 查看状态8、 测试一下 0、 界面预览 http://myfs.f3322.net:8020/ 用…

关于事件回调机制

OVERVIEW 关于事件回调机制1.事件回调编程模式2.C中的事件回调编程模式函数指针回调函数对象回调 3.简单回调实例 关于事件回调机制 1.事件回调编程模式 当涉及到编程和软件开发时,事件回调是一种常见的编程模式。它用于处理异步事件和消息传递系统中的事件通知。 …

自然语言处理(一):词嵌入

词嵌入 词嵌入(Word Embedding)是自然语言处理(NLP)中的一种技术,用于将文本中的单词映射到一个低维向量空间中。它是将文本中的单词表示为实数值向量的一种方式。 在传统的文本处理中,通常使用独热编码&…

pytorch学习(8)——现有网络模型的使用以及修改

1 vgg16模型 1.1 vgg16模型的下载 采用torchvision中的vgg16模型,能够实现1000个类型的图像分类,VGG模型在AlexNet的基础上使用3*3小卷积核,增加网络深度,具有很好的泛化能力。 首先下载vgg16模型,python代码如下&…

基于 kernel 4.0 初始kmalloc

kmalloc 系列函数是驱动者常用来向内核大管家申请内存的API,今天抽空扒一扒它是怎么工作的;首先看看它的原型 1. kmalloc () 函数 static __always_inline void *kmalloc(size_t size, gfp_t flags) {if (__builtin_constant_p(size)) {if (size > …

论文阅读:Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks

前言 要弄清MAML怎么做,为什么这么做,就要看懂这两张图。先说MAML**在做什么?**它是打着Mate-Learing的旗号干的是few-shot multi-task Learning的事情。具体而言就是想训练一个模型能够使用很少的新样本,快速适应新的任务。 定…

pdf转ppt软件哪个好用?推荐一个好用的pdf转ppt软件

在日常工作和学习中,我们经常会遇到需要将PDF文件转换为PPT格式的情况。PDF格式的文件通常用于展示和保留文档的原始格式,而PPT格式则更适合用于演示和展示。为了满足这一需求,许多软件提供了PDF转PPT的功能,使我们能够方便地将PD…

C语言暑假刷题冲刺篇——day5

目录 一、选择题 二、编程题 🎈个人主页:库库的里昂 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏✨收录专栏:C语言每日一练✨相关专栏:代码小游戏、C语言初阶、C语言进阶🤝希望作者…

【CSS】CSS 特性 ( CSS 优先级 | 优先级引入 | 选择器基本权重 )

一、CSS 优先级 1、优先级引入 定义 CSS 样式时 , 可能出现 多个 类型相同的 规则 定义在 同一个元素上 , 如果 CSS 选择器 相同 , 执行 CSS 层叠性 , 根据 就近原则 选择执行的样式 , 如 : 出现两个 div 标签选择器 , 都设置 color 文本颜色 ; <style>div {color: re…

精准高效农业作业,植保无人机显身手

中国作为农业大国&#xff0c;拥有约18亿亩的农田&#xff0c;每年都需要进行种子喷洒和农药施用等农业作业&#xff0c;对于普通农户来说&#xff0c;这是一项耗时耗力的工程&#xff0c;同时&#xff0c;人工喷洒农药极易造成农药慢性中毒&#xff0c;对农民的身体健康产生极…

k8s 安装istio (一)

前置条件 已经完成 K8S安装过程十&#xff1a;Kubernetes CNI插件与CoreDNS服务部署 部署 istio 服务网格与 Ingress 服务用到了 helm 与 kubectl 这两个命令行工具&#xff0c;这个命令行工具依赖 ~/.kube/config 这个配置文件&#xff0c;目前只在 kubernetes master 节点中…

bug复刻,解决方案---在改变div层级关系时,导致传参失败

问题描述&#xff1a; 在优化页面时&#xff0c;为了实现网页顶部遮挡效果&#xff08;内容滚动&#xff0c;顶部导航栏不随着一起滚动&#xff0c;并且覆盖&#xff09;&#xff0c;做法是将内容都放在一个div里面&#xff0c;为这个新的div设置样式&#xff0c;margin-top w…

c++ qt--事件过滤(第七部分)

c qt–事件过滤&#xff08;第七部分&#xff09; 一.为什么要用事件过滤 上一篇博客中我们用到了事件来进行一些更加细致的操作&#xff0c;如监控鼠标的按下与抬起&#xff0c;但是我们发现如果有很多的组件那每个组件都要创建一个类&#xff0c;这样就显得很麻烦&#xff…

python爬虫10:selenium库

python爬虫10&#xff1a;selenium库 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产…