精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在游戲中如何來使用LUA

移動開發 iOS
在游戲中如何來使用LUA是本文要介紹的內容,主要是來學習游戲中lua的使用方法,具體內容的實現來看本文詳解。

游戲中如何來使用LUA是本文要介紹的內容,主要是來學習游戲lua的使用方法,具體內容的實現來看本文詳解。首先,讓我來簡單的解釋一下Lua解釋器的工作機制,Lua解釋器自身維護一個運行時棧,通過這個運行時棧,Lua解釋器向主機程序傳遞參數,所以我們可以這樣來得到一個腳本變量的值:

獲取腳本的變量的值

  1. lua_pushstring(L, "var"); //將變量的名字放入棧  
  2. lua_gettatbl(L, LUA_GLOBALSINDEX);變量的值現在棧頂 

假設你在腳本中有一個變量 var = 100

你可以這樣來得到這個變量值:

  1. int var = lua_tonumber(L, -1); 

怎么樣,是不是很簡單?

Lua定義了一個宏讓你簡單的取得一個變量的值:

  1. lua_getglobal(L, name) 

我們可以這樣來取得一個變量的值:

  1. lua_getglobal(L, "var"); //變量的值現在棧頂  
  2. int var = lua_tonumber(L, -1); 

完整的測試代碼如下:

  1. #include "lua.h"  
  2. #inculde "lauxlib.h"  
  3. #include "lualib.h"  
  4. int main(int argc, char *argv[])  
  5. {  
  6. lua_State *L = lua_open();  
  7. luaopen_base(L);  
  8. luaopen_io(L);  
  9. const char *buf = "var = 100";  
  10. lua_dostring(L, buf);  
  11. lua_getglobal(L, "var");  
  12. int var = lua_tonumber(L, -1);  
  13. assert(var == 100);  
  14. lua_close(L);  
  15. return 0;  
  16. }  

關于全局變量:

如上面我們所看到的,lua_getglobal()將Lua的一個全局變量放至棧頂,假如我們的腳本包含一個全局變量z,下面這段代碼將獲取z的值,代碼:

  1. lua_getglobal(L, "z");  
  2.     z = (int)lua_tonumber(L, -1);  
  3.     lua_pop(L, 1); 

與之對應的lua_setglobal()用來設置Lua的一個全局變量的值,下面的這段代碼將全局變量z的值設置為10,代碼:

  1. lua_pushnumber(L, 10);  
  2.     lua_setglobal(L, "z"); 

注意,不需要在你的Lua腳本中顯式的全局變量,如果全局變量不存在,lua_setglobal()將創建一個新的全局變量。

在程序中調用腳本的函數

在你的游戲中應用Lua(1):調用函數

假設你在腳本中定義了一個函數:

  1. function main(number)  
  2. numbernumber = number + 1  
  3. return number  
  4. end 

在你的游戲代碼中,你希望在某個時刻調用這個函數取得它的返回值。

在Lua中,函數等同于變量,所以你可以這樣來取得這個函數:

  1. lua_getglobal(L, "main");//函數現在棧頂 

現在,我們可以調用這個函數,并傳遞給它正確的參數:

  1. lua_pushnumber(L, 100); //將參數壓棧  
  2. lua_pcall(L, 1, 1, 0); //調用函數,有一個參數,一個返回值  
  3. //返回值現在棧頂  
  4. int result = lua_tonumber(L, -1); 

result 就是函數的返回值

完整的測試代碼如下:

  1. #include "lua.h"  
  2. #include "lauxlib.h"  
  3. #include "lualib.h"  
  4. int main(int argc, char *argv[])  
  5. {  
  6. lua_State *L = lua_open();  
  7. luaopen_base(L);  
  8. const char *buf = "function main(number) number = number + 1 return number end";  
  9. lua_dostring(buf);  
  10. lua_getglobal(L, "main");  
  11. lua_pushnumber(L, 100);  
  12. lua_pcall(L, 1, 1, 0);  
  13. int result = lua_tonumber(L, -1);  
  14. assert(result == 101);  
  15. lua_close(L);  
  16. return 0; 
  17. }

在你的游戲中應用Lua(2):擴展Lua

Lua本身定位在一種輕量級的,靈活的,可擴充的腳本語言,這意味著你可以自由的擴充Lua,為你自己的游戲量身定做一個腳本語言。

你可以在主機程序中向腳本提供你自定的api,供腳本調用。

Lua定義了一種類型:lua_CFunction,這是一個函數指針,它的原型是:

  1. typedef int (*lua_CFunction) (lua_State *L); 

這意味著只有這種類型的函數才能向Lua注冊。

首先,我們定義一個函數

  1. int foo(lua_State *L)  
  2. {  
  3. //首先取出腳本執行這個函數時壓入棧的參數  
  4. //假設這個函數提供一個參數,有兩個返回值  
  5. //get the first parameter  
  6. const char *par = lua_tostring(L, -1);  
  7. printf("%s\n", par);  
  8. //push the first result  
  9. lua_pushnumber(L, 100);  
  10. //push the second result  
  11. lua_pushnumber(L, 200);  
  12. //return 2 result  
  13. return 2;  

我們可以在腳本中這樣調用這個函數

  1. r1, r2 = foo("hello")  
  2. print(r1..r2) 

完整的測試代碼如下:

  1. #include "lua.h"  
  2. #include "lauxlib.h"  
  3. #include "lualib.h"  
  4. int foo(lua_State *L)  
  5. {  
  6. //首先取出腳本執行這個函數時壓入棧的參數  
  7. //假設這個函數提供一個參數,有兩個返回值  
  8. //get the first parameter  
  9. const char *par = lua_tostring(L, -1);  
  10. printf("%s\n", par);  
  11. //push the first result  
  12. lua_pushnumber(L, 100);  
  13. //push the second result  
  14. lua_pushnumber(L, 200);  
  15. //return 2 result  
  16. return 2;  
  17. }  
  18. int main(int argc, char *argv[])  
  19. {  
  20. lua_State *L = lua_open();  
  21. luaopen_base(L);  
  22. luaopen_io(L);  
  23. const char *buf = "r1, r2 = foo("hello") print(r1..r2)";  
  24. lua_dostring(L, buf);  
  25. lua_close(L);  
  26. return 0;  

程序輸出:

  1. hello  
  2. 100200  

在你的游戲中應用Lua(3):using lua in cpp 

lua和主機程序交換參數是通過一個運行時棧來進行的,運行時棧的信息放在一個lua_State的結構中,lua提供的api都需要一個lua_State*的指針,除了一個:

  1. lua_open(); 

這個函數將返回一個lua_State*型的指針,在你的游戲代碼中,你可以僅僅擁有一個這樣的指針,也可以有多個這樣的指針。

***,你需要釋放這個指針,通過函數:

  1. lua_close(L); 

注意這個事實,在你的主機程序中,open()與close()永遠是成對出現的,在c++中,如果有一些事情是成對出現的,這通常意味著你需要一個構造函數和一個析構函數,所以,我們首先對lua_State做一下封裝:

  1. #ifndef LUA_EXTRALIBS  
  2. #define LUA_EXTRALIBS /* empty */  
  3. #endif  
  4.  
  5. static const luaL_reg lualibs[] =   
  6. {  
  7. {"base", luaopen_base},  
  8. {"table", luaopen_table},  
  9. {"io", luaopen_io},  
  10. {"string", luaopen_string},  
  11. {"math", luaopen_math},  
  12. {"debug", luaopen_debug},  
  13. {"loadlib", luaopen_loadlib},  
  14. /* add your libraries here */  
  15. LUA_EXTRALIBS  
  16. {NULL, NULL}  
  17. }; 

這是lua提供給用戶的一些輔助的lib,在使用lua_State的時候,你可以選擇打開或者關閉它。

完整的類實現如下:

  1. //lua_State  
  2. class state  
  3. {  
  4. public:  
  5. state(bool bOpenStdLib = false)  
  6. :  
  7. err_fn(0)  
  8. {  
  9. L = lua_open();  
  10.  
  11. assert(L);  
  12.  
  13. if (bOpenStdLib)  
  14. {  
  15. open_stdlib();  
  16. }  
  17. }  
  18.  
  19. ~state()  
  20. {  
  21. lua_setgcthreshold(L, 0);  
  22. lua_close(L);  
  23. }  
  24.  
  25. void open_stdlib()  
  26. {  
  27. assert(L);  
  28.  
  29. const luaL_reg *lib = lualibs;  
  30. for (; lib->func; lib++)   
  31. {  
  32. lib->func(L); /* open library */  
  33. lua_settop(L, 0); /* discard any results */  
  34. }  
  35. }  
  36. lua_State* get_handle()  
  37. {  
  38. return L;  
  39. }  
  40. int error_fn()  
  41. {  
  42. return err_fn;  
  43. }  
  44. private:  
  45. lua_State *L;  
  46.  
  47. int err_fn;  
  48. }; 

通常我們僅僅在游戲代碼中使用一個lua_State*的指針,所以我們為它實現一個單件,默認打開所有lua提供的lib:

  1. //return the global instance  
  2. state* lua_state()  
  3. {  
  4. static state L(true);  
  5. return &L;  

在你的游戲中應用Lua(3):using lua in cpp(封裝棧操作) 

前面提到了lua與主機程序是通過一個運行時棧來交換信息的,所以我們把對棧的訪問做一下簡單的封裝。

我們利用從c++的函數重載機制對這些操作做封裝,重載提供給我們一種以統一的方式來處理操作的機制。

向lua傳遞信息是通過壓棧的操作來完成的,所以我們定義一些Push()函數:

  1. inline void Push(lua_State *L, int value);  
  2. inline void Push(lua_State *L, bool value); 

...

對應簡單的c++內建類型,我們實現出相同的Push函數,至于函數內部的實現是非常的簡單,只要利用lua提供的api來實現即可,例如:

  1. inline void Push(lua_State *L, int value)  
  2. {  
  3. lua_pushnumber(L, value);  

這種方式帶來的好處是,在我們的代碼中我們可以以一種統一的方式來處理壓棧操作,如果有一種類型沒有定義相關的壓棧操作,將產生一個編譯期錯誤。

后面我會提到,如何將一個用戶自定義類型的指針傳遞到lua中,在那種情況下,我們的基本代碼無須改變,只要添加一個相應的Push()函數即可。

記住close-open原則吧,它的意思是對修改是封閉的,對擴充是開放的,好的類庫設計允許你擴充它,而無須修改它的實現,甚至無須重新編譯。

《c++泛型設計新思維》一書提到了一種技術叫type2type,它的本質是很簡單:

  1. template <typename T> 
  2. struct type2type  
  3. {  
  4. typedef T U;  
  5. }; 

正如你看到的,它并沒有任何數據成員,它的存在只是為了攜帶類型信息。

類型到類型的映射在應用于重載函數時是非常有用的,應用type2type,可以實現編譯期的分派。

下面看看我們如何在從棧中取得lua信息時應用type2type:

測試類型:由于lua的類型系統與c++是不相同的,所以,我們要對棧中的信息做一下類型檢測。

  1. inline bool Match(type2type<bool>, lua_State *L, int idx)  
  2. {  
  3. return lua_type(L, idx) == LUA_TBOOLEAN;  

類似的,我們要為cpp的內建類型提供相應的Match函數:

  1. inline bool Match(type2type<int>, lua_State *L, int idx);  
  2. inline bool Match(type2type<const char*>, lua_State *L, int idx); 

可以看出,type2type的存在只是為了在調用Match時決議到正確的函數上,由于它沒有任何成員,所以不存在運行時的成本。

同樣,我們為cpp內建類型提供Get()函數:

  1. inline bool Get(type2type<bool>, lua_State *L, int idx)  
  2. {  
  3. return lua_toboolean(L, idx);  
  4. }  
  5.  
  6. inline int Get(type2type<int>, lua_State *L, int idx)  
  7. {  
  8. return static_cast<int>(lua_tonumber(L, idx));  

我想你可能注意到了,在int Get(type2type<int>)中有一個轉型的動作,由于lua的類型系統與cpp的類型不同,所以轉型動作必須的。

除此之外,在Get重載函數(s)中還有一個小小的細節,每個Get的函數的返回值是不相同的,因為重載機制是依靠參數的不同來識別的,而不是返回值。

前面說的都是一些基礎的封裝,下來我們將介紹如何向lua注冊一個多參數的c函數。還記得嗎?利用lua的api只能注冊int (*ua_CFunction)(lua_State *)型的c函數,別忘記了,lua是用c寫的。

在你的游戲中應用Lua(3):using lua in cpp(注冊不同類型的c函數)之一 

前面說到,我們可以利用lua提供的api,向腳本提供我們自己的函數,在lua中,只有lua_CFunction類型的函數才能直接向lua注冊,lua_CFunction實際上是一個函數指針:

  1. typedef int (*lua_CFunction)(lua_State *L); 

而在實際的應用中,我們可能需要向lua注冊各種參數和返回值類型的函數,例如,提供一個add腳本函數,返回兩個值的和:

  1. int add(int x, int y); 

為了實現這個目的,首先,我們定義個lua_CFunction類型的函數:

  1. int add_proxy(lua_State *L)  
  2. {  
  3. //取得參數  
  4. if (!Match(TypeWrapper<int>(), L, -1))  
  5. return 0;  
  6. if (!Match(TypeWrapper<int>(), L, -2))  
  7. return 0;  
  8.   int x = Get(TypeWrapper<int>(), L, -1);  
  9.   int y = Get(TypeWrapper<int>(), L, -1);  
  10.   //調用真正的函數  
  11.   int result = add(x, y);  
  12.   //返回結果  
  13.   Push(result);  
  14.   return 1;  

現在,我們可以向lua注冊這個函數:

  1. lua_pushstring(L, “add”);  
  2. lua_pushcclosure(L, add_proxy, 0);  
  3. lua_settable(L, LUA_GLOBALINDEX); 

在腳本中可以這樣調用這個函數:

  1. print(add(100, 200)) 

從上面的步驟可以看出,如果需要向lua注冊一個非lua_CFunction類型的函數,需要:

1、為該函數實現一個封裝調用。

2、在封裝調用函數中從lua棧中取得提供的參數。

3、使用參數調用該函數。

4、向lua傳遞其結果。

注意,我們目前只是針對全局c函數,類的成員函數暫時不涉及,在cpp中,類的靜態成員函數與c函數類似。

假設我們有多個非lua_CFunction類型的函數向lua注冊,我們需要為每一個函數重復上面的步驟,產生一個封裝調用,可以看出,這些步驟大多是機械的,因此,我們需要一種方式自動的實現上面的步驟。

首先看步驟1,在cpp中,產生這樣一個封裝調用的函數的***的方式是使用template,我們需要提供一個lua_CFunction類型的模板函數,在這個函數中調用真正的向腳本注冊的函數,類似于這樣:

  1. template <typename Func> 
  2. inline int register_proxy(lua_State *L) 

現在的問題在于:我們要在這個函數中調用真正的函數,那么我們必須要在這個函數中取得一個函數指針,然而,lua_CFunction類型的函數又不允許你在增加別的參數來提供這個函數指針,現在該怎么讓regisger_proxy函數知道我們真正要注冊的函數呢?

在oop中,似乎可以使用類來解決這個問題:

  1. template <Func> 
  2. struct register_helper  
  3. {  
  4. explicit register_helper(Func fn) : m_func(fn)  
  5. {}  
  6. int register_proxy(lua_State *L);  
  7.  
  8. protected:  
  9. Func m_func;  
  10. }; 

可是不要忘記,lua_CFunction類型指向的是一個c函數,而不是一個成員函數,他們的調用方式是不一樣的,如果將上面的int register_proxy()設置為靜態成員函數也不行,因為我們需要訪問類的成員變量m_func;

讓我們再觀察一下lua_CFunction類型的函數:

  1. int register_proxy(lua_State *L); 

我們看到,這里面有一個lua_State*型的指針,我們能不能將真正的函數指針放到這里面存儲,到真正調用的時候,再從里面取出來呢?

Lua提供了一個api可以存儲用戶數據:

  1. Lua_newuserdata(L, size) 

在適當的時刻,我們可以再取出這個數據:

  1. lua_touserdata(L, idx) 

ok,現在傳遞函數指針的問題我們已經解決了,后面再看第二步:取得參數。

在你的游戲中應用Lua(3):using lua in cpp(注冊不同類型的c函數)之二

在解決了傳遞函數指針的問題之后,讓我們來看看調用函數時會有一些什么樣的問題。

首先,當我們通過函數指針調用這個函數的時候,由于我們面對的是未知類型的函數,也就是說,我們并不知道參數的個數,參數的類型,還有返回值的類型,所以我們不能直接從lua棧中取得參數,當然,我們可以通過運行時測試棧中的信息來得到lua傳遞進來的參數的個數和類型,這意味著我們在稍后通過函數指針調用函數時也需要動態的根據參數的個數和類型來決議到正確的函數,這樣,除了運行時的成本,cpp提供給我們的強類型檢查機制的好處也剩不了多少了,我們需要的是一種靜態的編譯時的“多態”。

在cpp中,至少有兩種方法可以實現這點。最直接簡單的是使用函數重載,還有一種是利用模板特化機制。

簡單的介紹一下模板特化:

在cpp中,可以針對一個模板函數或者模板類寫出一些特化版本,編譯器在匹配模板參數時會尋找最合適的一個版本。類似于這樣:

  1. templat <typename T> 
  2. T foo()  
  3. {  
  4. T tmp();  
  5. return tmp;  
  6. }  
  7.  
  8. //提供特化版本  
  9. template <> 
  10. int foo()  
  11. {  
  12. return 100;  

在main()函數中,我們可以顯示指定使用哪個版本的foo:

  1. int main(int argc, char **argv)  
  2. {  
  3. cout << foo<int>() << endl;  
  4. return 0;  

程序將輸出100,而不是0,以上代碼在 g++中編譯通過,由于vc6對于模板的支持不是很好,所以有一些模板的技術在vc6中可能不能編譯通過。

所以***使用重載來解決這個問題,在封裝函數調用中,我們首先取得這個函數指針,然后,我們要提供一個Call函數來真正調用這個函數,類似于這樣:

  1. //偽代碼  
  2. int Call(pfn, lua_State *L, int idx) 

可是我們并不知道這個函數指針的類型,現在該怎么寫呢?別忘記了,我們的register_proxy()是一個模板函數,它有一個參數表示了這個指針的類型:

  1. template <typename Func> 
  2. int register_proxy(lua_State *L)  
  3. {  
  4. //偽代碼,通過L參數取得這個指針  
  5. unsigned char *buffer = get_pointer(L);  
  6.  
  7. //對這個指針做強制類型轉化,調用Call函數  
  8. return Call(*(Func*)buffer, L, 1);  

由重載函數Call調用真正的函數,這樣,我們可以使用lua api注冊相關的函數,下來我們提供一個注冊的函數:

  1. template <typename Func> 
  2. void lua_pushdirectclosure(Func fn, lua_State *L, int nUpvalue)  
  3. {  
  4. //偽代碼,向L存儲函數指針  
  5. save_pointer(L);  
  6.  
  7. //向lua提供我們的register_proxy函數  
  8. lua_pushcclosure(L, register_proxy<Func>, nUpvalue + 1);  

再定義相關的注冊宏:

  1. #define lua_register_directclosure(L, func) \  
  2. lua_pushstring(L, #func);  
  3. lua_pushdirectclosure(func, L, 1);  
  4. lua_settable(L, LUA_GLOBALINDEX) 

現在,假設我們有一個int add(int x, int y)這樣的函數,我們可以直接向lua注冊:

  1. lua_register_directclosure(L, add); 

看,***使用起來很方便吧,我們再也不用手寫那么多的封裝調用的代碼啦,不過問題還沒有完,后面我們還得解決Call函數的問題。

在你的游戲中應用Lua(3):using lua in cpp(注冊不同類型的c函數)之三 

下面,讓我們集中精力來解決Call重載函數的問題吧。

前面已經說過來,Call重載函數接受一個函數指針,然后從lua棧中根據函數指針的類型,取得相關的參數,并調用這個函數,然后將返回值壓入lua棧,類似于這樣:

  1. //偽代碼  
  2. int Call(pfn, lua_State *L, int idx) 

現在的問題是pfn該如何聲明?我們知道這是一個函數指針,然而其參數,以及返回值都是未知的類型,如果我們知道返回值和參數的類型,我們可以用一個typedef來聲明它:

  1. typedef void (*pfn)();  
  2. int Call(pfn fn, lua_State *L, int idx); 

我們知道的返回值以及參數的類型只是一個模板參數T,在cpp中,我們不能這樣寫:

  1. template <typename T> 
  2. typedef T (*Func) (); 

一種解決辦法是使用類模板:

  1. template <typename T> 
  2. struct CallHelper  
  3. {  
  4. typedef T (*Func) ();  
  5. }; 

然后在Call中引用它:

  1. template <typename T> 
  2. int Call(typename CallHelper::Func fn, lua_State *L, int idx) 

注意typename關鍵字,如果沒有這個關鍵字,在g++中會產生一個編譯警告,它的意思是告訴編譯器,CallHelper::Func是一個類型,而不是變量。

如果我們這樣來解決,就需要在CallHelper中為每種情況大量定義各種類型的函數指針,還有一種方法,寫法比較古怪,考慮一個函數中參數的聲明:

  1. void (int n); 

首先是類型,然后是變量,而應用于函數指針上:

  1. typedef void (*pfn) ();  
  2. void (pfn fn); 

事實上,可以將typedef直接在參數表中寫出來:

  1. void (void (*pfn)() ); 

這樣,我們的Call函數可以直接這樣寫:

  1. //針對沒有參數的Call函數  
  2. template <typename RT> 
  3. int Call(RT (*Func) () , lua_State *L, int idx);  
  4. {  
  5. //調用Func  
  6. RT ret = (*Func)();  
  7.  
  8. //將返回值交給lua  
  9. Push(L, ret);  
  10.  
  11. //告訴lua有多少個返回值  
  12. return 1;  
  13. }  
  14.  
  15. //針對有一個參數的Call  
  16. template <typename T, typename P1> 
  17. int Call(RT (*Func)(), lua_State *L, int idx)  
  18. {  
  19. //從lua中取得參數  
  20. if (!Match(TypeWrapper<P1>(), L, -1)  
  21. return 0;  
  22.  
  23. RT ret = (*Func) (Get(TypeWrapper<P1>(), L, -1));  
  24.  
  25. Push(L, ret);  
  26. return 1;  

按照上面的寫法,我們可以提供任意參數個數的Call函數,現在回到最初的時候,我們的函數指針要通過lua_State *L來存儲,這只要利用lua提供的api就可以了,還記得我們的lua_pushdirectclosure函數嗎:

  1. template <typename Func> 
  2. void lua_pushdirectclosure(Func fn, lua_State *L, int nUpvalue)  
  3. {  
  4. //偽代碼,向L存儲函數指針  
  5. save_pointer(L);  
  6.  
  7. //向lua提供我們的register_proxy函數  
  8. lua_pushcclosure(L, register_proxy<Func>, nUpvalue + 1);  

其中,save_pointer(L)可以這樣實現:

  1. void save_pointer(lua_State *L)  
  2. {  
  3. unsigned char* buffer = (unsigned char*)lua_newuserdata(L, sizeof(func));  
  4. memcpy(buffer, &func, sizeof(func));  

而在register_proxy函數中:

  1. template <typename Func> 
  2. int register_proxy(lua_State *L)  
  3. {  
  4. //偽代碼,通過L參數取得這個指針  
  5. unsigned char *buffer = get_pointer(L);  
  6. //對這個指針做強制類型轉化,調用Call函數  
  7. return Call(*(Func*)buffer, L, 1);  
  8. }  
  9. get_pointer函數可以這樣實現:  
  10.  
  11. unsigned char* get_pointer(lua_State *L)  
  12. {  
  13.   return (unsigned char*) lua_touserdata(L, lua_upvalueindex(1));  

這一點能夠有效運作主要依賴于這樣一個事實:

我們在lua棧中保存這個指針之后,在沒有對棧做任何操作的情況下,又把它從棧中取了出來,所以不會弄亂lua棧中的信息,記住,lua棧中的數據是由用戶保證來清空的。

到現在,我們已經可以向lua注冊任意個參數的c函數了,只需簡單的一行代碼:

  1. lua_register_directclosure(L, func)就可以啦 

在你的游戲中應用Lua(3):Using Lua in cpp(基本數據類型、指針和引用)之一

  1. Using Lua in cpp(基本數據類型、指針和引用) 

前面介紹的都是針對cpp中的內建基本數據類型,然而,即使是這樣,在面對指針和引用的時候,情況也會變得復雜起來。

使用前面我們已經完成的宏lua_register_directclosure只能注冊by value形式的參數的函數,當參數中存在指針和引用的時候(再強調一次,目前只針對基本數據類型):

1、如果是一個指針,通常實現函數的意圖是以這個指針傳遞出一個結果來。

2、如果是一個引用,同上。

3、如果是一個const指針,通常只有面對char*的時候才使用const,實現函數的意圖是,不會改變這個參數的內容。其它情況一般都避免出現使用const指針。

4、如果是一個const引用,對于基本數據類型來說,一般都避免出現這種情況。

Lua和cpp都允許函數用某種方式返回多個值,對于cpp來說,多個返回值是通過上述的第1和第2種情況返回的,對于lua來說,多個返回值可以直接返回:

  1. --in Lua  
  2. function swap(x, y)  
  3. tmp = x 
  4. x = y 
  5. y = tmp 
  6. return x, y  
  7. end  
  8. x = 100 
  9. y = 200 
  10. x, y = swap(x, y)  
  11. print(x..y)  
  12.  
  13. 程序輸出:200100 

同樣的,在主機程序中,我們也可以向Lua返回多個值:

  1. int swap(lua_State *L)  
  2. {  
  3. //取得兩個參數  
  4. int x = Get(TypeWrapper<int>(), L, -1);  
  5. int y = Get(TypeWrapper<int>(), L, -2);  
  6.  
  7. //交換值  
  8. int tmp = x;  
  9. x = y;  
  10. y = tmp;  
  11.  
  12. //向Lua返回值  
  13. Push(L, x);  
  14. Push(L, y);  
  15.  
  16.   //告訴Lua我們返回了多少個值  
  17. return 2;  

現在我們可以在Lua中這樣調用這個函數:

  1. x = 100 
  2. y = 200 
  3. x, y = swap(x, y) 

在我們的register_proxy函數中只能對基本數據類型的by value方式有效,根據我們上面的分析,如果我們能夠在編譯期知道,對于一個模板參數T:

1、這是一個基本的數據類型,還是一個用戶自定義的數據類型?

2、這是一個普通的指針,還是一個iterator?

3、這是一個引用嗎?

4、這是一個const 普通指針嗎?

5、這是一個const 引用嗎?

如果我們能知道這些,那么,根據我們上面的分析,我們希望:(只針對基本數據類型)

1、 如果這是一個指針,我們希望把指針所指的內容返回給Lua

2、 如果這是一個引用,我們希望把引用的指返回給Lua

3、 如果這是const指針,我們希望將從Lua棧中取得的參數傳遞給調用函數。
         
4、 如果這是一個const引用,我們也希望把從Lua棧中取得的參數傳遞給調用函數。

小結:在游戲中如何來使用LUA的內容介紹完了,希望通過本文的學習能對你有所幫助!

責任編輯:zhaolei 來源: 博客園
相關推薦

2010-04-27 17:14:36

AIX svmon

2010-05-06 17:24:05

Unix命令

2014-03-10 09:22:31

LuaLua開發

2019-05-27 15:00:17

Pygame游戲平臺

2010-02-01 14:48:43

2022-05-27 11:22:40

Canvas超級瑪麗游戲

2010-03-11 18:57:17

Python腳本

2011-08-25 09:55:27

2015-09-23 10:25:41

Docker英雄聯盟Docker實踐

2022-01-12 10:37:09

區塊鏈技術金融

2011-08-25 13:22:40

CEGUILua腳本

2011-08-29 15:10:19

JAVALua 腳本

2017-03-29 11:00:28

區塊鏈比特幣游戲

2013-04-03 15:10:09

GMGC全球移動游戲大

2012-05-09 12:18:14

HTML5Canvas

2015-08-11 08:51:40

游戲死亡

2011-08-24 09:49:38

VS2008Lua解釋器

2011-08-24 13:56:12

Lua游戲

2013-12-13 17:21:14

Lua腳本語言

2009-12-15 17:53:18

Ruby標準庫
點贊
收藏

51CTO技術棧公眾號

午夜在线视频免费| 黑人狂躁日本娇小| 自拍偷拍亚洲视频| 亚洲国产电影在线观看| 亚洲一区二区在线| 成年人免费高清视频| 欧美熟乱15p| 精品久久一区二区三区| 日韩免费毛片视频| fc2ppv国产精品久久| 91在线精品一区二区| 国产精品专区一| 日本天堂在线视频| 婷婷亚洲图片| 亚洲精品有码在线| 免费人成视频在线播放| 人人视频精品| 亚洲第一激情av| 一区二区视频在线观看| 日本波多野结衣在线| 久久国产精品72免费观看| 久久免费福利视频| www色aa色aawww| 国产亚洲电影| 亚洲精品一线二线三线无人区| 凹凸日日摸日日碰夜夜爽1| 在线电影福利片| 欧美国产丝袜视频| 免费在线成人av| 日本免费一区视频| 福利电影一区二区| 成人性生交大片免费看视频直播| 国产三级精品三级在线观看| 欧美日本不卡| 久久福利网址导航| 女人裸体性做爰全过| 日本午夜精品久久久| 日韩视频免费观看高清完整版在线观看| 免费黄色一级网站| 中文字幕乱码中文乱码51精品| 一区二区三区视频在线看| 亚洲午夜精品久久| 都市激情在线视频| 久久夜色精品国产噜噜av| 国产另类自拍| 欧日韩在线视频| 成人在线视频一区二区| 7777精品伊久久久大香线蕉语言| 11024精品一区二区三区日韩| 视频一区二区三区入口| 国产91精品在线播放| av网站中文字幕| 国产欧美一区二区三区国产幕精品| 欧美日韩国产va另类| 欧美卡一卡二卡三| 欧美1区2区| 欧美俄罗斯乱妇| 久久成人国产精品入口| 亚洲国产一区二区三区在线播放| 日韩在线资源网| 美国黄色一级视频| 1204国产成人精品视频| 日韩女优av电影| 曰本三级日本三级日本三级| 7777精品| 日韩精品中文字幕久久臀| 丰满少妇一区二区| 精品视频黄色| 日韩在线资源网| 青青操国产视频| 韩日成人av| 高清欧美性猛交xxxx黑人猛交| 国产一级中文字幕| 午夜亚洲精品| 国产精品专区一| 亚洲AV无码国产精品午夜字幕| 粉嫩绯色av一区二区在线观看| 国产精品一区二区你懂得| 亚洲aaaaaaa| 亚洲国产高清在线观看视频| 男插女免费视频| 免费成人在线电影| 在线观看欧美精品| 樱花草www在线| 国产精品调教视频| 国产亚洲欧洲高清| 欧美人妻精品一区二区免费看| 精品二区久久| 国产精品91在线| 国产色视频在线| 91麻豆精品一区二区三区| 日本在线播放不卡| 在线播放免费av| 欧美性高潮在线| 天天影视色综合| 噜噜噜狠狠夜夜躁精品仙踪林| 亚洲日本中文字幕| 欧美日韩免费一区二区| 久久久久免费| 不卡一区二区三区视频| 黄色小视频在线观看| 亚洲精品成a人| 国产免费成人在线| 99tv成人影院| 亚洲欧洲在线观看| 久久久久亚洲av成人片| 日本女优在线视频一区二区| 高清国产在线一区| 五月婷婷在线观看| 欧美性开放视频| 被黑人猛躁10次高潮视频| 中文字幕伦av一区二区邻居| 欧美日韩高清在线观看| 中文字字幕在线观看| av成人老司机| 欧美日韩激情四射| 久久99国产精品二区高清软件| 亚洲国产成人在线视频| 日韩欧美综合视频| 日韩 欧美一区二区三区| 国产日产精品一区二区三区四区| www.亚洲视频| 色偷偷久久人人79超碰人人澡| 亚洲精品久久一区二区三区777| 久久精品国产亚洲夜色av网站| 7777精品视频| 韩国av免费在线| 亚洲三级理论片| 女同激情久久av久久| sdde在线播放一区二区| 欧美亚洲另类视频| 欧美特黄一级视频| 亚洲最大色网站| 在线观看免费看片| 一区二区蜜桃| 91色精品视频在线| 青青影院在线观看| 欧美日韩在线精品一区二区三区激情| 亚洲欧美视频在线播放| 精品69视频一区二区三区Q| 成人日韩在线电影| 日韩精品黄色| 91成人国产精品| 亚洲色成人网站www永久四虎| 国产亚洲成人一区| 精品午夜一区二区三区| 欧亚在线中文字幕免费| 亚洲国产欧美精品| 国产香蕉视频在线| 99久久综合精品| 91国视频在线| 久久av免费| 国产成人精品优优av| 免费在线视频一级不卡| 色婷婷亚洲精品| 亚洲av成人无码久久精品 | 久久观看最新视频| 玖玖玖电影综合影院| 欧美精品在线第一页| www久久久com| 午夜影视日本亚洲欧洲精品| 一级特级黄色片| 亚洲欧美成人综合| 日韩精品欧美一区二区三区| 国产精品黄色片| 久久在线免费视频| 丁香六月色婷婷| 姬川优奈aav一区二区| 女~淫辱の触手3d动漫| 日本亚洲天堂网| 香蕉视频在线网址| 亚洲欧洲国产精品一区| 性欧美在线看片a免费观看| 日韩私人影院| 欧美日韩成人一区二区| 欧美xxxx黑人xyx性爽| 成a人片亚洲日本久久| 日本www在线播放| 日本久久精品| 99re在线视频观看| 成人免费看黄| 久久精品亚洲一区| 神马午夜一区二区| 91久久国产最好的精华液| 国产色无码精品视频国产| 成人久久久精品乱码一区二区三区 | 99热在线成人| 国产精品区一区二区三在线播放| 中文在线аv在线| 久久久999精品视频| 日韩永久免费视频| 欧美偷拍一区二区| 国产福利久久久| 中文一区在线播放| 国产精品成人99一区无码| 免费成人av在线| 国产玉足脚交久久欧美| 成人久久一区| 国产一区高清视频| av一级久久| 国产999精品久久久| 丝袜综合欧美| 中文字幕亚洲无线码a| 少妇无码一区二区三区| 欧美精品丝袜久久久中文字幕| 国产一区二区三区影院| 亚洲三级在线免费| 在哪里可以看毛片| 成人一区二区三区视频| 奇米影音第四色| 亚洲视频1区| 国产一区二区三区在线免费| 日本不卡高清| 日韩av一区二区三区美女毛片| 4438全国亚洲精品观看视频| 国产日本欧美一区二区三区| 亚洲男人av| 久久久久久久久久国产精品| 麻豆影视国产在线观看| 国产亚洲激情在线| 无码国产精品高潮久久99| 日韩一级视频免费观看在线| 综合久久中文字幕| 一本一道久久a久久精品| 久草免费在线视频观看| 亚洲人成精品久久久久久 | 亚洲精品日产精品乱码不卡| 萌白酱视频在线| 国产日韩精品视频一区| 国产黄色网址在线观看| av高清不卡在线| 成人在线视频免费播放| 国产成人精品三级| 91亚洲一区二区| 国产在线不卡一区| 午夜宅男在线视频| 欧美aaaaaa午夜精品| 宅男噜噜噜66国产免费观看| 三级亚洲高清视频| 蜜臀av午夜一区二区三区| 亚洲欧美日韩国产| 免费高清在线观看免费| 每日更新成人在线视频| 日韩在线视频在线观看| 免费欧美在线| 那种视频在线观看| 老妇喷水一区二区三区| 久久久久久香蕉| 日韩av一区二区三区| 在线免费观看av的网站| 久久精品免费观看| 天天综合网久久| 国产一区二区三区久久久| 特级西西444www| 国产成人免费av在线| 美女黄色一级视频| caoporn国产一区二区| 中文字幕狠狠干| 国产午夜亚洲精品羞羞网站| 亚洲一级黄色录像| 最新中文字幕一区二区三区| av激情在线观看| 亚洲高清免费一级二级三级| 成人免费视频毛片| 欧美亚洲国产一区在线观看网站| 岳乳丰满一区二区三区| 欧美福利视频一区| 亚洲av无码乱码国产精品| 亚洲国产欧美久久| 国产免费av高清在线| 久久亚洲国产成人| 3344国产永久在线观看视频| 日本欧美中文字幕| 色999韩欧美国产综合俺来也| 99re6在线| 国产剧情一区| 好吊色这里只有精品| 99成人在线| 蜜臀av免费观看| 国产aⅴ精品一区二区三区色成熟| 丰满岳乱妇一区二区| 中文字幕精品一区| 久久久久久久久久久97| 欧美性猛交xxxx乱大交| 国产一区二区波多野结衣| 337p日本欧洲亚洲大胆精品| 国产高清免费av在线| 欧美成人全部免费| 竹内纱里奈兽皇系列在线观看 | 国产精品毛片视频| 翔田千里亚洲一二三区| 国产综合精品| 在线观看免费黄网站| 成人少妇影院yyyy| 9.1片黄在线观看| 亚洲国产毛片aaaaa无费看| 欧美成人精品网站| 精品少妇一区二区三区在线视频| 国产人成在线视频| 国内精品一区二区三区| 精品福利在线| 久久婷婷开心| 欧美在线观看天堂一区二区三区| wwwxxx黄色片| 成人午夜激情在线| 国产精品视频看看| 欧美日韩激情网| 国产高潮在线观看| 最近2019年手机中文字幕| 涩涩网在线视频| 成人资源av| 国产精品久久久久久久免费观看| 精品一区二区中文字幕| 国产98色在线|日韩| 国产精品理论在线| 欧美性猛交视频| 高h调教冰块play男男双性文| 日韩中文字幕免费看| 桃花岛成人影院| 精品伊人久久大线蕉色首页| 欧美特黄一区| 在线观看视频在线观看| 国产精品国产a| 美女黄页在线观看| 一道本无吗dⅴd在线播放一区 | 国产精品免费观看高清| 91精品高清| 五月天丁香花婷婷| 中文字幕精品一区| 怡春院在线视频| 一区二区在线视频| 成人开心激情| 日韩精品另类天天更新| 日韩精品成人一区二区三区| 中文字幕一区二区三区人妻不卡| 香蕉av福利精品导航| 亚洲精品字幕在线| 欧美福利视频在线| 日韩成人在线观看视频| 日韩中文在线字幕| 国产一区二三区好的| 182在线观看视频| 制服.丝袜.亚洲.另类.中文 | 国产精品入口久久| 国产成人av影视| 国产视频一区二区在线观看| 无码人妻熟妇av又粗又大| 亚洲精品一区久久久久久| 欧美大片免费高清观看| 欧美日韩亚洲一区二区三区在线观看| 国产视频一区三区| a级片在线观看| 欧美性xxxxxxxx| 麻豆视频免费在线观看| 成人中文字幕+乱码+中文字幕| 香蕉国产精品| 亚洲区 欧美区| 午夜伊人狠狠久久| 麻豆影视在线| 国产精品极品在线| 国产精品久久久久久久免费观看| 免费不卡av网站| 亚洲国产成人精品视频| 神马亚洲视频| 国产精品三级久久久久久电影| 97国产成人高清在线观看| 国产精品欧美性爱| 欧美日韩在线视频一区二区| 成人在线免费电影| 亚洲va电影大全| 日韩天堂av| 免费黄色在线网址| 日韩欧美国产午夜精品| 麻豆网站免费在线观看| 欧美一区二区三区电影在线观看| 蜜桃av一区二区| 久久久.www| 亚洲欧美在线看| 激情视频亚洲| 色综合av综合无码综合网站| 中文字幕欧美激情| 亚洲国产999| 日本高清不卡在线| 91精品国产91久久久久久密臀| 精品人妻一区二区免费| 91久久免费观看| 爱情岛论坛亚洲品质自拍视频网站| 欧美日韩精品一区| 国产酒店精品激情| 波多野结衣 久久| 欧美日本高清视频| 精品国产中文字幕第一页| 日本中文字幕在线不卡| 欧美日韩中文字幕综合视频| av免费看在线| 日韩视频在线观看国产| 成人三级伦理片| 国产女人18毛片水18精| 青青草成人在线| 国产主播一区|