1. 程式人生 > >如何用C++做遊戲(1)

如何用C++做遊戲(1)

現在,越來越多的C++伺服器和客戶端融入了指令碼的支援,尤其在網遊領域,指令碼語言已經滲透到了方方面面,比如你可以在你的客戶端增加一個指令碼,這個指令碼將會幫你在介面上顯示新的資料,亦或幫你完成某些任務,亦或幫你檢視別的玩家或者NPC的狀態。。。如此等等。

但是我覺得,其實指令碼語言與(C++)的結合,遠遠比你在遊戲中看到的特效要來的迅猛。它可以運用到方方面面的領域,比如你最常見的應用領域。

比如,你 可以用文字編輯器,寫一個指令碼語言,然後用你的程式載入一下,就會產生出很絢麗的介面。亦或一兩句文字語言,就會讓你的程式傳送資料給伺服器,是不是很酷 呢?

Lua指令碼

Lua語言,想必不少程式設計師都聽過,據我所知,由於《魔獸世界》裡面對它的載入,它一下子變成了很多遊戲開發者競相研究的物件,至於這個巴西創造者麼,我不過多介紹,網上有很多關於lua的教材和例子,說真的,對於當年的我而言,幾乎看不懂,當時很鬱悶,感覺Lua複雜的要命,有些懼怕,後來沉下心來一點點研究,覺得其實還是蠻簡潔的。只是網上的資料或許偏向於某些功能,導致了邏輯和程式碼的複雜。後來總結,其實學習一種指令碼語言,完全可以抱著放鬆的心態一 點點的研究,反而效果會更好。

我們來看看怎麼寫一個簡單的lua程式吧。

建立一個檔案,起名Sample.lua 裡面新增這樣的程式碼。

function func_Add(x, y) 
   return x+y; 
end

這是一個標準的lua語法,一個函式,實現簡單的a+b操作,並返回操作結果。 儲存退出。 多一句嘴,在Lua裡面,是可以支援多資料返回的。 比如你這麼寫:

function func_Add(x, y) 
   return x+y, x-y; 
end

意思是返回第一個引數是相加的結果,第二個是相減的結果,也是可以的。在lua裡面沒有型別的概念。當然,在C++接受這樣的返回值的時候,也很簡單,請往下看。

好了,材料齊備了,咱們來看看C++程式怎麼呼叫它。 首先,建立一個類,負責載入這個lua檔案,並執行函式操作,我們姑且叫做CLuaFn 要載入這個lua檔案,按照正常的思路,我們應該先載入,然後再呼叫不同的函式。恩,對了,咱們就這麼做。

extern “C” 
{ 
        #include “lua.h” 
        #include “lualib.h” 
        #include “lauxlib.h” 
};

class CLuaFn 
{ 
public: 
        CLuaFn(void); 
        ~CLuaFn(void);

        void Init();            //初始化Lua物件指標引數 
        void Close();         //關閉Lua物件指標

        bool LoadLuaFile(const char* pFileName)
; //載入指定的Lua檔案 bool CallFileFn(const char* pFunctionName, int nParam1, int nParam2); //執行指定Lua檔案中的函式 private: lua_State* m_pState; //這個是Lua的State物件指標,你可以一個lua檔案對應一個。 }

恩,標頭檔案就這麼多,看看,一點也不復雜吧,看了cpp我想你會更高興,因為程式碼一樣很少。我一個個函式給你們介紹。

void CLuaFn::Init() 
{ 
        if(NULL == m_pState) 
        { 
                m_pState = lua_open(); 
                luaL_openlibs(m_pState); 
        } 
}

初始化函式,標準程式碼,沒啥好說的,lua_open()是返回給你一個lua物件指標,luaL_openlibs()是一個好東西,在 lua4,初始化要做一大堆的程式碼,比如載入lua的string庫,io庫,math庫等等等等,程式碼洋洋灑灑一大堆,其實都是不必要的,因為這些庫你 基本都需要用到,除了練習你的打字能力別的意義不大,因為程式碼寫法都是固定的。於是在5以後,Lua的創造者修改了很多,這就是其一,一句話幫你載入了所 有你可能用到的Lua基本庫。

void CLuaFn::Close() 
{ 
        if(NULL != m_pState) 
        { 
                lua_close(m_pState); 
                m_pState = NULL; 
        } 
}

顧名思義,我用完了,關閉我的Lua物件並釋放資源。呵呵,標準寫法,沒啥好說的。

bool CLuaFn:: LoadLuaFile(const char* pFileName) 
{ 
        int nRet = 0; 
        if(NULL == m_pState) 
        { 
                printf(“[CLuaFn:: LoadLuaFile]m_pState is NULL./n”); 
                return false; 
        }

        nRet = luaL_dofile(m_pState, pFileName); 
        if (nRet != 0) 
        { 
                printf(“[CLuaFn:: LoadLuaFile]luaL_loadfile(%s) is file(%d)(%s)./n”, pFileName, nRet, lua_tostring(m_pState, -1)); 
                return false; 
        }

        return true; 
}

載入一個Lua檔案

這裡我要詳細的說一下,因為Lua是指令碼語言,載入lua檔案本身的時候才會編譯。

所 以,推薦大家在載入檔案的時候儘量放在程式的初始化中,因為當你執行luaL_dofile()函式的時候,Lua會啟用語法分析器,去分析你的指令碼語法 是否符合Lua規則,如果你胡亂的傳一個檔案過去,Lua就會告訴你檔案語法錯誤,無法載入。如果你的Lua指令碼很大,函式很多,語法分析器會比較耗時, 所以,載入的時候,儘量放在合適的地方,而且,對於一個Lua檔案而言,反覆載入luaL_dofile()除了會使你的CPU變熱沒有任何意義。

或許你對

printf(“[CLuaFn:: LoadLuaFile]luaL_loadfile(%s) is file(%d)(%s)./n”, pFileName, nRet, lua_tostring(m_pState, -1))

這句話很感興趣,這個在幹什麼?這裡我先說

lua_tostring(m_pState, -1)

這是在幹什麼,還記得我說的Lua是基於棧傳輸資料的麼?那麼,如果報錯,我怎麼知道錯誤是什麼?luaL_dofile標準返回一個int,我總 不能到lua.h裡面遍歷這個nRet 是啥意思吧,恩,Lua創造者早就為你想好了,只不過你需要稍微動一下你的腦筋。Lua的創造者在語法分析器分析你的語法的時候,發現錯誤,會有一段文字 告訴你是什麼錯誤,它會把這個字串放在棧頂。那麼,怎麼取得棧頂的字串呢?lua_tostring(m_pState, -1)就可以,-1代表的是當前棧的位置是相對棧頂。當然,你也可以看看棧裡面還有一些什麼其他古怪的資料,你可以用1,2,3(這些是絕對位置,而-1 是相對位置)去嘗試,呵呵。不過,相信你得到的也很難看懂,因為一個Lua物件執行的時候,會用很多次棧進行資料交換,而你看到的,有可能是交換中的數 據。那麼,話說回來,這句話的意思就是”[CLuaFn:: LoadLuaFile]luaL_loadfile(檔名) is file(錯誤編號)(錯誤具體描述文字)./n”

bool CLuaFn::CallFileFn(const char* pFunctionName, int nParam1, int nParam2) 
{ 
        int nRet = 0; 
        if(NULL == m_pState) 
        { 
                printf(“[CLuaFn::CallFileFn]m_pState is NULL./n”); 
                return false; 
        }

        lua_getglobal(m_pState, pFunctionName);

        lua_pushnumber(m_pState, nParam1); 
        lua_pushnumber(m_pState, nParam2);

        nRet = lua_pcall(m_pState, 2, 1, 0); 
        if (nRet != 0) 
        { 
                printf(“[CLuaFn::CallFileFn]call function(%s) error(%d)./n”, pFunctionName, nRet); 
                return false; 
        }

        if (lua_isnumber(m_pState, -1) == 1) 
        { 
                int nSum = lua_tonumber(m_pState, -1); 
                printf(“[CLuaFn::CallFileFn]Sum = %d./n”, nSum); 
        }

        return true; 
}

這個函式是,傳入函式名稱和引數,去你的Lua檔案中去執行。

lua_getglobal(m_pState, pFunctionName);

這個函式是驗證你的Lua函式是否在你當前載入的Lua檔案中,並把指標指向這個函式位置。

lua_pushnumber(m_pState, nParam1);   <—對應你的x引數 
lua_pushnumber(m_pState, nParam2);   <—對應你的y引數

這就是著名的壓棧操作了,把你的引數壓入Lua的資料棧。供Lua語法器去獲得你的資料。 lua_pushnumber()是一個壓入數字,lua_pushstring()是壓入一個字串。。。

那麼你會問,如果我有一個自己的型別,一個類指標或者別的什麼,我怎麼壓入?彆著急,方法當然是有的,呵呵,不過你先看看如果簡單的如何做,在下幾講中,我會告訴你更強大的Lua壓棧藝術。 這裡需要注意的是,壓棧的順序,對,簡單說,就是從左到右的引數,左邊的先進棧,右邊的最後進棧。

nRet = lua_pcall(m_pState, 2, 1, 0); 這句話的意思是,執行這個函式,2是輸入引數的個數,1是輸出引數的個數。當然,如果你把Lua函式改成 return x+y, x-y; 程式碼需要改成nRet = lua_pcall(m_pState, 2, 2, 0); 明白了吧,呵呵,很簡單吧。 當然,如果函式執行失敗,會觸發nRet,我這裡偷了個懶,如果你想得到為什麼錯了?可以用lua_tostring(m_pState, -1)去棧頂找,明白?是不是有點感覺了?

lua_isnumber(m_pState, -1)

這句話是判定棧頂的元素是不是數字。因為如果執行成功,棧頂就應該是你的資料返回值。

int nSum = lua_tonumber(m_pState, -1); 
printf(“[CLuaFn::CallFileFn]Sum = %d./n”, nSum);

這個nSum就是返回的結果。 當然,你會問,如果 return x+y, x-y;我該怎麼辦?

int nSum = lua_tonumber(m_pState, -1); 
int nSub = lua_tonumber(m_pState, -2);

搞定,看見沒。按照壓棧順序。呵呵,是不是又有感覺了,對,棧就是資料互動的核心。對Lua的理解程度和運用技巧,其實就是對棧的靈活運用和操作。 好了。你的第一個Lua程式大功告成!竟然不是Hello world,呵呵。 好了,我們看看Main函式怎麼寫吧,相信大家都會寫。

#include “LuaFn.h”

int _tmain(int argc, _TCHAR* argv[]) 
{ 
        CLuaFn LuaFn;

        //LuaFn.InitClass();

        LuaFn.LoadLuaFile(“Sample.lua”); 
        LuaFn.CallFileFn(“func_Add”, 11, 12); 
        getchar();

        return 0; 
}

行了,Build一下,看看,是不是你要的結果?如果是,賀喜你,你已經邁出了Lua的第一步。 洋洋灑灑寫了一個小時,喝口水吧,呵呵, 下一講,我將強化這個LuaFn類,讓它給我做更多的事情。呵呵,最後,我會讓你打到,用Lua檔案直接畫出一個Windows窗體來。並在上面畫出各種 按鈕,列表,以及複選框。是不是感覺很酷?用文字去創造一個程式?很激動吧,恩,確實,Lua能給你做到。只要你有耐心看下去。。。

小夥伴們,還請持續關注更新,更多幹貨和資料請直接聯絡我,也可以加群710520381,邀請碼:柳貓,歡迎大家共同討論

相關推薦

如何用C++遊戲(1)

現在,越來越多的C++伺服器和客戶端融入了指令碼的支援,尤其在網遊領域,指令碼語言已經滲透到了方方面面,比如你可以在你的客戶端增加一個指令碼,這個指令碼將會幫你在介面上顯示新的資料,亦或幫你完成某些任務,亦或幫你檢視別的玩家或者NPC的狀態。。。如此等等。但是我覺得,其實指令

C#一個簡單紙牌遊戲的程式

小子不才學C#沒多久,想做個窗體紙牌遊戲玩,但是窗體應用懂得不多,只能在控制命令臺上進行遊戲設計,希望有大神能幫我設計這個窗體程式,或者推薦好的窗體設計資料,謝謝了,控制命令臺程式如下: namespace BasicCardsGame {     class OutOfR

【程序5】 題目:利用條件運算符的嵌套來完成此題:學習成績>=90分的同學A表示,60-89分之間的B表示,60分以下的C表示。 1.程序分析:(a>b)?a:b這是條件運算符的基本例子。

window code 例子 prompt 利用 學習 amp text span if…else語句相對比較多,但是容易理解 1 var scroe = window.prompt("請輸入1-100之間的數") 2 scroe = parseInt

Unity遊戲,你需要深入瞭解一下IL2CPP

這次我們翻譯了一篇Unity官方部落格上的文章,原文題目為AN INTRODUCTION TO IL2CPP INTERNALS ,作者是從事Unity軟體開發的Joshua Peterson。文章的看點在於,它是以IL2CPP內部開發人員的角度來講述的,所以對於開發者來說非常有參考價值。 如果

C#:撲克牌遊戲(1):規劃CardLib類庫開發撲克牌遊戲

(一):前言         這是《C#入門經典(第七版)》的學習筆記,接下來會通過一個撲克牌程式學習關於C#相關知識。 (二):前期思考過程         建立一個類庫,命名應該為CardLib,不過按照

C++了一個圖書管理系統

圖書管理系統功能如下: 新增書籍。 刪除書籍。當系統中存在此書時,刪除該書籍,否則提示使用者刪除失敗。 借閱書籍。當系統中存在此書且未被借閱時,將書的狀態設定為“借出”,否則提示使用者借閱失敗。 歸還書籍。當系統中存在未歸換的該書時,將書的狀態設定為“可用”,否則提示使用者歸還失敗。

C++和遊戲開發那些事,告訴你怎麼C++縱橫遊戲程式設計!

C語言和C++ C 語言可以說是一門設計的非常成功的語言。但是C語言沒有OOP的特性,在做一些大型專案的時候力不從心。一些大型的C專案,隨著專案的臃腫,人類基本沒辦 法維護這個專案了。要維護這麼龐大的專案而又不出錯,只能加入一些OOP特性重構,有經驗的C程式設計師寫著寫著,很多概念就類似C+

C語言計算1~20的階乘之和

  昨天(2018/12/7)在做C語言的課後練習題的時候,有一道題要求我們計算1~20的階乘之和。程式碼很快就寫出來了,考慮到結果的值會比較大,而在Windows作業系統下,int 型別和 long 型別居然都是4個位元組(C#中long型別是八個位元組,找同學試了下,Linux下C語言的long型別好像也

C++和遊戲開發那些事,告訴你怎麼C++縱橫遊戲程式設計

C語言和C++ C 語言可以說是一門設計的非常成功的語言。但是C語言沒有OOP的特性,在做一些大型專案的時候力不從心。一些大型的C專案,隨著專案的臃腫,人類基本沒辦 法維護這個專案了。要維護這麼龐大的專案而又不出錯,只能加入一些OOP特性重構,有經驗的C程式設計師寫著寫著,很多概念就類似C++了

C++一次雞兔同籠 2017.3.17

這節課做了一道雞兔同籠的題,用最大的“武器庫”。 “int”是整數,“double”是小數; 要先給定義變數,然後賦值,接著用題目中解出的方程求雞和兔子的只數,最後用F11輸出 。(做出來還有點兒成就感,呵呵) 這些是c++的一些知識體系,網上搜的,  C語言語法知識

c++實現遊戲2048---前三步

利用c++實現遊戲2048(命令列版) 寫在前面 在知乎上偶爾看到有人利用寫這種小程式練手,正好最近剛考完期末考試,所以就花了一個晚上寫了一下,也簡單的寫了一個2048. 以下是效果圖。 之前沒有用c++寫過比較大型的內容,對c++的理解也不是很

如何用C++遊戲(2)

上一節講了一些基本的Lua應用,或許你會說,還是很簡單麼。呵呵,恩,是的,本來Lua就是為了讓大家使用的方便快捷而設計的。如果設計的過為複雜,就不會有人使用了。下面,我要強調一下,Lua的棧的一些概念,因為這個確實很重要,你會經常用到。熟練使用Lua,最重要的就是要時刻知道什

c語言實現1+2+3+...+n求和

  在做藍橋杯題的時候,做到最簡單的等差數列求和,我就先用for迴圈寫了一個程式,其中的核心就是很簡單的: sum += i; 具體的函式如下: #include <stdio.h> int main() { int n; int i; int sum

自己C#的一個萬年曆

剛開始接觸C#不久,自己嘗試做了一個日曆,說是說萬年曆哈其實只從1900開始算起哈,因為題目就是這樣的。先貼一下題目;   實現傳入一個年份後,輸出改年份每個月的資訊,星期和日期;       提示:1900.1.1剛好是星期一 下面是程式碼:using System; us

C語言計算1!+2!+3!

test.c #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int i = 0; int sum = 0; int ret = 1; for (i = 1; i <

手把手教你C#疫情傳播模擬

手把手教你用C#做疫情傳播模擬 姐妹篇:手把手教你用C#做疫情傳播模擬 產品經理版 在上篇文章中,我介紹了用C#做的疫情傳播模擬程式的使用和配置,演示了其執行效果,但沒有著重講其中的程式碼。 今天我將抽絲剝繭,手把手分析程式的架構,以及妙趣橫生的細節。 首先來回顧一下執行效果: 注意看,程式中的資訊,

一個c#基礎知識的小遊戲

通過一個教學視訊所學來的方法using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 飛行棋

IPHONE6 近來1年不會開放NFC的API給開發人員,也就是僅僅能支持了如今

company its put ech tran repo article -s cati IPHONE6 近來1還不會開放NFC的API給開發人員,也就是僅僅能用來做支持了如今,可是能夠肯定的是,以後肯定會放發出來的。就像指紋傳感器一樣,如今也開放出來了。前

Html5/CSS3Winform,一步一步教你搭建CefSharp開發環境(附JavaScript異步調C#例子,及全部源代碼)上

轉載 界面設計 右鍵 異步 一個 由於 編寫 scrip 調用 本文為雞毛巾原創,原文地址:http://www.cnblogs.com/jimaojin/p/7077131.html,轉載請註明 CefSharp說白了就是Chromium瀏覽器的嵌入式核心,我們用此開發W

C++使用libcurlHttpClient(業務觀摩,C++封裝過程式代碼,post和get的數據,最好url編碼,否則+會變成空格)good

com 如果 msvc 是否 out tle source rac 無需 當使用C++做HTTP客戶端時,目前通用的做法就是使用libcurl。其官方網站的地址是http://curl.haxx.se/,該網站主要提供了Curl和libcurl。Curl是命令行