遊戲中實現指令碼控制的乾貨分享

才智咖 人氣:2.08W

一個遊戲引擎做好了,最重要的是缺什麼?指令碼。打個比方,遊戲引擎是一部電腦,則指令碼就是電腦的軟體。既然指令碼這麼重要,那該怎樣實現呢?下面本站小編就來說說自己的做法。想了解更多相關資訊請持續關注我們應屆畢業生培訓網。

遊戲中實現指令碼控制的乾貨分享

首先理解一下訊息迴圈

 一個好的遊戲離不開好的訊息迴圈。它是遊戲實現很重要的一部分。

首先,我定義了一個全域性變數extern int GameState;

在遊戲中定義了許多當前的遊戲狀態例如

#define GAME_STATE_CUSTOM 0 //這代表在戰鬥中玩家可以控制遊戲

#define GAME_STATE_TALKING 1

等等。

好了,下面在WinMain裡面的while(1)迴圈中有個UpdateScreen()函式

原型為

void UpdateScreen()

{

延時

switch(GameState)

{

case GAME_STATE_CUSTOM:

畫出地圖

畫出所有精靈

畫出天氣(如果有的話)

如果玩家選中了敵人的話(打個比方DrawFlag=DrawEnemyState)就顯示敵人的移動範圍和敵人狀態

break;

case GAME_STATE_TALKING:

GameDialogProc();

break;

case GAME_STATE_SCRIPTCONTROLLING:

ScriptControlProc();

break;

….//其他的訊息在這裡處理

}

將緩衝表面的圖象顯示到螢幕;

}

每個遊戲狀態都需要一個獨立的函式來寫。這樣在每次切換遊戲狀態時都不會出現無法處理的情況。在處理鍵盤訊息的時候我也用一個個獨立的函式來寫,如處理回車鍵我用了 KeyReturnProc()來控制。在這個函式裡同樣也少不了switch(GameState)這一句,為什麼?答案很簡單,比如說在精靈行走時回車鍵就沒有用,這是我沒有處理精靈行走這個狀態的鍵盤訊息。而在戰鬥場景裡按下回車鍵,如果有精靈在選擇框裡的話,就會處理相應的東西。

例如選擇了敵人則使DrawFlag=DrawEnemyState;這樣在更新螢幕時就會畫出敵人的移動範圍和狀態。

明白了嗎?好了,如果你明白了訊息迴圈的原理,下面的東西就很容易理解了。

下面談談指令碼控制

要實現這個,就必須在UpdataScreen()這個函式中攔截一個“指令碼控制”的訊息,並呼叫相應的處理函式:ScriptControlProc(); 那麼怎樣得到“指令碼控制”這個訊息呢?我是這樣約定的:

新遊戲->呼叫指令碼

“戰鬥結束”->呼叫指令碼

“前往下一個地點”->呼叫指令碼

好了,就只有這幾種情況下才呼叫,呼叫指令碼的函式為BeginScriptControl();

這個函式做了三個工作:

1.首先讀取舞臺(場景)角色的資料(沒一關都是一個不同的舞臺)

2.開啟指令碼檔案(注意要用全域性的檔案指標)(雖然我在源程式中沒直接開啟,但是原理是一樣的)

3.將遊戲狀態設定為“指令碼控制”以便在下一次UpdateScreen()中呼叫的.是ScriptControlProc();(怎麼樣?知道訊息迴圈的作用了吧?)

ScriptControlProc()這個函式其實也很簡單:

讀取指令碼檔案中的引數直到檔案結束,讀取指令碼檔案需要一個解釋指令碼的函式LoadParam(FILE*fp);這個函式負責解釋指令碼中的東西:是函式呼叫還是函式引數,然後找到相應的函式執行即可。

比如說腳本里有一段程式碼MovePlayerTo(1,1,1);意思就是把第1個玩家移動到1,1處。怎樣做呢?

我是按照以下幾步做的

1.儲存當前的遊戲狀態

2.把當前遊戲狀態設定為“移動精靈”

當引擎得到“移動精靈”這個函式後,在UpdataScreen()中呼叫的是MoveRoleProc()這個函式。

當移動結束後,MoveRoleProc()呼叫EndMoveRole(),這個函式的作用就是讀取先前的遊戲狀態

怎麼樣?又回到讀指令碼了吧?記住在移動角色的時候指令碼檔案的指標沒有改變,所以回到讀指令碼的這個函式後不是重新讀取而是繼續讀取!同理其他的指令碼指令如LoadDialog也是一樣的道理!

當檔案要結束的時候,別忘了告訴引擎該停止了,這時候我們必須更新遊戲狀態。腳本里的SetGameState就是負責這項工作的。