《游戏编程模式》学习笔记(七)状态模式 State Pattern
状态模式的定义
允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样。
举个例子
在书的示例里要求你写一个人物控制器,实现跳跃功能
直觉上来说,我们代码会这么写:
void Heroine::handleInput(Input input)
{if (input == PRESS_B){yVelocity_ = JUMP_VELOCITY;setGraphics(IMAGE_JUMP);}
}
可是这么写不对,因为人物本身应该只能跳一次,这样写的话人物就可以无限按B实现跳跃了。我们加一个bool变量来限制跳跃的情况。
void Heroine::handleInput(Input input)
{if (input == PRESS_B){if (!isJumping_){isJumping_ = true;// 跳跃……}}
}
好的,现在还要加一个趴下的功能,松开按键还得能站起来。如果我们这么加代码:
void Heroine::handleInput(Input input)
{if (input == PRESS_B){// 如果没在跳跃,就跳起来……}else if (input == PRESS_DOWN){if (!isJumping_){setGraphics(IMAGE_DUCK);}}else if (input == RELEASE_DOWN){setGraphics(IMAGE_STAND);}
}
实际上就会出bug,如果玩家在趴下的状态下按了B跳起,此时再松开趴下键,人物就会在空中变成站立的姿势。那么为了防止这种情况的发生,我们又加了一个bool变量来标识趴下的情况:
void Heroine::handleInput(Input input)
{if (input == PRESS_B){if (!isJumping_ && !isDucking_){// 跳跃……}}else if (input == PRESS_DOWN){if (!isJumping_){isDucking_ = true;setGraphics(IMAGE_DUCK);}}else if (input == RELEASE_DOWN){if (isDucking_){isDucking_ = false;setGraphics(IMAGE_STAND);}}
}
这段代码已经很臃肿了,如果我们还想让人物实现移动,是不是又得加个标志位?再进一步,人物如果要实现攻击呢?代码就会越来越复杂……
这个时候我们就需要FSM来救场了。
(这里说的FSM和状态模式是同一个东西,下同)
FSM的要点:
顺着这个思路,这里列出一个最简单的FSM,我们先用枚举定义状态:
enum State
{STATE_STANDING,STATE_JUMPING,STATE_DUCKING,STATE_DIVING
};
在之前的代码中,我们先判断输入,再根据状态的不同做判断。但是在这里,我们让处理状态的代码聚在一起,所以先对状态做分支。这样的话:
void Heroine::handleInput(Input input)
{switch (state_){case STATE_STANDING:if (input == PRESS_B){state_ = STATE_JUMPING;yVelocity_ = JUMP_VELOCITY;setGraphics(IMAGE_JUMP);}else if (input == PRESS_DOWN){state_ = STATE_DUCKING;setGraphics(IMAGE_DUCK);}break;case STATE_JUMPING:if (input == PRESS_DOWN){state_ = STATE_DIVING;setGraphics(IMAGE_DIVE);}break;case STATE_DUCKING:if (input == RELEASE_DOWN){state_ = STATE_STANDING;setGraphics(IMAGE_STAND);}break;}
}
我们扔掉了烦人的标志位,简化了状态的变化,将其变成了字段,然后将处理所有状态的代码都聚集在了一起。这就是最简单的一种FSM。
现在让我们更进一步,看看对于复杂情况,我们要如何构建一个状态模式控制下的人物逻辑。
对于一些复杂的状态,我们有时候既要处理输入,又要处理时间。因为有些状态会根据按下时间的长短进行改变。
比如,现在趴下一定时间后会进行充能,充能后发动的攻击威力更大。
我们以此为目标,按照面向对象的逻辑,我们先写一个状态基类:
class HeroineState
{
public:virtual ~HeroineState() {}virtual void handleInput(Heroine& heroine, Input input) {}virtual void update(Heroine& heroine) {}
};
这里的handleInput()就是处理输入的接口,update()就是处理状态随着时间变化的接口。
我们再以此为基础,写趴下状态,将其单独变为一个类,并且继承这个基类:
class DuckingState : public HeroineState
{
public:DuckingState(): chargeTime_(0){}virtual void handleInput(Heroine& heroine, Input input) {if (input == RELEASE_DOWN){// 改回站立状态……heroine.setGraphics(IMAGE_STAND);}}virtual void update(Heroine& heroine) {chargeTime_++;if (chargeTime_ > MAX_CHARGE){heroine.superBomb();}}private:int chargeTime_;
};
这样,我们在人物Heroine的类中添加当前状态的指针,就可以让人物拥有趴下的状态了:
class Heroine
{
public:virtual void handleInput(Input input){state_->handleInput(*this, input);}virtual void update(){state_->update(*this);}private:HeroineState* state_;
};
要改变状态,只要让指针指向别的地方就OK了。
这就是一个面向对象式的,相对复杂的状态模式的实现方式。是不是还算很简单?
一些细节
如果状态中不存储数据,或者只有全程只有一个人物拥有这些状态,你可以直接静态声明这些状态,将其放在全局存储区内。但如果这些状态包含着数据,就像上边的例子中的chargeTime,你就需要考虑把这些状态实例化,以便管理。
有时候你需要对状态加入入口行为和出口行为来控制状态的转换。例如在每个状态的入口行为方法中改变人物的贴图等等。
原文: https://gpp.tkchu.me/state.html
相关文章:

《游戏编程模式》学习笔记(七)状态模式 State Pattern
状态模式的定义 允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样。 举个例子 在书的示例里要求你写一个人物控制器,实现跳跃功能 直觉上来说,我们代码会这么写: void Heroine::handleInput(Input input…...

博客系统之功能测试
博客系统共有:用户登录功能、发布博客功能、查看文章详情功能、查看文章列表功能、删除文章功能、退出功能 1.登录功能: 1.1测试对象:用户登录 1.2测试用例 方法:判定表 用例 编号 操作步骤预期结果实际结果截图1 1.用户名正确…...
CJS和 ES6 的语法区别
CommonJS 使用 module.exports 导出模块。ES6 使用 export 导出模块。 示例代码: CommonJS(CJS)模块的导出: // 导出模块 module.exports {foo: bar,baz: function() {return qux;} }; ES6 模块的导出: // 导出模…...

ArcGIS Pro如何制作不规则形状图例
在默认的情况下,ArcGIS Pro生成的图例是标准的点、直线和矩形的,对于湖泊等要素而言,这样的表示方式不够直观,我们可以将其优化一下,制作不规则的线和面来代替原有图例,这里为大家介绍一下制作方法…...

微软Win11 Dev预览版Build23526发布
近日,微软Win11 Dev预览版Build23526发布,修复了不少问题。牛比如斯Microsoft,也有这么多bug,所以你写再多bug也不作为奇啊。 主要更新问题 [开始菜单] 修复了在高对比度主题下,打开开始菜单中的“所有应…...

【NEW】视频云存储EasyCVR平台H.265转码配置增加分辨率设置
关于视频分析EasyCVR视频汇聚平台的转码功能,我们在此前的文章中也介绍过不少,感兴趣的用户可以翻阅往期的文章进行了解。 安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求,让平台在内网、专网、VPN、广域网、互联网等各…...

【数据结构】如何用队列实现栈?图文详解(LeetCode)
LeetCode链接:225. 用队列实现栈 - 力扣(LeetCode) 本文默认读者已经掌握栈与队列的基本知识 或者先看我的另一篇博客:【数据结构】栈与队列_字节连结的博客-CSDN博客 做题思路 由于我们使用的是C语言,不能直接使用队…...

Linux 虚拟机Ubuntu22.04版本通过远程连接连接不上,输入ifconfig只能看到127.0.0.1的解决办法
之前给虚拟机配置静态IP之后,可以直接通过主机Vscode远程连接。但是前一段时间把主机的TCP/IPV4静态IP设置了一下之后,再连接虚拟机就连不上了,于是参考解决虚拟机不能上网ifconfig只显示127.0.0.1的问题,又可以连接上了ÿ…...

C语言刷题训练DAY.9
1.线段图案 解题思路: 这里非常简单,我们只需要用一个循环控制打印即可。 解题代码: #include<stdio.h> int main() {int n 0;while ((scanf("%d", &n)) ! EOF){int i 0;for (i 0; i < n; i){printf("*&…...

CTFHub php://input
1.首先看代码: 这里其实就应该想到的是php://伪协议: php://filter、php://input、php://filter用于读取源码 php://input用于执行php代码 2.其次,判断使用php://input伪协议 而执行php://input伪协议条件是allow_url_include是On 可以先利用…...

React Native expo项目修改应用程序名称
https://expo.dev/accounts/xutongbao/projects npm install --global eas-cli && \eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 app.config.js: export default {name: 学习,slug: learn-gpt,owner: x…...

unity 之Transform组件(汇总)
文章目录 理论指导结合例子 理论指导 当在Unity中处理3D场景中的游戏对象时,Transform 组件是至关重要的组件之一。它管理了游戏对象的位置、旋转和缩放,并提供了许多方法来操纵和操作这些属性。以下是关于Transform 组件的详细介绍: 位置&a…...

基于Opencv的虚拟拖拽项目
预备知识 勾股定理 跟随移动算法 手势识别图解 项目源代码 """ 演示一个简单的虚拟拖拽 步骤: 1、opencv 读取视频流 2、在视频图像上画一个方块 3、通过mediapipe库获取手指关节坐标 4、判断手指是否在方块上 5、是,方块跟着移动 6、…...

基于单片机DHT11温湿度NRF2401无线通信控制系统
一、系统方案 本设计采用STC89C5单片机作为主控制器,从机采用DHT11传感器采集温湿度、按键设置报警阀值,液晶1602显示,蜂鸣器报警,无线NRF2401模块。 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统…...

AutoSAR配置与实践(基础篇)2.5 RTE对数据一致性的管理
传送门 点击返回 ->AUTOSAR配置与实践总目录 AutoSAR配置与实践(基础篇)2.5 RTE对数据一致性的管理 一、 数据一致性问题引入二、 数据一致性的管理2.1 RTE管理 (SWC间)2.2 中断保护 (SWC内)2.3 变量保护IRVS (SWC内)2.4 Task分配2.5 任务抢占控制 一…...

ASP.NET WEB API通过SugarSql连接MySQL数据库
注意:VS2022企业版可以,社区版可能存在问题。实体名称和字段和数据库中的要一致。 1、创建项目,安装SqlSugarCore、Pomelo.EntityFrameworkCore.MySql插件 2、文件结构 2、appsettings.json { “Logging”: { “LogLevel”: { “Default”: …...

08-微信小程序视图层
08-微信小程序视图层 文章目录 视图层 ViewWXML数据绑定列表渲染条件渲染模板引用importimport 的作用域include WXSS尺寸单位样式导入内联样式选择器全局样式与局部样式 WXS注意事项页面渲染数据处理 视图层 View 框架的视图层由 WXML 与 WXSS 编写,由组件来进行…...

[机器学习]特征工程:特征降维
特征降维 1、简介 特征降维是指通过减少特征空间中的维度,将高维数据映射到一个低维子空间的过程。 在机器学习和数据分析中,特征降维可以帮助减少数据的复杂性、降低计算成本、提高模型性能和可解释性,以及解决维度灾难等问题。特征降维通…...

12. Docker可视化工具
目录 1、前言 2、Docker UI 2.1、部署Docker UI 2.2、管理容器 3、Portainer 3.1、部署Portainer 3.2、管理容器 3.3、添加远程Docker 4、Shipyard 1、前言 Docker 提供了命令行工具来管理 Docker 的镜像和运行 Docker 的容器。我们也可以使用图形工具来管理 Docker。…...
css层叠关系
文章目录 cascading声明冲突应用重置样式表a元素的类选择器顺序问题 cascading cascading – 层叠 解决声明冲突的过程,浏览器会自动处理;就是计算样式的权重,权重大的就被选择; 声明冲突 是指多个选择器选中同一个标签&#x…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...