探索關于Lua自動綁定系統問題
關于Lua自動綁定系統問是本文要介紹的內容,因為游戲內容增長的速度遠遠超過了以前,所以程序員已經不能夠完全控制所有代碼行為了。他們需要其他游戲開發者的幫助。腳本語言在游戲里已經被用了幾十年,但是現在的游戲機更能抓住它們的優點來打打提高玩家的體驗。
本精粹著重說明Lua語言的綁定實現。這門技術能夠讓程序員將它們的C++類暴露給Lua,但不需要了解這個系統。這里介紹的工具不僅能用在C++語言里,對其他語言也有效。這種設計的核心思想是易用性、效率、內存占用和多線程的設計目標來驅動的。
1、介紹
在本精粹里介紹的綁定玉虛在Lua腳本里建立、訪問和使用C++對象。舉例來說,在一個singleton的類WORLD里保存了一個ENTITY類型的實力列表,下面的腳本就能夠用來設置玩家的生命值。
- local entity = WORLD:GetEntity("player")
- entity:SetHealth(50)
在這個例子里用到的綁定是由如下的聲明定義的。
- //in.h and class definition
- SCRIPTABLE_DefineClass(WORLD)
- //in.cpp
- SCRIPTABLE_Class(WORLD)
- {
- SCRIPTABLE_ResultMethod1(GetEntity,ENTITY,std::string)
- }
綁定一個類就這么簡單。不需要做其他任何步驟,允許程序員把C++類和自己的函數暴露給Lua,就這么簡單。
2、特性
這個形同的設計目標如下:
低內存消耗;
高效率綁定;
支持C++的繼承;
使用方便;
在腳本與腳本之間保證線程使用的安全。
3、函數的綁定
Lua需要一個特別借口來綁定函數。被綁定的函數必須是下面代碼里定義的類型。Lua的綁定是基于堆棧的,lua_State包含了所有傳到那個函數里去的參數。這些參數必須通過使用堆棧索引號 lua_to*來收集。在這個例子里,這個函數接受到的第一個參數是字符串,第二個參數是數字,返回值也是數字。關于C函數的綁定,你可以在Lua手冊[Ierusalimschy06]里找到更多的相關信息。C函數的綁定是Lua綁定到C/C++的唯一一個方法,也是這個系統的基礎。
- int bingding_method(lua_State* state)
- {
- const char* some_string;
- double some_number,another_number;
- some_string = lua_tostring(state,1);
- some_number = lua_tonumber(state,2);
- //在這里可以設置返回值,或者做點你需要做的事情
- //另外一個數字
- lua_pushnumber(state,another_number);
- return 1;//假如說我們返回1
- }
4、在Lua里的面向對象
Lua是使用廣泛的一種編程語言,功能也很強大。本精粹介紹了如何把Lua變成一個面向對象的語言。為了幫助大家用好這個功能,Lua的作者們定義了一系列的工具來給大家提供語法幫助(syntactic sugar)。下面列出我們在本系統里使用的一個。在這段代碼里,the_object是一個初始的變量,這段代碼模擬了this_call的函數返回。
- the_object:Test(5)==the_object["Test"]( the_object,5)
面向對象的方法可以是用這種語法來實現。對象被當做關系數組,用函數名來進行索引,返回的就是你需要調用的函數。Lua里有一個機制,允許通過使用元表(metatable)來讓任何類型的變量對一個數組進行交互(這事Lua5.1的特性。Lua5.0中只有表和用戶數據對象才有元表)。元表是Lua里的表,這個表被分配給一個對象,這個對象包含一些特殊的字段:_index, _newindex等([Ierusalimschy06])。在那些特殊字段里設置的函數會根據情況來被調用。當一個對象被訪問時,采取的如果是數組形式的訪問方式,_index就被調用了。下面的代碼說明了如何講一個元表設置到一個對象上。
- metatable = {}
- metatable._ _index = function(table,key) return key end
- setmetatable(object, metatable)
- test_return = object["Test"] --在元表里面調用_index函數
Lua的內部函數類型有數字(double 或者float)、string、table、nil、function(Lua或C)、thread和(輕)用戶數據。我們采用最后一個類型在Lua里保存對象。輕用戶數據和用戶數據稍微有點不一樣。第二種完全是Lua對象,可以擁有一個元表。
5、在Lua里綁定C++對象
綁定需要幾個機制:在Lua重新描述C++對象、綁定函數的保存,最后是每個C++對象綁定數據的注冊。在本精粹里,我們先把整體的技術介紹給大家,稍后我們會講解一些特別的例子。
綁定數據結構
在已經存在的現實中,綁定是直接保存在Lua里面的,而相關的綁定數據就幫存在每個腳本里。但是如果系統必須支持的腳本數量很大,那么綁定數據就回不必要的被重復保存。為了避免這樣的情況發生,我們決定把綁定數據保存在C++中一個叫SCRIPTABLE_BINDING_DATA的類里。每個綁定的類都會被分配到一個索引值。
SCRIPTABLE_BINDING_DATA里包含一個記錄雷鳴和類的索引號的映射,它被保存在CLassIndexTable里。然后每個類都有個映射,記錄每個函數名和對應的綁定函數。MethodTable是這種映射的重組,可以根據ClassIndex Table里的值進行索引。因為delete操作符是沒有名字的,所以它的綁定被存放在單獨的數組里,這個數組叫做Delete Table。最后,Parent Table保存了每個類的弗雷的索引。如果某個類是沒有父類的,那么Parent Table的入口就被設置了 -1
在本書附帶光盤中,你可以找到一系列的副主函數,這些輔助函數能夠讓你訪問這些映射。你可以在 scriptable_bingding_data.h文件里找到它們。
- class SCRIPTABLE_BINDING_DATA
- {
- typedef int(* BINDING_FUNCTION) (lua_State *);
- std::map<std:string,int>
- ClassIndexTable;
- std::vector<std::map<std::string,BINDING_FUNCTION>*>
- MethodTable;
- std::vector<BINDING_FUNTION>
- DeleteTable;
- std::vector<int>;
- ParentTable;
- };
指向這個綁定數據的指針和之歌類的索引被存放在lua_State里。這個數據的空間是由luaconf.h里的LUAI_EXTRASPACE常量分配的。
小結:探索關于Lua自動綁定系統問題的內容介紹完了,希望通過本文的學習能對你有所幫助!