1、定义
有限状态机简写为FSM(Finite State Machine),主要分为2大类:
1、若输出只和状态有关而与输入无关,则称为Moore状态机
2、输出不仅和状态有关而且和输入有关系,则称为Mealy状态机
2、 要素
1、现态:是指当前所处的状态。
2、条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
3、动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
4、次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
3、 样例
以《王者荣耀》孙悟空1技能为例:
使用一技能后,孙悟空可以在1秒提升40%移速,在0.2秒内获得护身咒,护身咒可以抵挡一次敌方技能,抵挡成功可以获得短暂无敌和持续4秒的护盾。
| 现态 | 条件 | 动作 | 次态 |
|---|---|---|---|
| 护生法咒(禁用) | 技能点>0 | 升级护生法咒 | 护生法咒(可点击) |
| 护生法咒(可点击) | 点击护生法咒 | (触发0.2秒无敌效果)无动作 | 护生法咒(CD中) |
| 护生法咒(CD中) | 12秒等待 | (CD状态,无法点击)无动作 | 护生法咒(可点击) |

图3-1示例图
4、代码及不足之处
mainwindow.h
#ifndef MAINWINDOW\_H
#define MAINWINDOW\_H
#include QT\_BEGIN\_NAMESPACE
namespace Ui { class MainWindow; }
QT\_END\_NAMESPACE
enum state
{
FORBIDDEN = 0, //禁用状态
CLICKABLE= 1, //可点击
WAITING = 2 //等待中
};
class MainWindow : public QMainWindow
{
Q\_OBJECT
public:
MainWindow(QWidget \*parent = nullptr);
~MainWindow();
void init();
private slots:
void on\_spinBox\_valueChanged(int arg1);
void on\_btn1\_clicked();
private:
Ui::MainWindow \*ui;
state btn\_state = FORBIDDEN;
};
#endif // MAINWINDOW\_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui\_mainwindow.h"
#include MainWindow::MainWindow(QWidget \*parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
init();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::init()
{
//设置范围
ui->spinBox->setRange(0,15);
//设置步长
ui->spinBox->setSingleStep(1);
//设置初始值
ui->spinBox->setValue(0);
//初始禁用技能
ui->btn1->setEnabled(false);
}
void MainWindow::on\_spinBox\_valueChanged(int arg1)
{
//已升级,技能可使用
if(ui->spinBox->value() > 0)
{
ui->btn1->setEnabled(true);
btn\_state = CLICKABLE;
}
//未升级,技能保持禁用状态
if(ui->spinBox->value() == 0)
{
ui->btn1->setEnabled(false);
btn\_state = FORBIDDEN;
}
}
void MainWindow::on\_btn1\_clicked()
{
if(btn\_state == CLICKABLE)
{
btn\_state = WAITING;
ui->label->setText("0.2s无敌,护生法咒进入CD");
QEventLoop eventloop1;
QTimer::singleShot(200, &eventloop1, SLOT(quit()));
eventloop1.exec();
ui->btn1->setEnabled(false);
btn\_state = CLICKABLE;
//进入cd,等待x(5)秒
ui->label->setText("CD12s,请等待......");
QEventLoop eventloop;
QTimer::singleShot(5000, &eventloop, SLOT(quit()));
eventloop.exec();
ui->label->clear();
if(ui->spinBox->value() > 0)
{
ui->btn1->setEnabled(true);
}
}
}
相关控件,如图4-1所示:
图4-1 ui控件
示例不足之处:
1、样例更多的是在“可点击”与“CD中”,进行切换,没有很好的体现出FSM的相关特点。
2、技能状态CD,仿真度不够。
3、理想的情景是,透过状态来判断,且相关状态与ui显示进行绑定。