接下来我们进入教程的主菜,进入游戏。
再此之前,我先给出游戏系统的架构图:
有点复杂,不要紧,让我一点一点的为你分析
先从我们之前看到过的PreGame着手,这里再一次贴出PreGame的定义
class CPreGame : public CGameController
{
public:
enum State {
UNKNOWN,
WAIT_ON_ADDRESS,
WAIT_ON_SCRIPT,
WAIT_ON_MAP,
WAIT_ON_MOD,
ALL_READY,
};
CPreGame(bool server, const std::string& demo, const std::string& save);
virtual ~CPreGame();
CglList* showList;
bool Draw();
int KeyPressed(unsigned short k,bool isRepeat);
bool Update();
bool server;
State state;
bool saveAddress;
bool hasDemo,hasSave;
static std::string mapName;
static std::string modName;
static std::string modArchive;
static std::string scriptName;
std::string demoFile;
void UpdateClientNet();
unsigned char inbuf[16000]; //buffer space for incomming data
int inbufpos; //where in the input buffer we are
int inbuflength; //last byte in input buffer
CLoadSaveHandler *savefile;
private:
CInfoConsole* infoConsole;
void ShowScriptList();
void ShowMapList();
void ShowModList();
static void SelectScript(std::string s);
static void SelectMap(std::string s);
static void SelectMod(std::string s);
};
可以看到 CPreGame我们前面所用于控制函数生成的类,是继承于一个非常重要的类CGameController,上面的 Update();Draw();等控制游戏重要的方法都是CGameController上虚函数的override.
以下是CPreGame的一个方法Update,我们从中可以看到,在获得状态ALL_READY之后,CPreGame将执行开始游戏的一系列操作,包括实例化一个游戏中最重要的类Update(),Cgame.
case ALL_READY: {
ENTER_MIXED;
// Map all required archives depending on selected mod(s)
vector<string> ars = archiveScanner->GetArchives(pregame->modArchive);
if (ars.empty())
logOutput.Print("Warning: mod archive ""%s"" is missing?"n", pregame->modArchive.c_str());
for (vector<string>::iterator i = ars.begin(); i != ars.end(); ++i)
if (!hpiHandler->AddArchive(*i, false))
logOutput.Print("Warning: Couldn't load archive '%s'.", i->c_str());
// Determine if the map is inside an archive, and possibly map needed archives
CFileHandler* f = SAFE_NEW CFileHandler("maps/" + pregame->mapName);
if (!f->FileExists()) {
vector<string> ars = archiveScanner->GetArchivesForMap(pregame->mapName);
if (ars.empty())
logOutput.Print("Warning: map archive ""%s"" is missing?"n", pregame->mapName.c_str());
for (vector<string>::iterator i = ars.begin(); i != ars.end(); ++i) {
if (!hpiHandler->AddArchive(*i, false))
logOutput.Print("Warning: Couldn't load archive '%s'.", i->c_str());
}
}
delete f;
// always load springcontent.sdz
hpiHandler->AddArchive("base/springcontent.sdz", false);
const int teamID = gs->players[gu->myPlayerNum]->team;
const CTeam* team = gs->Team(teamID);
LoadStartPicture(team->side);
// create GameServer here where we can ensure to know which map and mod we are using
if (server) {
good_fpu_control_registers("before CGameServer creation");
gameServer = SAFE_NEW CGameServer(gameSetup? gameSetup->hostport : 8452, pregame->mapName, pregame->modArchive, pregame->scriptName, demoFile);
good_fpu_control_registers("after CGameServer creation");
}
game = SAFE_NEW CGame(server, pregame->mapName, pregame->modArchive, infoConsole);
if (savefile) {
savefile->LoadGame();
}
infoConsole = 0;
ENTER_UNSYNCED;
pregame=0;
delete this;
return true;
}
当然在开始之前,该系统有读取文件等异步IO操作的文件系统,我们留到以后再讲,我们先将系统的基本架构理顺。
Cgame与我们前面说过的Pregame都是继承于类 CGameController。这可以说是游戏中最重要的类,所以这个类的构造函数可以说是最重要的构造函数。他几乎启动了系统的所有模块的所有功能。。。。所以各位如果像我刚开始时闷头看我们就看不出什么所以然了。那我们先选择各个击破,大家请看上面的主系统架构图,进入CGame这个重要的模块,我们需要调用到以下的重要子模块或者跟确切的说是方面:
给大家看看他头文件的定义:
class CGame : public CGameController
{
public:
CR_DECLARE(CGame); //Don't use CGame pointer in CR_MEMBER()!!!
void UpdateUI();
bool ClientReadNet();
void PostLoad();
void SimFrame();
void StartPlaying();
bool DrawWorld();
bool Draw();
bool Update();
int KeyReleased(unsigned short k);
int KeyPressed(unsigned short k,bool isRepeat);
CGame(bool server, std::string mapname, std::string modName, CInfoConsole *infoConsole);
void ResizeEvent();
virtual ~CGame();
bool ActionPressed(const CKeyBindings::Action&, const CKeySet& ks, bool isRepeat);
bool ActionReleased(const CKeyBindings::Action&);
int que;
unsigned int oldframenum;
unsigned int fps;
unsigned int thisFps;
time_t fpstimer, starttime;
Uint64 lastUpdate;
Uint64 lastMoveUpdate;
Uint64 lastModGameTimeMeasure;
Uint64 lastUpdateRaw;
float updateDeltaSeconds;
unsigned int lastframe;
float totalGameTime; //time in seconds, stops at game end
unsigned char inbuf[40000*2]; //buffer space for incomming data //should be NETWORK_BUFFER_SIZE*2
int inbufpos; //where in the input buffer we are
int inbuflength; //last byte in input buffer
bool bOneStep; //do a single step while game is paused
int leastQue;
std::string userInputPrefix;
int lastTick;
float timeLeft;
float consumeSpeed;
int chatSound;
int skipping;
bool playing;
bool allReady;
bool chatting;
bool camMove[8];
bool camRot[4];
bool hideInterface;
bool gameOver;
bool windowedEdgeMove;
bool showFPS;
bool showClock;
bool noSpectatorChat; //prevents spectator msgs from being seen by players
bool drawFpsHUD;
float maxUserSpeed;
float minUserSpeed;
bool gamePausable;
bool soundEnabled;
float gameSoundVolume;
CScript* script;
CInfoConsole *infoConsole;
void MakeMemDump(void);
CConsoleHistory* consoleHistory;
CWordCompletion* wordCompletion;
bool creatingVideo;
CAVIGenerator* aviGenerator;
void DrawDirectControlHud(void);
#ifdef DIRECT_CONTROL_ALLOWED
short oldHeading,oldPitch;
unsigned char oldStatus;
#endif
void HandleChatMsg(std::string msg, int player, bool demoPlayer);
void SetHotBinding(const std::string& action) { hotBinding = action; }
protected:
void SendNetChat(const string& message);
void DrawInputText();
void ParseInputTextGeometry(const string& geo);
void SelectUnits(const string& line);
void SelectCycle(const string& command);
void LogNetMsg(const string& msg, int player);
void ReloadCOB(const string& msg, int player);
void Skip(const string& msg, bool demoPlayer);
protected:
std::string hotBinding;
float inputTextPosX;
float inputTextPosY;
float inputTextSizeX;
float inputTextSizeY;
float lastCpuUsageTime;
};
无论从头文件还是从架构图都可以看到,Cgame所启动的内容首先包括以下几个大方面:
1, UI生成。 ----生成操作界面
2, 图像生成。 ----生成游戏图形
3, 用户操作。 ----响应用户的鼠标或键盘的操作
4, 远程网络通讯。 ----与其他玩家同步游戏信息
5,AI系统 ----当地图中有电脑玩家的时候,与人对战的AI ,也包括单位的基本AI如寻道,等等
接下来分大几章为大家介绍这个大游戏是怎么一句一句写出来。

浙公网安备 33010602011771号