关于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自动绑定系统问题的内容介绍完了,希望通过本文的学习能对你有所帮助!