State Pattern1

°ÔÀÓ¿¡¼­ ÀÚÁÖ »ç¿ëµÇ´Â C++ State ÆÐÅÏÀ» JavaScript·Î ¹Ù²ãº¸ÀÚ.

C++ ÄÚµå

´Ù¿î·Îµå:
IState.h
StateManager.cpp
StateManager.h
statePattern.cpp
Unit.cpp
Unit.h
statePattern_cpp.zip

IState ½ºÅÂÀÌÆ® ÀÎÅÍÆäÀ̽º·Î ½ºÅ×ÀÌÆ®°¡ ½ÃÀÛÇÒ¶§ Enter, ³¡³¯¶§ Exit°¡ ½ÇÇàµÈ´Ù.
·çÇÁ¿¡¼­´Â Execute ÇÔ¼ö°¡ ½ÇÇàµÈ´Ù.
Ãß°¡ µÇ´Â State´Â IState¸¦ »ó¼ÓÇؼ­ Ãß°¡ ÇÏ¸é µÈ´Ù.
class IState {
public:
    virtual void Enter(Unit* unit) = 0;
    virtual void Execute(Unit* unit, float dt) = 0;
    virtual void Exit(Unit* unit) = 0;
};

State¸¦ »ó¼ÓÇؼ­ RunState¸¦ ¸¸µé¾ú´Ù.
¿©±â¼­´Â State¸¦ °ø¿ëÀ¸·Î »ç¿ëÇϱâ À§ÇØ ½Ì±ÛÆÐÅÏÀ¸·Î ¸¸µé¾ú´Ù.
class RunState : public IState
{
protected:
    static RunState* m_instance;
    RunState()
    {
    }

public:
    static RunState* GetInstance()
    {
        return m_instance;
    }

    static RunState* CreateInstance()
    {
        if (!m_instance)
            m_instance = new RunState();
        return m_instance;
    }
    static void ReleaseInstance()
    {
        if (m_instance)
            delete m_instance;
        m_instance = nullptr;
    }

    virtual ~RunState()
    {
        printf("RunState delete\n");
    }
   
    virtual void Enter(Unit* unit) override
    {
        printf("RunState enter\n");
    }
    virtual void Execute(Unit* unit, float dt) override
    {
        printf("RunState execute\n");
    }
    virtual void Exit(Unit* unit) override
    {
        printf("RunState exit\n");
    }
};

ÄÚµå »ç¿ë ¿¹

int main()
{
    RunState::CreateInstance();
    AttackState::CreateInstance();

    Player player;
    player.ChangeState(RunState::GetInstance());
    player.Update(0.1f);
    player.ChangeState(AttackState::GetInstance());
    player.Update(0.2f);

    RunState::ReleaseInstance();
    AttackState::ReleaseInstance();
    return 0;
}


IState.h
StateManager.cpp
StateManager.h
statePattern.cpp
Unit.cpp
Unit.h

°á°ú)
RunState enter
RunState execute
RunState exit
AttackState enter
AttackState execute
RunState delete
AttackState delete

ÀÚ¹Ù½ºÅ©¸³Æ® ÄÚµå

´Ù¿î·Îµå: statePattern.html

C++À» ÀÚ¹Ù½ºÅ©¸³Æ®·Î º¯È¯ ÇÏ¿´´Ù.

½Ì±ÛÅÏ ÆÐÅÏÀ» »ç¿ëÇϱâ À§ÇØ ´ÙÀ½ Äڵ带 »ç¿ëÇÏ¿´´Ù.

static get instance()
static set instance(obj)
static createInstance()

class¿¡¼­ Á¤ÀûÀÎ ÇÔ¼ö´Â ÀÚ¹Ù½ºÅ©¸³Æ®¿¡¼­ Áö¿øÀÌ µÇÁö¸¸  Á¤ÀûÀÎ º¯¼öµå´Â ÀÚ¹Ù½ºÅ©¸³Æ®¿¡¼­ Áö¿øÀÌ ¾ÈµÈ´Ù.
¿ìȸ ÇÏ´Â ¹æ¹ýÀº ´ÙÀ½ÀåÀ» Âü°íÇÑ´Ù.

javascript class static variable:  tutorial7.html

class IState {
    enter(unit) {
        console.log('enter');
    }
    execute(unit, dt) {
        console.log('execute');
    }
    exit(unit) {
        console.log('exit');
    }
};

class StateManager {   
    constructor(uUnit) {
        this.unit = uUnit;
        this.previousState = null;
        this.currentState = null;
        this.nextState = null;
    }
    changeState(uState) {
        this.previousState = this.currentState;
        if (this.currentState != null) {           
            this.currentState.exit(this.unit);
        }
        this.currentState = uState;
        this.currentState.enter(this.unit);    
    }
    update(dt) {
        if (this.currentState != null)
            this.currentState.execute(this.unit, dt);
    }
}


class RunState extends  StateInterface {
    static get instance() {
        return this._instance;
    }

    static set instance(obj) {
        this._instance = obj;
    }
    
    static createInstance() {
        if(!RunState.instance) {
            console.log('create RunState Instance');
            RunState.instance = new RunState();
        }
    }
    
    constructor() {
        super();
    }
   
    enter(unit) {
        console.log('RunState enter');
    }
    execute(unit, dt) {
        console.log('RunState execute');
    }
    exit(unit) {
        console.log('RunState exit');
    }
}

class AttackState extends  StateInterface {
    static get instance() {
        return this._instance;
    }

    static set instance(obj) {
        this._instance = obj;
    }
    
    static createInstance() {
        if(!AttackState.instance) {
            console.log('create AttackState Instance');
            AttackState.instance = new AttackState();
        }
    }
    
    constructor() {
        super();
    }
   
    enter(unit) {
        console.log('AttackState enter');
    }
    execute(unit, dt) {
        console.log('AttackState execute');
    }
    exit(unit) {
        console.log('AttackState exit');
    }
}

class Player {
    constructor() {
        this.stateManager = new StateManager(this);
    }
 
    changeState(uState) {
        this.stateManager.changeState(uState);
    }
    
    update(dt) {
        this.stateManager.update(dt);
    }
}

player = new Player();
RunState.createInstance();
AttackState.createInstance();

player.changeState(RunState.instance);
player.update(0.1);
player.changeState(AttackState.instance);
player.update(0.2);

½ÇÇà°á°ú)
create RunState Instance
create AttackState Instance
RunState enter
RunState execute
RunState exit
AttackState enter
AttackState execute

Âü°í)
C++ State Pattern
http://dolphin.ivyro.net/file/cplusplus/state_pattern.html
https://www.haroldserrano.com/blog/implementing-a-state-design-pattern

Javascript °ÔÀÓ ±âÃÊ - »óÅ °ü¸®
https://codeincomplete.com/posts/javascript-game-foundations-state-management/
https://github.com/jakesgordon/javascript-state-machine/

¸¶¸®¿À State
http://h5y1m141.hatenablog.com/entry/20110516/p1
https://x-team.com/blog/react-application-state-management/

ÆÐÅϵé....
https://devstudioonline.com/article/good-coding-pattern-and-technique-in-javascript

»óÅ ³ª¿­
http://robdodson.me/take-control-of-your-app-with-the-javascript-state-patten/

ÀÌÇØ ¾È°¡´Â ÄÚµå
https://www.smashingmagazine.com/2018/01/rise-state-machines/

ÀÚ¹Ù½ºÅ©¸³Æ® ÆÁ
https://www.smashingmagazine.com/2010/04/seven-javascript-things-i-wish-i-knew-much-earlier-in-my-career/

ÀÚ¹Ù½ºÅ©¸³Æ® Ãà¾à
http://plaboratory.org/archives/3415