<html>

        绚丽的大型游戏背后,都存在着一个主循环,能依据游戏的进度控制游戏的状态。主循环管理游戏的正常执行。管理着游戏执行失败该怎样处理,对某些不能执行的情况给予杀死等等。

另外。在MMORPG中,主循环相同也是AI的管理者。时刻依据游戏的执行状态,调度出不同的AI执行,增强了游戏的可玩性和趣味性。同一时候主循环对于关卡控制。游戏画面渲染,声音管理。资源管理也有所掌控。总之,主循环对于大型游戏是不可或缺的一部分~~

        下面是游戏主循环的各个组成部分:

I. 游戏初始化的相关參数:

#pragma once

#include <iostream>
using namespace std;
//========================================================================
// Initialization.h : Defines utility functions for game initialization
//========================================================================

typedef unsigned int  DWORD;
typedef long long DWORDLONG;
typedef unsigned char TCHAR;

extern bool CheckStorage(const DWORDLONG diskSpaceNeeded);
extern DWORD ReadCPUSpeed();
extern bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded);
extern bool IsOnlyInstance(const TCHAR* gameTitle);
extern const TCHAR *GetSaveGameDirectory(HWND hWnd, const TCHAR *gameAppDirectory);
extern bool CheckForJoystick(HWND hWnd);


struct GameOptions
{
	// Level option 与关卡相关的选项
	std::string m_Level;

	// Rendering options 与渲染相关的选项
	std::string m_Renderer;
	bool m_runFullSpeed;
	Point m_ScreenSize;

	// Sound options 与音频相关
	float m_soundEffectsVolume;			
	float m_musicVolume;				

	// Multiplayer options 多人同一时候在线选项
	int m_expectedPlayers;				
	int m_listenPort;					
	std::string m_gameHost;				
	int m_numAIs;
	int m_maxAIs;
	int m_maxPlayers;

    // resource cache options 资源缓存
    bool m_useDevelopmentDirectories;

	// TiXmlElement - look at this to find other options added by the developer
	TiXmlDocument *m_pDoc;

	GameOptions();
	~GameOptions() { SAFE_DELETE(m_pDoc); }

	void Init(const char* xmlFilePath, LPWSTR lpCmdLine);
};
//========================================================================
// Initialization.cpp : Defines utility functions for game initialization
//========================================================================


#include "GameCodeStd.h"
#include <shlobj.h>
#include <direct.h>
#include "Initialization.h"

//
// CheckStorage	对于端游而言的安装.
//
bool CheckStorage(const DWORDLONG diskSpaceNeeded)
{
	// Check for enough free disk space on the current disk.
	int const drive = _getdrive();
	struct _diskfree_t diskfree;

	_getdiskfree(drive, &diskfree);

	unsigned __int64 const neededClusters = 
		diskSpaceNeeded /(diskfree.sectors_per_cluster*diskfree.bytes_per_sector);

	if (diskfree.avail_clusters < neededClusters)
	{
		// if you get here you donít have enough disk space!
		GCC_ERROR("CheckStorage Failure: Not enough physical storage.");
		return false;
	}
	return true;
}

//
// CheckMemory
//
bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded)
{
	MEMORYSTATUSEX status;
	GlobalMemoryStatusEx(&status);
	if (status.ullTotalPhys < physicalRAMNeeded)
	{
		// you donít have enough physical memory. Tell the player to go get a real 
		// computer and give this one to his mother. 
		GCC_ERROR("CheckMemory Failure: Not enough physical memory.");
		return false;
	}

	// Check for enough free memory.
	if (status.ullAvailVirtual < virtualRAMNeeded)
	{
		// you donít have enough virtual memory available. 
		// Tell the player to shut down the copy of Visual Studio running in the
		// background, or whatever seems to be sucking the memory dry.
		GCC_ERROR("CheckMemory Failure: Not enough virtual memory.");
		return false;
	}

	char *buff = GCC_NEW char[(unsigned int)virtualRAMNeeded];
	if (buff)
		delete[] buff;
	else
	{
		// even though there is enough memory, it isnít available in one 
		// block, which can be critical for games that manage their own memory
		GCC_ERROR("CheckMemory Failure: Not enough contiguous available memory.");
		return false;
	}
	return true;
}

//
// ReadCPUSpeed
//
DWORD ReadCPUSpeed()
{
	DWORD BufSize = sizeof(DWORD);
	DWORD dwMHz = 0;
	DWORD type = REG_DWORD;
	HKEY hKey;

	// open the key where the proc speed is hidden:
	long lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
        L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
        0, KEY_READ, &hKey);
    
	if(lError == ERROR_SUCCESS)
	{
		// query the key:
		RegQueryValueEx(hKey, L"~MHz", NULL, &type, (LPBYTE) &dwMHz, &BufSize);
	}
	return dwMHz;
}



/***
DWORD GetFreeVRAM()
{

	// NOTE: This method is deprecated, and unfortunately not really replaced with
	// anything useful.....


	DDSCAPS2 ddsCaps;
	ZeroMemory(&ddsCaps, sizeof(ddsCaps));
		
	ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
	DWORD dwUsedVRAM = 0;
	DWORD dwTotal=0;
	DWORD dwFree=0;

	// lp_DD points to the IDirectDraw object	
	HRESULT hr = g_pDisplay->GetDirectDraw()->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree); 
		
	// dwUsedVRAM holds the number of bytes of VRAM used
	dwUsedVRAM = dwTotal-dwFree;
	return dwUsedVRAM;								

	return 0;
}
****/

GameOptions::GameOptions()
{
	// set all the options to decent default valu
	m_Level = "";
	m_Renderer = "Direct3D 9";
	m_runFullSpeed = false;
	m_soundEffectsVolume = 1.0f;			
	m_musicVolume = 1.0f;				
	m_expectedPlayers = 1;
	m_listenPort = -1;					
	std::string m_gameHost = "MrMike-m1710";
	m_numAIs = 1;
	m_maxAIs = 4;
	m_maxPlayers = 4;
	m_ScreenSize = Point(1024,768);
    m_useDevelopmentDirectories = false;

	m_pDoc = NULL;
}


void GameOptions::Init(const char* xmlFileName, const TCHAR* lpCmdLine)
{
	// read the XML file
	// if needed, override the XML file with options passed in on the command line.

	m_pDoc = new TiXmlDocument(xmlFileName);
	if (m_pDoc && m_pDoc->LoadFile())
	{
        TiXmlElement *pRoot = m_pDoc->RootElement();
        if (!pRoot)
            return;

        // Loop through each child element and load the component
        TiXmlElement* pNode = NULL;
		pNode = pRoot->FirstChildElement("Graphics"); 
		if (pNode)
		{
			std::string attribute;
			attribute = pNode->Attribute("renderer");
			if (attribute != "Direct3D 9" && attribute != "Direct3D 11")
			{
				GCC_ASSERT(0 && "Bad Renderer setting in Graphics options.");
			}
			else
			{
				m_Renderer = attribute;
			}

			if (pNode->Attribute("width"))
			{
				m_ScreenSize.x = atoi(pNode->Attribute("width"));
				if (m_ScreenSize.x < 800) m_ScreenSize.x = 800;
			}

			if (pNode->Attribute("height"))
			{
				m_ScreenSize.y = atoi(pNode->Attribute("height"));
				if (m_ScreenSize.y < 600) m_ScreenSize.y = 600;
			}

			if (pNode->Attribute("runfullspeed"))
			{
				attribute = pNode->Attribute("runfullspeed");
				m_runFullSpeed = (attribute == "yes") ? true : false;
			}
		}

		pNode = pRoot->FirstChildElement("Sound"); 
		if (pNode)
		{
			m_musicVolume = atoi(pNode->Attribute("musicVolume")) / 100.0f;
			m_soundEffectsVolume = atoi(pNode->Attribute("sfxVolume")) / 100.0f;
		}

		pNode = pRoot->FirstChildElement("Multiplayer"); 
		if (pNode)
		{
			m_expectedPlayers = atoi(pNode->Attribute("expectedPlayers"));
			m_numAIs = atoi(pNode->Attribute("numAIs"));
			m_maxAIs = atoi(pNode->Attribute("maxAIs"));
			m_maxPlayers = atoi(pNode->Attribute("maxPlayers"));
			
			m_listenPort = atoi(pNode->Attribute("listenPort"));
			m_gameHost = pNode->Attribute("gameHost");
		}

        pNode = pRoot->FirstChildElement("ResCache");
        if (pNode)
        {
            std::string attribute(pNode->Attribute("useDevelopmentDirectories"));
            m_useDevelopmentDirectories = ((attribute == "yes") ?

(true) : (false)); } } } // // IsOnlyInstance // bool IsOnlyInstance(const TCHAR* gameTitle) { // Find the window. If active, set and return false // Only one game instance may have this mutex at a time... HANDLE handle = CreateMutex(NULL, TRUE, gameTitle); // Does anyone else think 'ERROR_SUCCESS' is a bit of an oxymoron? if (GetLastError() != ERROR_SUCCESS) { HWND hWnd = FindWindow(gameTitle, NULL); if (hWnd) { // An instance of your game is already running. ShowWindow(hWnd, SW_SHOWNORMAL); SetFocus(hWnd); SetForegroundWindow(hWnd); SetActiveWindow(hWnd); return false; } } return true; } // // GetSaveGameDirectory // const TCHAR *GetSaveGameDirectory(HWND hWnd, const TCHAR *gameAppDirectory) { HRESULT hr; static TCHAR m_SaveGameDirectory[MAX_PATH]; TCHAR userDataPath[MAX_PATH]; hr = SHGetSpecialFolderPath(hWnd, userDataPath, CSIDL_APPDATA, true); _tcscpy_s(m_SaveGameDirectory, userDataPath); _tcscat_s(m_SaveGameDirectory, _T("\\")); _tcscat_s(m_SaveGameDirectory, gameAppDirectory); // Does our directory exist? if (0xffffffff == GetFileAttributes(m_SaveGameDirectory)) { if (SHCreateDirectoryEx(hWnd, m_SaveGameDirectory, NULL) != ERROR_SUCCESS) return false; } _tcscat_s(m_SaveGameDirectory, _T("\\")); return m_SaveGameDirectory; } // // bool CheckForJoystick 手柄检測 // bool CheckForJoystick(HWND hWnd) { JOYINFO joyinfo; UINT wNumDevs; BOOL bDev1Attached, bDev2Attached; if((wNumDevs = joyGetNumDevs()) == 0) return false; bDev1Attached = joyGetPos(JOYSTICKID1,&joyinfo) != JOYERR_UNPLUGGED; bDev2Attached = joyGetPos(JOYSTICKID2,&joyinfo) != JOYERR_UNPLUGGED; if(bDev1Attached) joySetCapture(hWnd, JOYSTICKID1, 1000/30, true); if (bDev2Attached) joySetCapture(hWnd, JOYSTICKID2, 1000/30, true); return true; }

以上就是主循环中游戏初始化相关的东西。包含声音。资源,游戏选项等。

II. 游戏过程 > GameProcess

#pragma once
//========================================================================
// Process.h : defines common game events
//========================================================================
#include <memory>
#include <iostream>
using namespace std::shared_ptr;
using namespace std::weak_ptr;

class Process;
typedef shared_ptr<Process> StrongProcessPtr;
typedef weak_ptr<Process> WeakProcessPtr;

//--------------------------------------------------------------------
// Process class
// 
// Processes are ended by one of three methods: Success, Failure, or Aborted.
//		- Success means the process completed successfully.  If the process has a child, it will be attached to the process mgr.
//		- Failure means the process started but failed in some way.  If the process has a child, it will be aborted.
//		- Aborted processes are processes that are canceled while not submitted to the process mgr.  Depending on the circumstances, they may or may not have gotten an OnInit() call.

//  For example, a process can
//		  spawn another process and call AttachToParent() on itself.  If the new process fails, the child will get an Abort() call on it, even though its status is RUNNING.
//--------------------------------------------------------------------
class Process
{
	friend class ProcessManager;

public:
	enum State
	{
		// Processes that are neither dead nor alive
		UNINITIALIZED = 0,  // created but not running
		REMOVED,  // removed from the process list but not destroyed; this can happen when a process that is already running is parented to another process

		// Living processes
		RUNNING,  // initialized and running
		PAUSED,  // initialized but paused
		
		// Dead processes
		SUCCEEDED,  // completed successfully
		FAILED,  // failed to complete
		ABORTED,  // aborted; may not have started
	};
	
private:
	State m_state;  // the current state of the process
	StrongProcessPtr m_pChild;  // the child process, if any

public:
	// construction
    Process(void);
	virtual ~Process(void);
	
protected:
	// interface; these functions should be overridden by the subclass as needed
	virtual void VOnInit(void) { m_state = RUNNING; }  // called during the first update; responsible for setting the initial state (typically RUNNING)
	virtual void VOnUpdate(unsigned long deltaMs) = 0;  // called every frame
	virtual void VOnSuccess(void) { }  // called if the process succeeds (see below)
	virtual void VOnFail(void) { }  // called if the process fails (see below)
	virtual void VOnAbort(void) { }  // called if the process is aborted (see below)

public:
	// Functions for ending the process.
	inline void Succeed(void);
	inline void Fail(void);
	
	// pause
	inline void Pause(void);
	inline void UnPause(void);

	// accessors
	State GetState(void) const { return m_state; }
	bool IsAlive(void) const { return (m_state == RUNNING || m_state == PAUSED); }
	bool IsDead(void) const { return (m_state == SUCCEEDED || m_state == FAILED || m_state == ABORTED); }
	bool IsRemoved(void) const { return (m_state == REMOVED); }
	bool IsPaused(void) const { return m_state == PAUSED; }

	// child functions
	inline void AttachChild(StrongProcessPtr pChild);
	StrongProcessPtr RemoveChild(void);  // releases ownership of the child
	StrongProcessPtr PeekChild(void) { return m_pChild; }  // doesn't release ownership of the child

private:
	void SetState(State newState) { m_state = newState; }
};


//--------------------------------------------------------------------------------------------
// Inline function definitions
//--------------------------------------------------------------------------------------------
inline void Process::Succeed(void)
{
	GCC_ASSERT(m_state == RUNNING || m_state == PAUSED);
	m_state = SUCCEEDED;
}

inline void Process::Fail(void)
{
	GCC_ASSERT(m_state == RUNNING || m_state == PAUSED);
	m_state = FAILED;
}

inline void Process::AttachChild(StrongProcessPtr pChild)
{
	if (m_pChild)
		m_pChild->AttachChild(pChild);
	else
		m_pChild = pChild;
}

inline void Process::Pause(void)
{
	if (m_state == RUNNING)
		m_state = PAUSED;
	else
		GCC_WARNING("Attempting to pause a process that isn't running");
}

inline void Process::UnPause(void)
{
	if (m_state == PAUSED)
		m_state = RUNNING;
	else
		GCC_WARNING("Attempting to unpause a process that isn't paused");
}

/*
inline StrongProcessPtr Process::GetTopLevelProcess(void)
{
	if (m_pParent)
		return m_pParent->GetTopLevelProcess();
	else
		return this;
}
*/
游戏Process包含游戏初始化后的各种状态与各种处理。

III. 游戏的Process管理类

#pragma once
//========================================================================
// ProcessManager.h : defines common game events
//========================================================================

#include "Process.h"
#include <list>
#include <iostream>
using namespace std::list>;

class ProcessManager
{
	typedef std::list<StrongProcessPtr> ProcessList;

	ProcessList m_processList;

public:
	// construction 明显的没有virtual 由于没有子类继承
	~ProcessManager(void);

	// interface
	unsigned int UpdateProcesses(unsigned long deltaMs);  // updates all attached processes
	WeakProcessPtr AttachProcess(StrongProcessPtr pProcess);  // attaches a process to the process mgr
	void AbortAllProcesses(bool immediate);

	// accessors
	unsigned int GetProcessCount(void) const { return m_processList.size(); }

private:
	void ClearAllProcesses(void);  // should only be called by the destructor
};
//========================================================================
// ProcessManager.cpp : defines common game events
//========================================================================

#include "GameCodeStd.h"
#include "ProcessManager.h"

//---------------------------------------------------------------------------------------------
// Destructor
//---------------------------------------------------------------------------------------------
ProcessManager::~ProcessManager(void)
{
    ClearAllProcesses();
}


//---------------------------------------------------------------------------------------------
// The process update tick.  Called every logic tick.  This function returns the number of process chains that 
// succeeded in the upper 32 bits and the number of process chains that failed or were aborted in the lower 32 bits.
//---------------------------------------------------------------------------------------------
unsigned int ProcessManager::UpdateProcesses(unsigned long deltaMs)
{
    unsigned short int successCount = 0;
    unsigned short int failCount = 0;

    ProcessList::iterator it = m_processList.begin();
    while (it != m_processList.end())
    {
        // grab the next process
        StrongProcessPtr pCurrProcess = (*it);

        // save the iterator and increment the old one in case we need to remove this process from the list
        ProcessList::iterator thisIt = it;
        ++it;

        // process is uninitialized, so initialize it
        if (pCurrProcess->GetState() == Process::UNINITIALIZED)
            pCurrProcess->VOnInit();

        // give the process an update tick if it's running
        if (pCurrProcess->GetState() == Process::RUNNING)
            pCurrProcess->VOnUpdate(deltaMs);

        // check to see if the process is dead
        if (pCurrProcess->IsDead())
        {
            // run the appropriate exit function
            switch (pCurrProcess->GetState())
            {
                case Process::SUCCEEDED :
                {
                    pCurrProcess->VOnSuccess();
                    StrongProcessPtr pChild = pCurrProcess->RemoveChild();
                    if (pChild)
                        AttachProcess(pChild);
                    else
                        ++successCount;  // only counts if the whole chain completed
                    break;
                }

                case Process::FAILED :
                {
                    pCurrProcess->VOnFail();
                    ++failCount;
                    break;
                }

                case Process::ABORTED :
                {
                    pCurrProcess->VOnAbort();
                    ++failCount;
                    break;
                }
            }

            // remove the process and destroy it
            m_processList.erase(thisIt);
        }
    }

    return ((successCount << 16) | failCount);
}


//---------------------------------------------------------------------------------------------
// Attaches the process to the process list so it can be run on the next update.
//---------------------------------------------------------------------------------------------
WeakProcessPtr ProcessManager::AttachProcess(StrongProcessPtr pProcess)
{
	m_processList.push_front(pProcess);
    return WeakProcessPtr(pProcess);
}

//---------------------------------------------------------------------------------------------
// Clears all processes (and DOESN'T run any exit code)
//---------------------------------------------------------------------------------------------
void ProcessManager::ClearAllProcesses(void)
{
    m_processList.clear();
}

//---------------------------------------------------------------------------------------------
// Aborts all processes.  If immediate == true, it immediately calls each ones OnAbort() function and destroys all 
// the processes.
//---------------------------------------------------------------------------------------------
void ProcessManager::AbortAllProcesses(bool immediate)
{
    ProcessList::iterator it = m_processList.begin();
    while (it != m_processList.end())
    {
        ProcessList::iterator tempIt = it;
        ++it;

        StrongProcessPtr pProcess = *tempIt;
        if (pProcess->IsAlive())
        {
            pProcess->SetState(Process::ABORTED);
            if (immediate)
            {
                pProcess->VOnAbort();
                m_processList.erase(tempIt);
            }
        }
    }
}

以上是进度管理的相关代码。包含不断的更新进度和杀死全部进度的控制。

以上的就是游戏的主循环的相关代码了。下一篇将是游戏音效管理相关的~~




版权声明:本文为博主原创文章,未经博主同意不得转载。 举报
  • 本文已收录于下面专栏:

相关文章推荐

cocos2d-x游戏开发(四)游戏主循环

欢迎转载:http://blog.csdn.net/fylz1125/article/details/8518737 最终抽时间把这个游戏写完了。因为没有自拍神器。所以把它移植到了Andro...

Cocos2d-x 动手实现游戏主循环

因为Cocos2d-x封装的非常好。所以对于非常多新手,他们仅仅知道先new一个场景。在场景上加入布景或精灵,然后用Director的runWithScene便能够执行游戏了。假设给一个精灵加个动作。精灵就...

cocos2d-x游戏循环与调度

每个游戏程序都有一个循环在不断执行,它是有导演对象来管理非常维护。

假设须要场景中的精灵运动起来,我们能够在游戏循环中使用定时器(Scheduler)对精灵等对象的执行进行调度。由于Node类封装了Scheduler类。所以我们也可

server公共组件实现 -- mangos的游戏主循环

当阅读一项project的源代码时,我们大概会选择从main函数開始。而当開始一项新的project时,第一个写下的函数大多也是main。

那我们就先来看看,游戏server代码实现中,main函数都做了些什么。

  因为我在读技术...

  • lfhfut
  • lfhfut
  • 2007-09-18 00:05
  • 4497

零基础学python-2.13 回到我们的游戏 增加循环

上次我们的游戏增加了条件推断。可是它仅仅可以给用户猜一次。很难猜中 所以,我们这节课在游戏里面增加循环,让用户多猜几次 先上原来的代码: print("---------欢迎来到猜数字的地方,请開始---------")#输出提示 guess=int(input("*数字区间0-100,请输入你猜的数字:"))#读取输入,然后赋值 print(guess)#打印输入 secret=18 if guess==secret: print("恭喜,猜对了") el

一款很不错的android游戏循环原理

讲解一款很不错的android游戏循环原理,給安卓游戏开发的朋友。

[代码]DroidzActivity.java <

Mangos源代码分析(7):server公共组件实现之游戏主循环

当阅读一项project的源代码时,我们大概会选择从main函数開始。而当開始一项新的project时,第一个写下的函数大多也是main。

那我们就先来看看。游戏server代码实现中,main函数都做了些什么。   因为我...

约瑟夫环,杀人游戏(静态循环链表实现)

认为用静态循环链表最划算了。 1、动态链表要动态分配,指针移来移去,释放指针等等,弄得非常烦。easy出错。 2、用循环链表是当然的了。 // DS: 似循环静态链表 #include &lt;iostream&gt; #include &lt;cstdio&gt; //#include &lt;cstdlib&gt; using namespace std; int Kill_You( const int sum = 1, const int distance = 1,
  • bcyy
  • bcyy
  • 2012-03-24 15:51
  • 56

游戏主循环

摘自:http://my.oschina.net/u/243648/blog/71814 引言 游戏主循环是每一个游戏的心跳,输送着整个游戏须要的养分。不幸的是没有不论什么一篇好的文章来指导...

写一个好的游戏主循环

<p style="line-height: 25px; margin-top: 0px; margin-bottom: 0px; padding-top: 10px; padding-bottom:
  • 微博
    微信
    QQ
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多仅仅同意输入30个字)

posted @ 2017-08-15 16:57  zhchoutai  阅读(199)  评论(0编辑  收藏  举报