这是GAMEGEMS中
![](/icons/73518de.gif)
第 3章
![](/icons/73518de.gif)
第
![](/icons/73518yi.gif)
部分
![](/icons/73518dou.gif)
番
![](/icons/73518de.gif)
不好
![](/icons/73518dou2.gif)
你可以直接阅读原文
![](/icons/73518dou2.gif)
原本以为这是人工智能
![](/icons/73518de.gif)
部分
![](/icons/73518dou.gif)
看到
![](/icons/73518yi.gif)
半才发现只是
![](/icons/73518yi.gif)
个简单
![](/icons/73518de.gif)
框架
![](/icons/73518dou2.gif)
如果你想学人工智能
![](/icons/73518dou.gif)
这里没有
![](/icons/73518dou.gif)
就不要浪费时间了
![](/icons/73518dou2.gif)
由于本人水平有限
![](/icons/73518dou.gif)
其中难免会出现原则性
![](/icons/73518de.gif)
![](/icons/73518cuowu.gif)
![](/icons/73518dou.gif)
希望指正
![](/icons/73518dou2.gif)
关键字:有限状态机、状态、输入、状态转换、输出状态当前状态
![](/icons/73518yi.gif)
个有限状态机类
在这篇文章中
![](/icons/73518dou.gif)
我们创建了
![](/icons/73518yi.gif)
个通用
![](/icons/73518de.gif)
有限状态机(FSM)
![](/icons/73518de.gif)
C
![](/icons/73518jiajia.gif)
类
![](/icons/73518dou2.gif)
有限状态机是计算机科学和数学理论
![](/icons/73518de.gif)
抽象
![](/icons/73518dou.gif)
它在许多
![](/icons/73518de.gif)
方面是很有用处
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
这里我们不去讲解有限状态机
![](/icons/73518de.gif)
理论上
![](/icons/73518de.gif)
知识
![](/icons/73518dou2.gif)
而是讲如何实现
![](/icons/73518yi.gif)
个“有限状态机”
![](/icons/73518dou.gif)
“有限状态机”在游戏
![](/icons/73518de.gif)
人工智能方面是很有用处
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
“有限状态机”是由有限
![](/icons/73518de.gif)
状态组成
![](/icons/73518de.gif)
![](/icons/73518yi.gif)
个机制
![](/icons/73518dou2.gif)
![](/icons/73518yi.gif)
个“状态”就是
![](/icons/73518yi.gif)
个状况
![](/icons/73518dou2.gif)
你考虑
![](/icons/73518yi.gif)
下门;它
![](/icons/73518de.gif)
“状态”有“开”或“关”以及“锁”和“未锁”
![](/icons/73518dou2.gif)
对于
![](/icons/73518yi.gif)
个“有限状态机”
![](/icons/73518dou.gif)
它应该有
![](/icons/73518yi.gif)
个“输入”
![](/icons/73518dou2.gif)
这个“输入”可以影响“状态转换”
![](/icons/73518dou2.gif)
“有限状态机”应该有
![](/icons/73518yi.gif)
个简单(或复杂)
![](/icons/73518de.gif)
状态转换
![](/icons/73518hanshu.gif)
![](/icons/73518dou.gif)
这个
![](/icons/73518hanshu.gif)
可以决定什么状态可以变成“当前状态”
![](/icons/73518dou2.gif)
这个当前
![](/icons/73518de.gif)
新状态被称为“有限状态机”
![](/icons/73518de.gif)
“状态转换”
![](/icons/73518de.gif)
“输出状态”
![](/icons/73518dou2.gif)
如果你对这个概念有些迷惑
![](/icons/73518dou.gif)
就把“门”做为理解“有限状态机”
![](/icons/73518de.gif)
例子
![](/icons/73518dou2.gif)
当
![](/icons/73518yi.gif)
个“门”处于“关闭”状态和“锁”状态
![](/icons/73518dou.gif)
当你输入了“使用钥匙”时
![](/icons/73518dou.gif)
门
![](/icons/73518de.gif)
状态可以变成“未锁”状态(即“状态转换”
![](/icons/73518de.gif)
输出状态
![](/icons/73518dou.gif)
也就是门
![](/icons/73518de.gif)
当前状态)
![](/icons/73518dou2.gif)
当你输入了“使用手”时
![](/icons/73518dou.gif)
门
![](/icons/73518de.gif)
状态可以转换成“开”
![](/icons/73518de.gif)
状态
![](/icons/73518dou2.gif)
当门处于“开”
![](/icons/73518de.gif)
状态时
![](/icons/73518dou.gif)
我们输入“使用手”时
![](/icons/73518dou.gif)
会使门
![](/icons/73518de.gif)
状态重新回到“关”
![](/icons/73518de.gif)
状态
![](/icons/73518dou2.gif)
当“门”处于“关”
![](/icons/73518de.gif)
状态时
![](/icons/73518dou.gif)
我们输入“使用钥匙”时
![](/icons/73518dou.gif)
这将会使门重新回到“锁”
![](/icons/73518de.gif)
状态
![](/icons/73518dou2.gif)
当门处于“锁”
![](/icons/73518de.gif)
状态
![](/icons/73518dou.gif)
我们输入“使用手”
![](/icons/73518dou.gif)
就不能把门
![](/icons/73518de.gif)
状态转换到“开”
![](/icons/73518de.gif)
状态
![](/icons/73518dou.gif)
门仍然会保持“锁”
![](/icons/73518de.gif)
状态
![](/icons/73518dou2.gif)
还有
![](/icons/73518dou.gif)
当门处于“开”
![](/icons/73518de.gif)
状态时
![](/icons/73518dou.gif)
我们输入“使用钥匙”是不能把门
![](/icons/73518de.gif)
状态转换成“锁”
![](/icons/73518de.gif)
状态
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
总的
![](/icons/73518dou.gif)
“有限状态机”是
![](/icons/73518yi.gif)
个有限
![](/icons/73518de.gif)
状态组成
![](/icons/73518de.gif)
![](/icons/73518dou.gif)
其中
![](/icons/73518de.gif)
![](/icons/73518yi.gif)
个状态是“当前状态”
![](/icons/73518dou2.gif)
“有限状态机”可以接受
![](/icons/73518yi.gif)
个“输入”
![](/icons/73518dou.gif)
这个“输入”
![](/icons/73518de.gif)
结果将导致
![](/icons/73518yi.gif)
个“状态转换”
![](/icons/73518de.gif)
发生(即从“当前状态”转换到“输出”状态)
![](/icons/73518dou2.gif)
这个“状态转换”是基于“状态转换
![](/icons/73518hanshu.gif)
”
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
状态转换完成的后
![](/icons/73518dou.gif)
“输出状态”即变成了“当前状态”
![](/icons/73518dou2.gif)
输入 状态转换
![](/icons/73518hanshu.gif)
当前状态-----
![](/icons/73518smhr.gif)
状态转换-------------
![](/icons/73518smhr.gif)
输出状态(当前状态)
那么
![](/icons/73518dou.gif)
人们是如何将这个概念应用到游戏
![](/icons/73518de.gif)
AI系统中
![](/icons/73518de.gif)
呢?有限状态机
![](/icons/73518de.gif)
功能很多:管理游戏世界、模拟NPC
![](/icons/73518de.gif)
思维、维护游戏状态、分析玩游戏
![](/icons/73518de.gif)
人
![](/icons/73518de.gif)
输入
![](/icons/73518dou.gif)
或者管理
![](/icons/73518yi.gif)
个对象
![](/icons/73518de.gif)
状态
![](/icons/73518dou2.gif)
假如在
![](/icons/73518yi.gif)
个冒险游戏中有
![](/icons/73518yi.gif)
个NPC
![](/icons/73518dou.gif)
名字可以叫MONSTER
![](/icons/73518dou2.gif)
我们可以先假设这个MONSTER在游戏中有如下
![](/icons/73518de.gif)
状态:BERSERK、RAGE、MAD、ANNOYED以及UNCARING
![](/icons/73518dou2.gif)
(前几个状态不好分别)
![](/icons/73518dou2.gif)
假设
![](/icons/73518dou.gif)
MONSTER对于区别
![](/icons/73518de.gif)
状态可以执行区别
![](/icons/73518de.gif)
操作
![](/icons/73518dou.gif)
并且假设你已经有了这些区别操作
![](/icons/73518de.gif)
代码
![](/icons/73518dou2.gif)
我们这时可以使用“有限状态机”来模拟这个MONSTER
![](/icons/73518de.gif)
行为了
![](/icons/73518dou2.gif)
只要我们给出区别
![](/icons/73518de.gif)
“输入”
![](/icons/73518dou.gif)
MONSTER就会做出区别
![](/icons/73518de.gif)
反应
![](/icons/73518dou2.gif)
我们再来指出这些“输入”是什么:PLAYER SEEN、PLAYER ATTACKS、PLAYERGONE、MONSTER HURT、MONSTER HEALED
![](/icons/73518dou2.gif)
这样我们可以得到
![](/icons/73518yi.gif)
个状态转换
![](/icons/73518de.gif)
表格
![](/icons/73518dou.gif)
如下:游戏状态转换表:
当前状态 输入 输出状态
UNCARING PLAYER SEEN ANNOYED
UNCARING PLAYER ATTACKS MAD
MAD MONSTER HURT RAGE
MAD MONSTER HEALED UNCARING
RAGE MONSTER HURT BERSERK
RAGE MONSTER HEALED ANNOYED
BERSERK MONSTER HURT BERSERK
BERSERK MONSTER HEALED RAGE
ANNOYED PLAYER GONE UNCARING
ANNOYED PLAYER ATTACKS RAGE
ANNOYED MONSTER HEALED UNCARING
根据上面
![](/icons/73518de.gif)
这个表格
![](/icons/73518dou.gif)
我们可以很容易
![](/icons/73518de.gif)
画出
![](/icons/73518yi.gif)
个MONSTER
![](/icons/73518de.gif)
“状态转换图”
![](/icons/73518dou.gif)
MONSTER
![](/icons/73518de.gif)
每
![](/icons/73518yi.gif)
个状态就是图中
![](/icons/73518de.gif)
顶点
![](/icons/73518dou2.gif)
因此
![](/icons/73518dou.gif)
根据当前状态和对FSM
![](/icons/73518de.gif)
输入
![](/icons/73518dou.gif)
MONSTER
![](/icons/73518de.gif)
状态将被改变
![](/icons/73518dou2.gif)
这时根据MONSTER
![](/icons/73518de.gif)
状态执行相应操作
![](/icons/73518de.gif)
代码(假设已经实现)将被执行
![](/icons/73518dou.gif)
这时MONSTER好像是具备了人工智能
![](/icons/73518dou2.gif)
显然
![](/icons/73518dou.gif)
我们可以定义更多
![](/icons/73518de.gif)
“状态”
![](/icons/73518dou.gif)
写出更多
![](/icons/73518de.gif)
“输入”
![](/icons/73518dou.gif)
写出更多
![](/icons/73518de.gif)
“状态转换”
![](/icons/73518dou.gif)
这样
![](/icons/73518dou.gif)
MONSTER可以表现
![](/icons/73518de.gif)
更真实
![](/icons/73518dou.gif)
生动
![](/icons/73518dou.gif)
当然
![](/icons/73518dou.gif)
这些游戏
![](/icons/73518de.gif)
规则问题应该是策划制定
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
以及FSMstate
现在
![](/icons/73518dou.gif)
我们如何把这些思路方法变成现实?使用FSM
![](/icons/73518class.gif)
和它
![](/icons/73518de.gif)
组成部分FSMstate可以实现这些想法
![](/icons/73518dou2.gif)
定义FSMstate
![](/icons/73518class.gif)
FSMstate
{
unsigned m_usNumberOfTransition; //状态
![](/icons/73518de.gif)
最大数
![](/icons/73518int.gif)
* m_piInputs; //为了转换而使用
![](/icons/73518de.gif)
输入
![](/icons/73518shuzu.gif)
![](/icons/73518int.gif)
* m_piOutputState; //输出状态
![](/icons/73518shuzu.gif)
![](/icons/73518int.gif)
m_iStateID; //这个状态
![](/icons/73518de.gif)
唯
![](/icons/73518yi.gif)
标识符
public:
//
![](/icons/73518yi.gif)
个构造
![](/icons/73518hanshu.gif)
![](/icons/73518dou.gif)
可以接受这个状态
![](/icons/73518de.gif)
ID和它支持
![](/icons/73518de.gif)
转换数目
FSMstate(
![](/icons/73518int.gif)
iStateID,unsigned usTransitions);
//析构
![](/icons/73518hanshu.gif)
![](/icons/73518dou.gif)
清除分配
![](/icons/73518de.gif)
![](/icons/73518shuzu.gif)
~FSMstate
![](/icons/73518kh.gif)
;
//取这个状态
![](/icons/73518de.gif)
ID
![](/icons/73518int.gif)
GetID
![](/icons/73518kh.gif)
{
![](/icons/73518return.gif)
m_iStateID;}
//向
![](/icons/73518shuzu.gif)
中增加状态转换
void AddTransition(
![](/icons/73518int.gif)
iInput,
![](/icons/73518int.gif)
iOutputID);
//从
![](/icons/73518shuzu.gif)
中删除
![](/icons/73518yi.gif)
个状态转换
void DeleteTransition(
![](/icons/73518int.gif)
iOutputID);
//进行状态转换并得到输出状态
![](/icons/73518int.gif)
GetOutput(
![](/icons/73518int.gif)
iInput);
};
对这个类
![](/icons/73518de.gif)
分析:
功能:主要是实现和
![](/icons/73518yi.gif)
个状态相关
![](/icons/73518de.gif)
各种操作
![](/icons/73518dou2.gif)
我们前面假设了MONSTER
![](/icons/73518de.gif)
各种状态:
#
![](/icons/73518define.gif)
STATE_ID_UNCARING 1
#
![](/icons/73518define.gif)
STATE_ID_MAD 2
#
![](/icons/73518define.gif)
STATE_ID_RAGE 3
#
![](/icons/73518define.gif)
STATE_ID_BERSERK 4
#
![](/icons/73518define.gif)
STATE_ID_ANNOYED 5
状态转换所需
![](/icons/73518de.gif)
输入有:
#
![](/icons/73518define.gif)
INPUT_ID_PLAYER_SEEN 1
#
![](/icons/73518define.gif)
INPUT_ID_PLAYER_ATTACK 2
#
![](/icons/73518define.gif)
INPUT_ID_PLAYER_GONE 3
#
![](/icons/73518define.gif)
INPUT_ID_MONSTER_HURT 4
#
![](/icons/73518define.gif)
INPUT_ID_MONSTER_HEALED 5
以上是 5个状态
![](/icons/73518de.gif)
标识符
![](/icons/73518dou2.gif)
我们就要声明5个FSMstate
![](/icons/73518de.gif)
例子
![](/icons/73518dou.gif)
每
![](/icons/73518yi.gif)
个例子代表
![](/icons/73518yi.gif)
个状态和和的有关
![](/icons/73518de.gif)
操作
![](/icons/73518dou2.gif)
假设我们先处理状态STATE_ID_MAD
类成员变量m_iStateID就等于STATE_ID_MAD类成员变量m_usNumberOfTransition就是可由这个状态转换成
![](/icons/73518de.gif)
状态
![](/icons/73518de.gif)
个数
![](/icons/73518dou.gif)
前面有
![](/icons/73518yi.gif)
个表
![](/icons/73518dou.gif)
其中有两个状态可以由这个状态产生
![](/icons/73518dou.gif)
它们分别是STATE_ID_UNCARING和STATE_ID_RAGE
![](/icons/73518dou2.gif)
这时
![](/icons/73518dou.gif)
m_usNumberOfTransition等于2
m_piInputs是
![](/icons/73518yi.gif)
个指针变量
![](/icons/73518dou.gif)
它保存和这个状态相关
![](/icons/73518de.gif)
输入
![](/icons/73518dou.gif)
在前面
![](/icons/73518de.gif)
表中我们知道和STATE_ID_MAD相关
![](/icons/73518de.gif)
输入为
INPUT_ID_MONSTER_HURT和INPUT_ID_MONSTER_HEALED
![](/icons/73518dou.gif)
因此m_piInputs中存放
![](/icons/73518de.gif)
是这两个数据
![](/icons/73518dou2.gif)
而m_piOutputState存放
![](/icons/73518de.gif)
是和STATE_ID_MAD相关
![](/icons/73518de.gif)
状态
![](/icons/73518dou.gif)
即STATE_ID_RAGE和STATE_ID_UNCARING
![](/icons/73518dou.gif)
这样
![](/icons/73518dou.gif)
m_piOutputState中存放
![](/icons/73518de.gif)
数据便是这两个值
![](/icons/73518dou2.gif)
以上是对成员变量
![](/icons/73518de.gif)
解释
![](/icons/73518dou.gif)
下面解释成员
![](/icons/73518hanshu.gif)
:
构造
![](/icons/73518hanshu.gif)
FSMstate::FSMstate(
![](/icons/73518int.gif)
iStateID,unsigned usTransitions)
{
![](/icons/73518if.gif)
(!usTransitions) //如果给出
![](/icons/73518de.gif)
转换数量为0
![](/icons/73518dou.gif)
就算为1
m_usNumberOfTransitions=1;
![](/icons/73518else.gif)
m_usNumberOfTransitions=usTransitions;
//将状态
![](/icons/73518de.gif)
ID保存起来
m_iStateID=iStateID;
//分配内存空间
try
{
m_piInputs=
![](/icons/73518int.gif)
[m_usNumberOfTransitions];
for(
![](/icons/73518int.gif)
i=0;i<m_usNumberOfTransitions;
![](/icons/73518jiajia.gif)
i)
m_piInputs[i]=0;
}
catch(...)
{
throw;
}
try
{
m_piOutputState=
![](/icons/73518int.gif)
[m_usNumberOfTransition];
for(
![](/icons/73518int.gif)
i=0;i<m_usNumberOfTransitions;
![](/icons/73518jiajia.gif)
i)
m_piOutputState[i]=0;
}
catch(...)
{
delete
![](/icons/73518zhk2.gif)
m_piInputs;
throw;
}
}
这就是构造
![](/icons/73518hanshu.gif)
![](/icons/73518dou.gif)
在FSMstate类中共有 4个成员变量
![](/icons/73518dou.gif)
在这个
![](/icons/73518hanshu.gif)
中全部被
![](/icons/73518chushi.gif)
化了
![](/icons/73518dou2.gif)
FSMstate是
![](/icons/73518yi.gif)
个类
![](/icons/73518dou.gif)
是否还记得MONSTER
![](/icons/73518de.gif)
状态(如MAD、UNCARING)
![](/icons/73518dou2.gif)
这个类就是实现对MONSTER
![](/icons/73518de.gif)
![](/icons/73518yi.gif)
个状态
![](/icons/73518de.gif)
管理
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
假如这个状态是STATE_ID_MAD
![](/icons/73518dou.gif)
和这个状态相关
![](/icons/73518de.gif)
状态有两个
![](/icons/73518dou.gif)
上面已经讲过了
![](/icons/73518dou2.gif)
这时我们给成员变量赋值
![](/icons/73518dou.gif)
在这个具体例子中它们
![](/icons/73518de.gif)
值如下:
m_usNumberOfTransition=2
m_piInput[0]=0;
m_piInput[1]=0;
m_piOutputState[0]=0;
m_piOutputState[1]=0;
m_iStateID=STATE_ID_MAD;
析构
![](/icons/73518hanshu.gif)
:
FSMState::~FSMState
![](/icons/73518kh.gif)
{
delete
![](/icons/73518zhk2.gif)
m_piInputs;
delete
![](/icons/73518zhk2.gif)
m_piOutputState;
}
析构
![](/icons/73518hanshu.gif)
将动态分配
![](/icons/73518de.gif)
存储空间释放了
![](/icons/73518dou2.gif)
void FSMstate::AddTransition(
![](/icons/73518int.gif)
iInput,
![](/icons/73518int.gif)
iOutputID)
{
for(
![](/icons/73518int.gif)
i=0;i<m_usNumberOfTransitions;
![](/icons/73518jiajia.gif)
i)
![](/icons/73518if.gif)
(!m_piOutputState[i])
![](/icons/73518break.gif)
;
![](/icons/73518if.gif)
(i<m_usNumberOfTransition)
{
m_piOutputState[i]=iOutputID;
m_piInputs[i]=iInput;
}
}
这个
![](/icons/73518hanshu.gif)
给两个前面构造
![](/icons/73518hanshu.gif)
动态分配
![](/icons/73518de.gif)
空间加入数据
![](/icons/73518dou.gif)
首先要找到两个
![](/icons/73518shuzu.gif)
中找到适当
![](/icons/73518de.gif)
位置
![](/icons/73518dou.gif)
的后
![](/icons/73518dou.gif)
如果位置是合法
![](/icons/73518de.gif)
我们就可以把数据加入这两个
![](/icons/73518shuzu.gif)
中
![](/icons/73518dou2.gif)
![](/icons/73518yinwei.gif)
STATE_ID_MAD和两个状态有关
![](/icons/73518dou.gif)
因此
![](/icons/73518dou.gif)
我们可以
![](/icons/73518diaoyong.gif)
两次这个
![](/icons/73518hanshu.gif)
![](/icons/73518dou.gif)
把这两个状态加入到类中:
AddTransition(INPUT_ID_MONSTER_HURT,STATE_ID_RAGE);
AddTransition(INPUT_ID_MONSTER_HEALED,STATE_ID_UNCARING)
这样
![](/icons/73518dou.gif)
和状态STATE_ID_MAD相关
![](/icons/73518de.gif)
“状态”和“输入”也加入了
![](/icons/73518dou2.gif)
void FSMstate::DeleteTransition(
![](/icons/73518int.gif)
iOutputID)
{
// 遍历每
![](/icons/73518yi.gif)
个输出状态
for(
![](/icons/73518int.gif)
i=0;i<m_usNumberOfTransitions;
![](/icons/73518jiajia.gif)
i)
{
//如果找到输出状态
![](/icons/73518dou.gif)
退出循环
![](/icons/73518if.gif)
(m_piOutputState[i]
![](/icons/73518dd.gif)
iOutputID)
![](/icons/73518break.gif)
;
}
//如果没有找到输出状态
![](/icons/73518dou.gif)
返回
![](/icons/73518if.gif)
(i>=m_usNumberOfTransitions)
![](/icons/73518return.gif)
;
//将输出状态
![](/icons/73518de.gif)
内容置0
m_piInputs[i]=0;
m_piOutputState[i]=0;
//被删除
![](/icons/73518de.gif)
输出状态
![](/icons/73518de.gif)
后面
![](/icons/73518de.gif)
输出状态前移
for(;i<(m_usNumberOfTransition-1);
![](/icons/73518jiajia.gif)
i)
{
![](/icons/73518if.gif)
(!m_piOUtputState[i])
![](/icons/73518break.gif)
;
m_piInputs[i]=m_piInputs[i+1];
m_piOutputState[i]=m_piOutputState[i+1];
}
//最后面
![](/icons/73518de.gif)
输出状态置0
m_piInputs[i]=0;
m_piOutputState[i]=0;
}
这个
![](/icons/73518hanshu.gif)
是要删除和
![](/icons/73518yi.gif)
个状态相关
![](/icons/73518de.gif)
输出状态
![](/icons/73518dou2.gif)
设
![](/icons/73518yi.gif)
个状态STATE_ID_MAD
![](/icons/73518dou.gif)
和的相关
![](/icons/73518de.gif)
状态有两个STATE_ID_RAGE,STATE_ID_UNCARING
![](/icons/73518dou.gif)
当然这是经过
![](/icons/73518chushi.gif)
化以及前面
![](/icons/73518de.gif)
添加状态
![](/icons/73518hanshu.gif)
的后
![](/icons/73518dou.gif)
产生了这两个相关
![](/icons/73518de.gif)
状态
![](/icons/73518dou2.gif)
你想删除哪
![](/icons/73518yi.gif)
个?如果你想删除相关
![](/icons/73518de.gif)
输出状态
![](/icons/73518dou.gif)
只要在删除
![](/icons/73518hanshu.gif)
中指出那个状态即可
![](/icons/73518dou.gif)
例如:
DeleteTransition(STATE_ID_RAGE);
你就可以删除输出状态STATE_ID_RAGE了
![](/icons/73518dou2.gif)
![](/icons/73518int.gif)
FSMstate::GetOutput(
![](/icons/73518int.gif)
iInput)
{
//先给输出状态赋值(如果未找到和输入对应
![](/icons/73518de.gif)
输出状态时
![](/icons/73518dou.gif)
返回这个值)
![](/icons/73518int.gif)
iOutputID=m_iStateID;
//遍历输出状态
for(
![](/icons/73518int.gif)
i=0;i<m_usNumberOfTransitions;
![](/icons/73518jiajia.gif)
i)
{
//如果没找到
![](/icons/73518dou.gif)
退出循环
![](/icons/73518if.gif)
(!m_piOutputState[i])
![](/icons/73518break.gif)
;
//如果找到了和“输入”相对应
![](/icons/73518de.gif)
“输出状态”
![](/icons/73518dou.gif)
进行赋值
![](/icons/73518dou2.gif)
![](/icons/73518if.gif)
(iInput
![](/icons/73518dd.gif)
m_piInputs[i])
{
iOutputID=m_piOutputState[i];
![](/icons/73518break.gif)
;
}
}
//返回“输出状态”
![](/icons/73518return.gif)
(iOutputID);
}
这个
![](/icons/73518hanshu.gif)
功能是返回和“输入”相对应
![](/icons/73518de.gif)
“输出状态”
![](/icons/73518de.gif)
标识
![](/icons/73518dou2.gif)
如果没有和“输入”相对应
![](/icons/73518de.gif)
“输出状态”
![](/icons/73518dou.gif)
返回原来
![](/icons/73518de.gif)
状态
![](/icons/73518dou.gif)
如果有和的对应
![](/icons/73518de.gif)
“输出状态”
![](/icons/73518dou.gif)
返回这个状态
![](/icons/73518de.gif)
ID
![](/icons/73518dou2.gif)
下面定义
![](/icons/73518de.gif)
是FSM
![](/icons/73518class.gif)
![](/icons/73518dou.gif)
这个类用于维护FSMstate对象集合
![](/icons/73518dou2.gif)
![](/icons/73518class.gif)
FSM
![](/icons/73518class.gif)
{
State_Map m_map; //包括了状态机
![](/icons/73518de.gif)
所有状态
![](/icons/73518int.gif)
m_iCurrentState; //当前状态
![](/icons/73518de.gif)
ID
public:
FSM
![](/icons/73518class.gif)
(
![](/icons/73518int.gif)
iStateID); //
![](/icons/73518chushi.gif)
化状态
~FSM
![](/icons/73518class.gif)
![](/icons/73518kh.gif)
//返回当前状态ID
![](/icons/73518int.gif)
GetCurrentState
![](/icons/73518kh.gif)
{
![](/icons/73518return.gif)
m_iCurrentState;}
//设置当前状态ID
void SetCurrentState(
![](/icons/73518int.gif)
iStateID) {m_iCurrentState=iStateID;}
//返回FSMstate对象指针
FSMstate* GetState(
![](/icons/73518int.gif)
iStateID);
//增加状态对象指针
void AddState(FSMstate* pState);
//删除状态对象指针
void DeleteState(
![](/icons/73518int.gif)
iStateID);
//根据“当前状态”和“输入”完成“状态”
![](/icons/73518de.gif)
转换
![](/icons/73518dou2.gif)
![](/icons/73518int.gif)
StateTransition(
![](/icons/73518int.gif)
iInput);
};
FSM
![](/icons/73518class.gif)
::m_map是FSMstate对象
![](/icons/73518de.gif)
集合
![](/icons/73518dou.gif)
是从STL<map>中实现
![](/icons/73518de.gif)
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
::m_iCurrentState是FSMstate对象
![](/icons/73518de.gif)
状态标识
![](/icons/73518dou.gif)
是“有限状态机”
![](/icons/73518de.gif)
当前状态
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
::GetCurrentState
![](/icons/73518kh.gif)
可以用的访问当前
![](/icons/73518de.gif)
FSMstate对象
![](/icons/73518de.gif)
状态
![](/icons/73518de.gif)
标识符
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
::SetCurrentState
![](/icons/73518kh.gif)
可以设置当前FSMstate对象
![](/icons/73518de.gif)
状态
![](/icons/73518de.gif)
标识符
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
::GetState
![](/icons/73518kh.gif)
可以取得有限状态机中
![](/icons/73518de.gif)
任何FSMstate对象
![](/icons/73518de.gif)
指针
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
::AddState
![](/icons/73518kh.gif)
增加有限状态机中
![](/icons/73518de.gif)
FSMstate对象
![](/icons/73518dou2.gif)
FSM
![](/icons/73518class.gif)
::DeleteState
![](/icons/73518kh.gif)
删除有限状态机中
![](/icons/73518de.gif)
FSMstate对象
FSM
![](/icons/73518class.gif)
::StateTransition
![](/icons/73518kh.gif)
![](/icons/73518chushi.gif)
化状态转换
![](/icons/73518dou.gif)
根据输入返回输出状态
![](/icons/73518dou2.gif)
这个类使用了STL
![](/icons/73518dou.gif)
我不知道它如何用:)
![](/icons/73518dou2.gif)
听说是高人才使用它
![](/icons/73518dou.gif)
高人起码要写过上万行
![](/icons/73518de.gif)
代码
![](/icons/73518dou2.gif)
因此不能详细介绍这个类了
总的
![](/icons/73518dou.gif)
可以这么理解这两个类FSMstate,FSM
![](/icons/73518class.gif)
.FSMstate代表了
![](/icons/73518yi.gif)
个状态以及和状态相关
![](/icons/73518de.gif)
数据和操作
![](/icons/73518dou2.gif)
如在MONSTER中有 5个状态
![](/icons/73518dou.gif)
我们就要声明 5个类
![](/icons/73518de.gif)
对象
![](/icons/73518dou.gif)
每个对象中包括了和这个状态相关
![](/icons/73518de.gif)
状态
![](/icons/73518dou.gif)
输入和各种转换
![](/icons/73518hanshu.gif)
![](/icons/73518dou2.gif)
可以说FSMstate是对每
![](/icons/73518yi.gif)
个状态
![](/icons/73518de.gif)
封装(包括相关数据和操作)
![](/icons/73518dou.gif)
游戏中
![](/icons/73518de.gif)
对象有多少状态
![](/icons/73518dou.gif)
就要声明多少个FSMstate对象
![](/icons/73518dou2.gif)
而FSM
![](/icons/73518class.gif)
则是对这若干个FSMstate对象(这个例子中MONSTER有 5个状态)进行
![](/icons/73518de.gif)
封装
![](/icons/73518dou2.gif)
在FSM
![](/icons/73518class.gif)
中指明了若干个FSMstate中哪
![](/icons/73518yi.gif)
个是当前
![](/icons/73518de.gif)
MONSTER拥有
![](/icons/73518de.gif)
状态并且可以设置
![](/icons/73518dou.gif)
得到以及删除状态
![](/icons/73518dou.gif)
并且可以进行状态间
![](/icons/73518de.gif)
转换
![](/icons/73518dou2.gif)
总的:游戏中
![](/icons/73518de.gif)
MONSTER有多少状态
![](/icons/73518dou.gif)
游戏中就要声明多少
![](/icons/73518de.gif)
FSMstate对象
![](/icons/73518dou.gif)
每
![](/icons/73518yi.gif)
个FSMstate对象包括了和特定
![](/icons/73518de.gif)
状态相关
![](/icons/73518de.gif)
数据和操作
![](/icons/73518dou2.gif)
而FSM
![](/icons/73518class.gif)
只有
![](/icons/73518yi.gif)
个
![](/icons/73518dou.gif)
它用于协调若干个FSMstate的间
![](/icons/73518de.gif)
关系和操作
![](/icons/73518dou2.gif)
下面是如何在游戏中使用两个类
![](/icons/73518de.gif)
例子:
首先是创建FSMstate对象(若干个)
![](/icons/73518dou.gif)
有多少状态就要循环多少次
![](/icons/73518dou.gif)
下面是增加STATE_ID_UNCARING状态
![](/icons/73518de.gif)
例子:
FSMstate* pFSMstate=NULL;
//创建状态
try
{
//第
![](/icons/73518yi.gif)
个参数是增加状态
![](/icons/73518de.gif)
标识
![](/icons/73518dou.gif)
第 2个参数指明了和这个
//状态相关
![](/icons/73518de.gif)
状态
![](/icons/73518de.gif)
个数
![](/icons/73518dou2.gif)
pFSMstate=
![](/icons/73518new.gif)
FSMstate(STATE_ID_UNCARING,2);
}
catch(...)
{
throw;
}
//的后给这个状态加入相关
![](/icons/73518de.gif)
“输入”和“输出状态”
pFSMstate->AddTransition(INPUT_ID_PLAYER_SEEN,STATE_ID_ANNOYED);
pFSMstate->AddTransition(INPUT_ID_PLAYER_ATTACKS,STATE_ID_MAD);
这个
![](/icons/73518hanshu.gif)
指明了和特定状态相关
![](/icons/73518de.gif)
“输入”和“输出状态”
比如第
![](/icons/73518yi.gif)
个
![](/icons/73518hanshu.gif)
![](/icons/73518dou.gif)
它表明如果我要输入
![](/icons/73518yi.gif)
个INPUT_ID_PLAYER_SEEN
![](/icons/73518dou.gif)
这时就会产生
![](/icons/73518yi.gif)
个输出状态
![](/icons/73518dou.gif)
STATE_ID_ANNOYED
![](/icons/73518dou2.gif)
我们应该为每
![](/icons/73518yi.gif)
个状态做上面
![](/icons/73518de.gif)
事情
![](/icons/73518dou.gif)
这里就略过了
![](/icons/73518dou2.gif)
的后我们要声明
![](/icons/73518yi.gif)
个FSM
![](/icons/73518class.gif)
对象
![](/icons/73518dou.gif)
用于协调上面
![](/icons/73518de.gif)
FSMstate对象的间
![](/icons/73518de.gif)
关系
![](/icons/73518dou2.gif)
try
{
m_pFSM
![](/icons/73518class.gif)
=
![](/icons/73518new.gif)
FSM
![](/icons/73518class.gif)
(STATE_ID_UNCARING);
}
catch(...)
{
throw;
}
上面指明了MONSTER
![](/icons/73518de.gif)
当前状态是STATE_ID_UNCARING最后将FSMstate对象分别加入到FSM
![](/icons/73518class.gif)
中
![](/icons/73518dou2.gif)
下面介绍如何使用FSM
![](/icons/73518class.gif)
使用十分简单
![](/icons/73518dou.gif)
只要我们给出
![](/icons/73518yi.gif)
个“输入”
![](/icons/73518dou.gif)
的后
![](/icons/73518dou.gif)
我们便可以得到
![](/icons/73518yi.gif)
个“输出状态”
![](/icons/73518dou.gif)
根据这个“输出状态”我们执行相应
![](/icons/73518de.gif)
操作
![](/icons/73518dou.gif)
最后
![](/icons/73518dou.gif)
把这个“输出状态”变成MONSTER
![](/icons/73518de.gif)
当前状态
![](/icons/73518dou2.gif)
在游戏中发生了
![](/icons/73518yi.gif)
些事情
![](/icons/73518dou.gif)
如玩游戏
![](/icons/73518de.gif)
人指出他控制
![](/icons/73518de.gif)
人进攻MONSTER(用鼠标点击了MONSTER)
![](/icons/73518dou.gif)
这时会产生
![](/icons/73518yi.gif)
个“输入”iInputID=INPUT_ID_PLAYER_ATTACK;
这时
![](/icons/73518dou.gif)
我们
![](/icons/73518diaoyong.gif)
状态转换
![](/icons/73518hanshu.gif)
:
m_iOutputState=m_pFSM
![](/icons/73518class.gif)
->StateTransition(iInputID);
这时
![](/icons/73518dou.gif)
我们
![](/icons/73518de.gif)
“输入”对MONSTER产生了刺激
![](/icons/73518dou.gif)
产生了
![](/icons/73518yi.gif)
个“输出状态”
![](/icons/73518dou2.gif)
这时我们根据这个输出状态
![](/icons/73518diaoyong.gif)
相应
![](/icons/73518de.gif)
代码执行就可以了
![](/icons/73518dou.gif)
这时
![](/icons/73518de.gif)
MONSTER好像有应反了
![](/icons/73518dou.gif)
我们说它有了简单
![](/icons/73518de.gif)
智能
![](/icons/73518dou2.gif)
![](/icons/73518if.gif)
(m_iOutputState
![](/icons/73518dd.gif)
STATE_ID_MAD)
{
//some code for the monster to act mad
}
当然
![](/icons/73518dou.gif)
我们也应该把其它状态执行
![](/icons/73518de.gif)
操作也写出来
![](/icons/73518dou.gif)
但只写
![](/icons/73518yi.gif)
个就可以了
![](/icons/73518dou2.gif)
使用这个状态机就是这么简单
![](/icons/73518dou2.gif)
总的
![](/icons/73518dou.gif)
FSM
![](/icons/73518class.gif)
不是全部
![](/icons/73518de.gif)
人工智能
![](/icons/73518dou.gif)
相反
![](/icons/73518dou.gif)
它只是
![](/icons/73518yi.gif)
个框架
![](/icons/73518dou.gif)
![](/icons/73518yi.gif)
个开始智能需要
![](/icons/73518de.gif)
还很多
![](/icons/73518dou2.gif)
只要你可以分出“状态”
![](/icons/73518dou.gif)
并且知道什么“输入”产生什么“输出状态”就可以了
![](/icons/73518dou.gif)
当然这是
![](/icons/73518yi.gif)
个游戏
![](/icons/73518de.gif)
规则
![](/icons/73518dou.gif)
策划应当完成这个部分?
延伸阅读
最新评论