【FSM 】有效状态机~以王者荣耀吉吉国王1技能为模板的小示例

1、定义 有限状态机简写为 FSM (Finite State Machine),主要分为2大类: 1、若输出只和状态有关而与输入无关,则称为Moore状态机 2、输出不仅和状态有关而且和输入有关系,

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显示进行绑定。