zoukankan      html  css  js  c++  java
  • Cocos2d 游戏状态机

    加cocos2d 是标题党。

    事实上跟cocos2d无关。

    1.游戏背景介绍



    比方有这么一个"记忆"类的比赛游戏。你和电脑对战。轮到谁的回合,谁翻两张牌。假设两张牌一样,就消掉这两张牌,得2分,能够继续翻牌。假设两张牌不一样,就换一个人。

    直到最后,看谁的得分高。

    先把图画出来会清晰些:


    2.先看下不好的设计方式


    我们来设计游戏大致架构。用一个圈表示一个状态。

    typedef enum{
    	WaitingPlayer,
    	CheckPlayer,
    	AIThink,
    	AIFirstCard,
       AISecondCard,
    	CheckAI
    }MatchGameState;
    

    准备一个_state的变量来记录当前的状态,然后放到update函数里,运行以下的伪代码。


    void MatchLayer::update(float dt){
    	if(allCards.size() == 0){
    		_state = GameOver;
    	}
    
    
    	switch(_state){
    	case WaitingPlayer:
    		if(cardCount == 2){
    			_state = CheckPlayer;
    			cardCount = 0;
    		}
    		break;
    	case CheckPlayer:
    		if(playerCard1 == playerCard2){
              玩家得分
    			_state = WaitingPlayer;
    		}else{
    			_state = AIThink;
             把玩家点开的卡增加到记忆数组中
    		}
    		break;
    	case AIThink:
    		从记忆的数组中找两张同样的,找不到就随机准备两种卡
          _state = AIFirstCard;
    		break;
    	case AIFirstCard:
    		点开第一张卡
    		假设之前没找到同样卡。把这卡增加到记忆数组
    		_state = AISecondCard;
    		break;
    	case AISecondCard:
    		从记忆的数组中找两张同样的:
    		假设找到跟第一张一样,就点开它,找不到就点刚開始的随机第2张,而且把第2张增加到记忆数组中。

    _state = CheckAI; break; case CheckAI: if(AICard1 == AICard2){ _state = AIThink; 电脑得分 }else{ _state = WaitingPlayer; } } }


    这样写是能够,可是随着代码行数增加和业务逻辑变得复杂,兴许会比較难维护。


    3.使用"设计模式"来重构


    我们来看下怎样重构,使用"设计模式"来重构它。我盗了一张图来说明。



    不知道这方法是设计模式中的哪种。

    我们打算把全部的状态都用一个类来实现,它们都继承一个基类叫MatchState,它很easy。

    有一个类来管理全部的状态。

    MatchState例如以下:

    #ifndef _MATCHSTATE_
    #define _MATCHSTATE_
    
    
    class MatchState{
    	public:
    	virtual void Update() = 0;
    
    };
    
    #endif
    

    我这里就没加OnEnter和OnExit了。简单起见。

    为了简单些。就把Layer作为状态管理类,在Layer中增加一个属性,来表示当前状态:

    MatchState* currentState;

    在基本的Layer中增加一个方法来切换当前状态:

    void changeState(MatchState* state){
    	delete currentState;
    	currentState = state;
    }
    

    在update中就简单了,一直运行当前状态的Update方法:


    void MatchLayer::update(float dt){
    	if(allCards.size() == 0){
    		_state = GameOver;
    	}
    	currentState->Update();
    }
    

    每一个状态的详细业务逻辑都写在自己的类中。

    比方WaitingPlayerState类:

    #ifndef _WAITINGPLAYERSTATE_H
    #define _WAITINGPLAYERSTATE_H
    
    #include "MatchState.h"
    
    class WaitingPlayerState : public MatchState{
    public:
    	WaitingPlayerState(){
       }
    	void Update(){
          if(sGlobal->cardCount == 2){
    			sGlobal->matchLayer->changeState(new CheckPlayerCardsState());
    		}
       }
    };
    
    
    #endif
    

    这里sGlobal是一个单例。

    再比方CheckPlayerCardsState

    #ifndef _CHECKPLAYERCARDSSTATE_H
    #define _CHECKPLAYERCARDSSTATE_H
    
    #include "MatchState.h"
    
    class CheckPlayerCardsState : public MatchState
    {
    public:
    	void Update(){
          //很复杂的详细业务逻辑写在这里
          if(playerCard1 == playerCard2){
              玩家得分
    			sGlobal->matchLayer->changeState(new WaitingPlayerState ());
    		}else{
    			sGlobal->matchLayer->changeState(new AIThinkState ());
             把玩家点开的卡增加到记忆数组中
    		}
    
      }
    
    };
    
    
    #endif
    

    其它状态类就不写出来了,总之通过这样把一个状态用一个类来表示,大大的使代码简洁些,扩展性强些。


    http://www.waitingfy.com/archives/1273

  • 相关阅读:
    第009讲:了不起的分支和循环3
    Term_Application
    十大编程算法助程序员走上高手之路
    每天工作4小时的程序员
    编程真相_节选
    Sublime_Snippet
    VIM资源管理
    微信企业号开发资源整理
    vitruviano
    VIM_git
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5135509.html
Copyright © 2011-2022 走看看