C++有限状态机的实现

//待完善
有限状态机是一个很常用的技术,在流程控制和游戏AI中都比较实用,因为状态机编程简单又很符合直觉。与有限状态机类似的是设计模式中的状态模式。本文是参考《Programming Game AI by Example》
一、
记得最开始工作时候也接触过有限状态机,当时是一个长长的用switch写成的状态机,理解它的时候真的很困难。
所以现在使用一套内置规则到状态内部去,来控制状态的转换。
现在就来制作一个有限状态机。
作为一个关于使用状态机创建一个智能体的实际案例,我们先模拟这样一个场景。是作为一个简单的基于文本的控制台应用实现的,所以你将不得不想象遍地的风滚草,叽叽嘎嘎的矿井支柱,时有荒漠的灰尘吹进你的眼睛。任何状态的改变或者状态动作的输出将作为文本传送到控制台窗口。我使用这种只有普通的文本的方法是因为它能将有限状态机的机制演示清楚而不会由于更复杂的环境而增加编码混乱。
而这些位置每一个都代表了一个状态,因为我们是使用内置规则来控制状态机的转换,“我”在到达一个位置之后要干什么,都会由当前所处的状态和一些属性值来决定。
BaseGameEntity类,用来作为所有游戏对象的基类,主要为游戏对象提供了一个ID,以及每一帧更新时调用的纯虚函数Update。

class BaseGameEntity
{
private:int m_ID;                  // 每个实体具有一个唯一的识别数字static int m_iNextValidID; //这是下一个有效的ID。每次BaseGameEntity被实例化这个值就被更新void SetID(int val);//在构造函数中调用这个来确认ID被正确设置。在设置ID和增量前,它校验传递给方法的值是//大于还是等于下一个有效的ID。public:BaseGameEntity(int id) { SetID(id); }virtual ~BaseGameEntity() {}virtual void Update() = 0;//所有的实体必须执行一个更新函数int ID() const { return m_ID; }
};

使用一个枚举类型管理所有可能到达的地点,sweetHome、school、company、beerLady 分别代表家、学校、实习公司、啤酒阿姨这四个地点。在 Me 类中,对“我”所特有的属性进行了定义,如心情值( m_iMoodForDoingStuffs ),金钱数( m_iMoneyInCard ),能力( m_iAbilityLevel ),疲劳( m_iFatigue ),以及这些属性的阈值,用来在状态转移中起作用。随后定义的方法表明了这些属性如何变化,并为其他类查看这些属性暴露了接口。

enum location_type
{sweetHome,school,company,beerLady,
};class Miner : public BaseGameEntity
{
private:State* m_pCurrentState;location_type m_Location;//指向一个状态实例的指针State* m_pCurrentState;//矿工当前所处的位置location_type m_Location;//矿工的包中装了多少天然金块int m_iGoldcarried;//矿工在银行存了多少钱int m_iMoneyInBank;//价值越高,矿工越口渴int m_iThirst;//价值越高,矿工越累int m_iFatigue;public:Miner(int ID);				void Update(); void ChangeState(State *pNewState);location_type Location()const { return m_Location; }void ChangeLocation(const location_type goal) { m_Location = goal; }int Ability()const { return m_iAbilityLevel; }void SetAbilityLevel(const int val) { m_iAbilityLevel = val; }void AddToAbility(const int val);int MoneyInCard()const { return m_iMoneyInCard; }void SetMoneyInCard(const int val) { m_iMoneyInCard = val; }void ThePayDay(const int val);bool Fatigued()const;bool Rested()const;void DecreaseFatigue(const int val) { m_iFatigue -= val; }void IncreaseFatigue(const int val) { m_iFatigue += val; }bool LowMood()const;void DecreaseMood(const int val) { m_iMoodForDoingStuffs -= val; }void IncreaseMood(const int val) { m_iMoodForDoingStuffs += val; }bool FeelPoor()const;void BuyTheBeer() { m_iMoodForDoingStuffs = Max_Mood; m_iMoneyInCard -= 500; }
};

在这里插入图片描述

接下来是状态 State 类,这是一个纯虚类(抽象类),作为状态对象的一个通用接口。

class State
{
public:virtual ~State(){}virtual void Enter(Miner*) = 0;//当状态被进入时执行这个virtual void Execute(Miner*) = 0;//每一更新步骤调用virtual void Exit(Miner*) = 0;//退出是执行这个};

在这里使用单例模式实现每一个状态,一切从简,不考虑线程安全。分别针对不同的地点,定义在每个地点的状态类,代码如下:


class GoWorkAndEarnMoney:public State
{
private:GoWorkAndEarnMoney() = default;
public:static GoWorkAndEarnMoney* Instance();virtual void Enter(Me* pMe);virtual void Execute(Me* pMe);virtual void Exit(Me* pMe);
};class GoSchoolAndStudy:public State
{
private:GoSchoolAndStudy() = default;
public:static GoSchoolAndStudy* Instance();virtual void Enter(Me* pMe);virtual void Execute(Me* pMe);virtual void Exit(Me* pMe);
};class GoHomeAndSleep:public State
{
private:GoHomeAndSleep() = default;
public:static GoHomeAndSleep* Instance();virtual void Enter(Me* pMe);virtual void Execute(Me* pMe);virtual void Exit(Me* pMe);
};class GoBar:public State
{
private:GoBar() = default;
public:static GoBar* Instance();virtual void Enter(Me* pMe);virtual void Execute(Me* pMe);virtual void Exit(Me* pMe);
};

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

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

相关文章

手势希尔排序

void shell_sort(int *data, int length){int gap0;int i0,j0;for(gaplength/2;gap>1;gap/2){//组内插入排序for(igap;i<length;i){int temp data[i];for(ji-gap;j>0&&temp<data[j];jj-gap){data[jgap]data[j];}data[jgap]temp;}} }

Android之android.os.Build

一、类概述&#xff1a;从系统属性中提取设备硬件和版本信息。 二、内部类&#xff1a; 1、Build.VERSION 各种版本字符串 2、Build.VERSION_CODES 目前已知的版本代码的枚举类 三、常量&#xff1a;UNKNOWN 当一个版本属性不知道时所设定的值。其字符串值为 “unknown” 。 …

C++ unsigned char*转化为string的形式

unsigned char*转化为string int main(int argc,char **argv){//unsigned char * 转化为string//参考链接 https://www.itdaan.com/tw/4ff531a5e6651468a5b7c6d95927ba3dunsigned char *foo;unsigned char str[] "Hello world";string strHH;foo str;strHH.append…

KMP算法面试题

面试题&#xff1a;写一个在一个宇符串(n)中寻找一个子串&#xff08;m)第一个位置的函数。 10G的日志中&#xff0c;如何快速地查找关键字&#xff1f;

C++对于程序调试很有用的系统自带的名字

简单介绍 __func__当前调试的函数的名字__FILE__存放文件名的字符串的字面值__LINE__存放当前行号的整型字面值__TIME__存放文件编译时间的字符串的字面值__DATE__存放文件编译日期的字符串的字面值 例子 if(word.size() < threshold){cerr << "Error: " …

Android中List、Set、Map数据结构详解

Android中一般使用的数据结构有java中的基础数据结构List&#xff0c;Set&#xff0c;Map。还有一些Android中特有的几个&#xff0c;SparseArray(使用Map时Key是int类型的时候可以用这个代替)等。 继承关系&#xff1a; Collection<–List<–ArrayList Collection<…

Android设计模式之——单例模式

一、介绍 单例模式是应用最广的模式之一&#xff0c;也可能是很多初级工程师唯一会使用的设计模式。在应用这个模式时&#xff0c;单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象&#xff0c;这样有利于我们协调系统整体的行为。 二、定义 …

我的职业生涯规划(软件工程)

以后笔记先在语雀整理 方便一点https://www.yuque.com/juhao-pqdor/goeie3 整理一下自己的笔记 弥补一下以前没写博客的遗憾吧 二十载求学路将尽&#xff0c;行文至此&#xff0c;思绪万千。求学之路始于家乡&#xff0c;竿转热河&#xff0c;而今终于石门。一路行之如人饮水…

C++ primer第六章6.5函数的学习 之特殊用途的语言特性

6.5.1 默认实参 将反复出现的数值称为函数的默认实参&#xff0c;调用含有默认实参的时候可以包含该实参也可以不包含比如程序打开页面会有一个默认的宽高&#xff0c;如果用户不喜欢也允许用户自由指定与默认数值不同的数值&#xff0c;具体例子如下图所示 typedef string::s…

Android设计模式之——Builder模式

一、介绍 Builder模式是一步一步创建一个复杂对象的创建型模式&#xff0c;它允许用户在不知道内部构建细节的情况下&#xff0c;可以更精细的控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦&#xff0c;使得构建过程和部件的表示隔离开来。 因为一个复…

c++后端开发书籍推荐

推荐书籍: 略读80% 精读50% C&#xff1a; C Primer Plus C和指针&#xff08;入门书 不只是指针&#xff09; C陷阱与缺陷&#xff08;宏相关&#xff09; C专家编程 C&#xff1a; 有专门的视频 C primer C程序设计原理与实践&#xff08;c之父写的 入门经典&#xff09; Ef…

C++ primer第六章6.6函数匹配

函数的匹配 当重载函数的形参数量相等以及某些形参的类型可以由其他的类型转化得来的时候&#xff0c;对于函数的匹配就会变得很难 确定候选函数和可行函数 函数匹配的第一步就是选定本次调用对应的重载函数集&#xff0c;集合中的函数称为候选函数。候选函数具有两个特征&am…

Android设计模式之——原型模式

一、介绍 原型模式是一个创建型的模式。原型二字表明了该模型应该有一个样板实例&#xff0c;用户从这个样板对象中复制出一个内部属性一致的对象&#xff0c;这个过程也就是我们俗称的“克隆”。被复制的实例就是我们所称的“原型”&#xff0c;这个原型也是可定制的。原型模…

C++ primer第六章6.7函数指针

函数指针 函数指针指向的是函数而不是对象。和其他指针一样&#xff0c;函数指针指向某种特定的类型。函数的类型由他的返回类型和形参类型共同决定&#xff0c;而与函数的名字无关。 //比较两个string对象的长度 bool lengthCompare(const string &,const string &);…

Android设计模式之——工厂方法模式

一、介绍 工厂方法模式&#xff08;Factory Pattern&#xff09;&#xff0c;是创建型设计模式之一。工厂方法模式是一种结构简单的模式&#xff0c;其在我们平时开发中应用很广泛&#xff0c;也许你并不知道&#xff0c;但是你已经使用了无数次该模式了&#xff0c;如Android…

C++ primer第十八章 18.1小结 异常处理

18.1 异常处理 异常处理机制&#xff0c;允许程序独立开发的部分能够在运行的时候出现的问题进行通信并且做出相应的处理&#xff0c;异常的处理使得我们可以将问题的检测和处理分离开来。程序的一部分负责检测问题的出现&#xff0c;然后将解决这个问题的任务传递给程序的另一…

浅谈equals与==

一、前言 示例代码&#xff1a; public static void main(String[] args) throws IOException {String str1 new String("hello");String str2 new String("hello");String str3 "cde";String str4 "cde";int i1 3;int i2 3;In…

针对C++异常的学习

源码 头文件 sdf_exception.h #pragma once#include <exception> #include <string>namespace sdf {namespace common{using sdf_error_code_t uint32_t;class SdfException : std::exception{public:explicit SdfException(sdf_error_code_t errorCode) : erro…

Android设计模式之——抽象工厂模式

一、介绍 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff0c;也是创建型设计模式之一。前一节我们已经了解了工厂方法模式&#xff0c;那么这个抽象工厂又是怎么一回事呢&#xff1f;大家联想一下现实生活中的工厂肯定都是具体的&#xff0c;也就是说…

Android设计模式之——策略模式

一、介绍 在软件开发中也常常遇到这样的情况&#xff1a;实现某一个功能可以有多种算法或者策略&#xff0c;我们根据实际情况选择不同的算法或者策略来完成该功能。例如&#xff0c;排序算法&#xff0c;可以使用插入排序、归并排序、冒泡排序等。 针对这种情况&#xff0c;…