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

前言

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

声明

        本系列文章要求读者具备一定的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.rhkb.cn/news/107963.html

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

相关文章

wazuh环境配置及案例复现

文章目录 wazuh环境配置及案例复现wazuh环境配置 案例复现 wazuh环境配置及案例复现 wazuh环境配置 进入官网下载ova软件 https://documentation.wazuh.com/current/deployment-options/virtual-machine/virtual-machine.html 打开下载的ova,密码和用户名会显示…

sql developer 连不上oracle数据库 报错 ORA-01031: insufficient privileges

sql developer 连不上oracle数据库 报错 ORA-01031: insufficient privileges 1、问题描述2、问题原因3、解决方法4、sql developer 连接oracle 成功 1、问题描述 使用sys账户以SYSDBA角色登录失败 报错 ORA-01031: insufficient privileges 2、问题原因 因为没有给sys账户分…

【Go 基础篇】Go语言中的defer关键字:延迟执行与资源管理

介绍 在Go语言中,defer 是一种用于延迟执行函数调用的关键字。它提供了一种简洁而强大的方式,用于在函数返回之前执行一些必要的清理操作或者释放资源。defer 的灵活性和易用性使得它在Go语言中广泛应用于资源管理、错误处理和代码结构优化等方面。&…

2023年高教社杯数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

手把手教你用 ANSYS workbench

ANSYS Workbench ANSYS Workbench是一款基于有限元分析(FEA)的工程仿真软件。其基本概念包括: 工作区(Workspace):工程仿真模块都在此区域内,包括几何建模、网格划分、边界条件设置、分析求解等…

Ubuntu-Server 22.04安装详细过程-图文版

一.下载Ubuntu Server镜像,官方地址下载即可 https://ubuntu.com/download/server 乌班图镜像网址,点击下载即可 二.安装乌班图镜像,最好自己准备u盘在ISO软件内制作完成 1.选择 Install Ubuntu Server 2.选择安装语言为英语 3.安装程序更新选…

C#,《小白学程序》第二课:数组与排序

1 文本格式 /// <summary> /// 《小白学程序》第二课&#xff1a;数组与排序 /// </summary> /// <param name"sender"></param> /// <param name"e"></param> private void button2_Click(object sender, EventArgs …

Vue3(开发h5适配)

在开发移动端的时候需要适配各种机型&#xff0c;有大的&#xff0c;有小的&#xff0c;我们需要一套代码&#xff0c;在不同的分辨率适应各种机型。 因此我们需要设置meta标签 <meta name"viewport" content"widthdevice-width, initial-scale1.0">…

SD 总线引脚介绍

参考 https://www.cnblogs.com/justin-y-lin/p/12259851.html SD卡与TF卡的引脚定义 - 360文档中心

java+springboot+mysql医院预约挂号管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的医院预约挂号管理系统&#xff0c;系统包含超级管理员、管理员、医生、患者角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;用户管理&#xff1b;科室管理&#xff1b;床位管理&…

Linux系统编程之文件编程常用API回顾和文件编程一般步骤

目录 1.打开文件 2.创建文件 3.写入文件 4.读取文件 5.光标定位 6.关闭文件 7.文件编程一般步骤 Linux系统提供了一些常用API如&#xff1a; 打开/创建 open/creat 读写 write /read 光标定位 Iseek 关闭 close 1.打开文件 参数说明 Pathname:要打开的文件名 (含路径&…

Python 通过traceback追溯异常信息

Python 通过traceback追溯异常信息 导入traceback包 import traceback自定义函数 def func_3():return 1 / 0def func_2():func_3()def func_1():func_2()捕捉异常 try:func_1() except Exception as e:traceback_info traceback.format_exc()print("traceback_info"…

桌面图标不显示

问题 桌面图标不显示 解决办法 鼠标 右击->选择-查看->显示桌面图标

深入探讨C存储类和存储期——Storage Duration

&#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; ​—— 热门专栏《维生素C语言》的重制版 —— &#x1f4ad; 写在前面&#xff1a;这是一套 C 语言趣味教学专栏&#xff0c;目前正在火热连载中&#xff0c;欢迎猛戳订阅&#…

Linux CentOS安装抓包解包工具Wireshark图形化界面

1.Wireshark介绍 Wireshark 是一个开源的网络协议分析工具&#xff0c;它能够捕获和分析网络数据包&#xff0c;提供深入的网络故障排除、网络性能优化和安全审计等功能。它支持跨多个操作系统&#xff0c;包括 Windows、macOS 和 Linux。 2.Wireshark主要使用方法 捕获数据…

智能井盖传感器,物联网智能井盖系统

随着城市人口的不断增加和城市化进程的不断推进&#xff0c;城市基础设施的安全和可靠性变得愈发重要&#xff0c;城市窨井盖作为城市基础设施重要组成部分之一&#xff0c;其安全性事关城市安全有序运行和居民生产生活安全保障。 近年来&#xff0c;各地都在加强城市窨井盖治理…

el-backtop返回顶部的使用

2023.8.26今天我学习了如何使用el-backtop组件进行返回页面顶部的效果&#xff0c;效果如&#xff1a; <el-backtop class"el-backtop"style"right: 20px; bottom: 150px;"><i class"el-icon-caret-top"></i></el-backtop&…

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及JDBC示例(4)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

跳跃游戏【贪心算法】

跳跃游戏 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。在这里插入图片…

【Linux】多线程概念线程控制

文章目录 多线程概念Linux下进程和线程的关系pid本质上是轻量级进程id&#xff0c;换句话说&#xff0c;就是线程IDLinux内核是如何创建一个线程的线程的共享和独有线程的优缺点 线程控制POSIX线程库线程创建线程终止线程等待线程分离 多线程概念 Linux下进程和线程的关系 在…