美文网首页Cocos2d游戏开发技巧
[因为我不懂啊]-什么是状态机编程(设计模式)(1)

[因为我不懂啊]-什么是状态机编程(设计模式)(1)

作者: qufl | 来源:发表于2016-09-18 02:20 被阅读371次

    本阶段对状态机编程的理解:

    • 把物体的操作逻辑分为几个状态,每个状态有对应的处理
    • 操作时,只需要去改变物体状态即可,物体会自动根据状态执行对应的处理

    这段理解放入示例中是这样的:

    • 电梯有四个状态:开门、关门、运动、停止
    • 电梯在达到某个状态时,会输出对应的log作为处理
    • 电梯对外有一个goto指定楼层的接口

    下面来详细设计一下相关的内容

    • 状态[枚举]
      - 开门
      - 关门
      - 运动
      - 静止

    • 电梯[类]
      - 状态标志[变量]
      - 设置状态[方法]
      - 开门的处理[方法]
      - 关门的处理[方法]
      - 运动的处理[方法]
      - 停止的处理[方法]

      - 移动到楼层[方法]
      - 当前楼层[变量]
      - 目标楼层[变量]
      

    实现代码:

    //
    //  ElevatorOne.hpp
    //  QFLTest
    //
    //  Created by QuFangliu on 16/9/18.
    //
    //
    
    /*
        电梯测试_1
     
        运行逻辑:
            停止->开门(进入)->关门->运动->停止->开门(离开)->关门
     
        ????我tm写的什么
     
     
     */
    
    #ifndef ElevatorOne_hpp
    #define ElevatorOne_hpp
    
    #include <stdio.h>
    
    enum ElevatorOneState
    {
        State_Opening   = 1,    //电梯门打开状态
        State_Closing   = 2,    //电梯门关闭状态
        State_Running   = 3,    //电梯运动状态
        State_Stopping  = 4     //电梯静止状态
    };
    
    class ElevatorOne
    {
    public:
        ElevatorOne();
        virtual ~ElevatorOne();
        
    public:
        void gotoFloor(int nFloor);
        
    private:
        void setState(ElevatorOneState eState); //只能通过事件来改变电梯的状态,电梯自动运行
        
        void open();    //开门
        void close();   //关门
        void run();     //运动
        void stop();    //减速到停止
        
    private:
        ElevatorOneState m_eState;  //电梯状态标志
        int m_nTargetFloor;         //电梯目标楼层
        int m_nFloor;               //电梯所在楼层
    };
    
    #endif /* ElevatorOne_hpp */
    
    //
    //  ElevatorOne.cpp
    //  QFLTest
    //
    //  Created by QuFangliu on 16/9/18.
    //
    //
    
    #include "ElevatorOne.hpp"
    #include <iostream>
    
    #define QFLLOG(_text_)  do  \
                            {   \
                                std::cout << _text_ << std::endl;   \
                            } while (false) \
    
    ElevatorOne::ElevatorOne()
    {
        m_eState = ElevatorOneState::State_Stopping;    //默认静止状态
        m_nFloor = 1;                                   //默认楼层1楼
        m_nTargetFloor = 1;                             //默认目标1楼
    }
    
    ElevatorOne::~ElevatorOne()
    {
        
    }
    
    //操作
    void ElevatorOne::gotoFloor(int nFloor)
    {
        if (m_nTargetFloor == nFloor) {
            //不需要运动
            QFLLOG("Elevator is here.");
        }
        else {
            //设置目标楼层
            m_nTargetFloor = nFloor;
            //状态转换
            this->setState(ElevatorOneState::State_Opening);
        }
    }
    
    //状态转换
    void ElevatorOne::setState(ElevatorOneState eState)
    {
        m_eState = eState;
        
        switch (eState) {
            case State_Opening:
                this->open();
                break;
            case State_Closing:
                this->close();
                break;
            case State_Running:
                this->run();
                break;
            case State_Stopping:
                this->stop();
                break;
            default:
                break;
        }
    }
    
    //运行逻辑
    //开门
    void ElevatorOne::open()
    {
        QFLLOG("Elevator open...");
        
        //下一个状态必然是close
        this->setState(ElevatorOneState::State_Closing);
    }
    //关门
    void ElevatorOne::close()
    {
        QFLLOG("Elevator close...");
        
        //根据目标楼层,判断进入怎样的状态
        if (m_nFloor != m_nTargetFloor) {
            this->setState(ElevatorOneState::State_Running);
        }
        else {
            //结束状态
        }
    }
    //运行
    void ElevatorOne::run()
    {
        QFLLOG("Elevator run..." << m_nTargetFloor);
        
        //移动到对应的楼层
        m_nFloor = m_nTargetFloor;
        
        //下一个状态必然是stop
        this->setState(ElevatorOneState::State_Stopping);
    }
    //静止
    void ElevatorOne::stop()
    {
        QFLLOG("Elevator stop...");
        
        //下一个状态必然是open
        this->setState(ElevatorOneState::State_Opening);
    }
    

    上面就是Elevator的完整逻辑代码,运行测试过程代码如下,直接放在 int main(void)中即可,我示例中是写在按钮的触发事件中。

        //elevator
        auto pElevator = new ElevatorOne();
        pElevator->gotoFloor(20);
        pElevator->gotoFloor(20);//移动到本层试试
    

    输出结果:
    Elevator open...
    Elevator close...
    Elevator run...20
    Elevator stop...
    Elevator open...
    Elevator close...
    Elevator is here.


    总结:
    1.我不知道为什么要写一个gotoFloor的函数,只是觉得在测试中直接去写setState会很别扭,不符合正常控制过程(虽然在其他的博客中看到的关于FSM的实例代码,调用时都是直接写了几个setState)。
    2.虽然这里有区分4个状态,每个状态也有对应的处理函数。但是我觉得这里使用状态并没有什么用。因为[使用setState转移到下一个状态],都可以直接用[下一个状态的处理函数]来替换。也就是说
    //状态转换 this->setState(ElevatorOneState::State_Opening);
    可以直接使用
    //状态转换 this->open();
    来代替。


    求懂FSM的小伙伴评论指点。

    相关文章

      网友评论

      • HelloBobi:2.虽然这里有区分4个状态,每个状态也有对应的处理函数。但是我觉得这里使用状态并没有什么用。因为[使用setState转移到下一个状态],都可以直接用[下一个状态的处理函数]来替换。也就是说
        //状态转换 this->setState(ElevatorOneState::State_Opening);
        可以直接使用
        //状态转换 this->open();
        来代替。

        这么做是因为你的状态流程是固定的,有上一个状态自动无需输入就过滤到下一个状态,
        如果是玩家, 在站立状态,可能会根据输入来决定是起跳,还是下蹲
        qufl:@HelloBobi 确实,如果应用场景复杂起来,尤其是状态的切换触发部分由外部控制,就很有必要了

      本文标题:[因为我不懂啊]-什么是状态机编程(设计模式)(1)

      本文链接:https://www.haomeiwen.com/subject/ofvwettx.html