Part3:Handling the States of your Game/游戏状态处理

来自:http://www.codeproject.com/Articles/30775/TetroGL-An-OpenGL-Game-Tutorial-in-C-for-Win32-pla


目录

1、Handling the States of your Game

2、补充  简单使用

1、Handling the States of your Game

In almost every game, you will encounter different 'states': Usually you have a main menu (which allows the user to start a new game, set some options, view the highscores), the main play state, the highscore state, etc. It quickly becomes a mess in your code if you have to manage everything in the same class: The update and draw functions becomes a gigantic switch in which you have to take care of all the possible states, all the variables are mixed together which makes the code hard to maintain, and so on. Luckily, there's an easy design pattern that elegantly solves the problem: The state pattern. The principle is quite simple: Each state of your game has its own separate class which inherits from a common 'state' class. So, in our example we have a class for the menu, a class for the play state, a class for the highscores, and so on. A state manager class keeps track of the current state of the game and redirect every call to this active state (draw, update, key down, ...). When you have to switch to another state, you simply inform the state manager of the new state. You can find quite a lot of nice articles about this pattern on the net, so I won't enter into much details here. Take a look at the first link in the references if you want to go more in details about this design pattern.

In the sources, you will find a CStateManagerclass which looks like:

// Manages the different states of the game.
class CStateManager
{
public:
    // Default constructor
    CStateManager();
    // Default destructor
    ~CStateManager();

    // Switches to another active state.
    void ChangeState(CGameState* pNewState)
    {
        if (m_pActiveState)
            m_pActiveState->LeaveState();
        m_pActiveState = pNewState;
        m_pActiveState->EnterState();
    }

    // Returns the current active state.
    CGameState* GetActiveState()  { return m_pActiveState; }

    // 'Events' function, they are simply redirected to
    // the active state.
    void OnKeyDown(WPARAM wKey);
    void OnKeyUp(WPARAM wKey);
    void OnChar(WPARAM wChar);
    void Update(DWORD dwCurrentTime);
    void Draw();

private:
    // Active State of the game (intro, play, ...)
    CGameState* m_pActiveState;        
};

This class manages the current state of the game and redirects all 'events' call to it: If you look at the implementation ofOnKeyDown,OnKeyUp,UpdateandDraw, you will see that they simply call the same function on them_pActiveState instance. When switching to another state, the state manager calls theLeaveStateof the current state and theEnterStateof the new state. States can implement those functions to do special initialization or clean up when the state becomes active or inactive.

The CGameState is very easy too:

// Base class for the different states
// of the game.
class CGameState
{
public:
    // Constructor
    CGameState(CStateManager* pManager);
    // Destructor
    virtual ~CGameState();

    // The different 'events' functions. Child classes can 
    // implement the ones in which they are interested in.
    virtual void OnKeyDown(WPARAM ) { }
    virtual void OnKeyUp(WPARAM )   { }
    virtual void OnChar(WPARAM )   { }
    virtual void Update(DWORD )  { }
    virtual void Draw()  { }

    // Functions called when the state is entered or left
    // (transition from/to another state).
    virtual void EnterState()  { }
    virtual void LeaveState()   { }

protected:
    // Helper function to switch to a new active state.
    void ChangeState(CGameState* pNewState);

    // The state manager.
    CStateManager* m_pStateManager;
};
The different classes that will manage the states of the game inherit from this class. These child classes can then implement the 'event' functions in which they are interested. The ChangeStatefunction is there only as a helper function: It simply call ChangeStateof the CStateManager.

//原文end........

2、补充  简单使用

CStateManager类的其它部分:

CStateManager::CStateManager() : m_pActiveState(NULL)
{
}

CStateManager::~CStateManager()
{
}

void CStateManager::OnKeyDown(WPARAM wKey)
{
	if (m_pActiveState)
		m_pActiveState->OnKeyDown(wKey);
}

void CStateManager::OnKeyUp(WPARAM wKey)
{
	if (m_pActiveState)
		m_pActiveState->OnKeyUp(wKey);
}

void CStateManager::OnChar(WPARAM wChar)
{
	if (m_pActiveState)
		m_pActiveState->OnChar(wChar);
}

void CStateManager::Update(DWORD dwCurrentTime)
{
	if (m_pActiveState)
		m_pActiveState->Update(dwCurrentTime);
}

void CStateManager::Draw()
{
	if (m_pActiveState)
		m_pActiveState->Draw();
}
CGameState类的其它部分:

CGameState::CGameState(CStateManager* pManager)
  : m_pStateManager(pManager)
{
}

CGameState::~CGameState()
{
}

void CGameState::ChangeState(CGameState* pNewState)
{
	m_pStateManager->ChangeState(pNewState);
}
简单使用:

其中,CMenuState类、CPlayState类、CHighScoreState类均继承自CGameState类。

CStateManager *m_pStateManager;

CMainWindow::CMainWindow(..)
{
//...
    m_pStateManager = new CStateManager;
    m_pStateManager->ChangeState(CMenuState::GetInstance(m_pStateManager));
}

void CMainWindow::ProcessEvent(UINT Message, WPARAM wParam, LPARAM lParam)
{
    switch (Message)
    {
    // ...
    // Keydown event
    case WM_KEYDOWN :
        m_pStateManager->OnKeyDown(wParam);
        break;
    // Keyup event
    case WM_KEYUP :
        m_pStateManager->OnKeyUp(wParam);
        break;
    // Character event
    case WM_CHAR:
        m_pStateManager->OnChar(wParam);
        break;
    }
}

void CMainWindow::Update(DWORD dwCurrentTime)
{
    m_pStateManager->Update(dwCurrentTime);
}

void CMainWindow::Draw()
{
    // ...
    m_pStateManager->Draw();
    // ...
}
//...
//...
void CMenuState::SelectionChosen()
{
	switch (m_iCurrentSelection)
	{
	case 0:
		if (!m_pCurrentGame)
			m_pCurrentGame = CPlayState::GetInstance(m_pStateManager);
		m_pCurrentGame->Reset();
		ChangeState(m_pCurrentGame);
		break;
	case 1:
		if (m_pCurrentGame && !m_pCurrentGame->IsGameOver())
			ChangeState(m_pCurrentGame);
		break;
	case 2:
		ChangeState(CHighScoreState::GetInstance(m_pStateManager));
		break;
	case 3:
		PostQuitMessage(0);
		break;
	}
}
//...
//...
void CPlayState::OnKeyDown(WPARAM wKey)
{
	switch (wKey)
	{
	//case...
	case VK_ESCAPE:
		ChangeState(CMenuState::GetInstance(m_pStateManager));
		break;
	case VK_RETURN:
		if (m_bGameOver)
		{
			CHighScoreState* pHighScores = 
				CHighScoreState::GetInstance(m_pStateManager);
			pHighScores->SetNewHighScore(m_ulCurrentScore);
			ChangeState(pHighScores);
		}
	}
}
//...
//...
void CHighScoreState::OnKeyDown(WPARAM wKey) 
{ 
	if (m_bEnterName)
	{
    //...
	}
	else
	{	switch(wKey)
		{
		case VK_ESCAPE:
		case VK_RETURN:
			ChangeState(CMenuState::GetInstance(m_pStateManager));
			break;
		}
	}
}






















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值