C++ 对象的Lua脚本化-阿里云开发者社区

开发者社区> leonwei> 正文

C++ 对象的Lua脚本化

简介:
+关注继续查看

脚本化编程

脚本化编程的最大好处就是简单灵活,另外就是热更新,这在网游中广泛被采用,在网游中,通常采用引擎(c/C++)+脚本(lua/python)的架构,那种SDK性质的代码放在引擎中,这些代码在游戏上线后通常很稳定很少被修改,而真正游戏逻辑的制作就都在脚本层中进行。这样有两个好处:1.脚本层的bug基本不会导致程序的crash,因为是沙盒的。2.对于运行的代码,可以方便的采用热更新修复bug。

C与lua的交互

  而如果想在脚本层编写逻辑代码,一个最重要的就是需要将引擎层即C++中的对象、函数、全局变量等等暴露给脚本层来访问,当然有时也要能让C++层能够方便的访问脚本层的全局变量。最近稍微仔细的探索了一下C++与Lua之间交互的知识,稍作总结,分享给需要的人。

在C中可以写代码访问调用lua(函数、变量..),同时也可以在C中写代码让所lua里面能访问c。c和lua的交互通常无外乎就以下这三种情况

1.这种情况C是启动程序,然后调用lua里的变量

2.这种情况C被编成库程序,启动程序是lua(通常是你的lua解释器lua.exe),在lua中可以使用c的变量

3.这种情况C是启动程序,然后调用lua里的变量,然后调用的lua里面又能访问c的变量。

 

无论以上哪种,情况,做到C和lua交互的代码都是在c中写的,这些代码被称为lua的C API。我们要利用C API做三件事:

1.执行某个LUA脚本

2.获取某个LUA的全局变量

2.将C变量或函数注册成指定的规格,使得在LUA中可以调用注册的那些C变量和函数。

 

如果能完成者三件事,那么就可以完成上图的所有这些途径。

将C API的常用功能和交互的API以图形化的方法绘制出来:


上图中C和lua通过一个虚拟的栈(全局的还有函数内部局部的)来实现互相的访问。

其中

1.执行某个LUA脚本

2.获取某个LUA的全局变量

2.将C变量或函数注册成指定的规格,使得在LUA中可以调用注册的那些C变量和函数。

这三点都可以在上图中找到相关的实现方法,但是这些方法都是为C写的,对于C++的引擎来说,我们通常想实现一种在脚本层的面向对象的访问,通俗来说,比如C++层有个类C,C有个借口 Get(),我们希望在脚本层可以方便的写出c= newClassC(),c:Get()这样的代码,这就是本文探讨的C++对象的LUa脚本化,这在C++引擎的脚本化编程中非常重要。

C++ 对象的Lua脚本化

假设有一个类MyCClass 我在C++层实现了它的一些方法,如SetI(int)、 GetI()等,我想将这个类脚本化给Lua层能面向对象的访问。

下面写下我的一些简要实现

--New :

在C++中定义函数int MyCClass::NewMyCClass( lua_State* L ) ,这个函数在lua中可以使用c=NewMyCClass()来生成一个MyCClass的对象

NewMyCClass 具体实现是:

int MyCClass::NewMyCClass( lua_State* L )
{

//创建usrdata实例并传到栈中
 size_t bytes=sizeof(MyCClass);
 MyCClass* c=(MyCClass*)lua_newuserdata(L,bytes);


 //为usrdata创建元表以实现面向对象的方法,这里给c这个对象加入一个元表,原表中对GetI这个index赋予MyCClass::GetI这个函数
 int r=luaL_newmetatable(L,"MyCClassMeta");
 lua_pushvalue(L,-1);//copy --index table
 lua_pushcfunction(L,MyCClass::GetI);
 lua_setfield(L,-2,"GetI");//reg func
 lua_setfield(L,-2,"__index");//set __index table
 
 lua_setmetatable(L,-2);//-2?

 return 1;
}

当然在程序开始处要注册这个NewMyCClass

lua_register(L,"NewMyCClass",MyCClass::NewMyCClass);

 

--成员函数GetI:可以在lua层 c:GetI()

int MyCClass::GetI( lua_State* L )
{
 MyCClass* c=(MyCClass*)lua_touserdata(L,1);

int r=c->GetI()
 lua_pushinteger(L,r);
 return 1;
}

 

--成员函数SetI  可以在lua层 c:SetI(100)

int MyCClass::SetI( lua_State* L )
{
 MyCClass* c=(MyCClass*)(lua_touserdata(L,1));
 int p1=luaL_checkint(L,2);

int r=c->SetI(p1)
 return 0;
 

}

 

这样一个非常简单的在lua层面向对象的访问C++的实现就好了。

 

优化

1.完整的版本在元表的赋值中可能还有加入MyCClass::Del以实现c:Del()来删除 但是有些架构所有的析构操作可能都在引擎层完成,并不暴露给脚本层,(甚至new操作也是)

2.上面的代码对于在c++中写的每个类都要相应的写出来一遍这些函数,如对于MyCClass::SetI(int i)你就要写一个供lua调用版本的static int MyCClass::SetI( lua_State* L ),因为给lua调用函数永远是这种类型,且需要是全局的。在实际框架的搭建中,我们通常采用宏函数的方法,如定义一个宏 REG_CLASS_FUNC(class,class_func)来按一定规则自动产生这个lua调用版的函数。相应的也可以通过定义一个宏函数REG_CLASS来自动注册一个类的lua_register(L,"NewMyCClass",MyCClass::NewMyCClass)给lua

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
《Lua游戏开发实践指南》一第2章 脚 本 语 言
本节书摘来华章计算机《Lua游戏开发实践指南》一书中的第2章 ,(美)Paul SchuytemaMark Manyen著 田剑译 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
916 0
《JavaScript启示录》——1.3 JavaScript原生/内置对象构造函数
JavaScript语言包含9个原生(或内置)对象构造函数。JavaScript使用这些对象来构建JavaScript语言。“构建”的意思是指,这些对象是用于表达JavaScript代码中的对象值,以及协调语言中的多个特性。
1370 0
C++函数对象
  原文:http://blog.csdn.net/ggggqqqqihc/article/details/1727020   标准库里的count_if可以统计容器中满足特定条件的元素的个数。例如要统计一个整数vector——ivec中正数的个数,可以先写一个返回类型为bool,含有一个int参数的条件函数: bool pred(int val){ return val>0; }    之后可以用count_if(ivec.begin(),ivec.end(),pred)计算出正整数的个数。
465 0
关于 OpenGL 中平移矩阵变换与实体对象坐标平移的关系分析结论
关于 OpenGL 中平移矩阵变换与实体对象坐标平移的关系分析结论 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循“署名-非商业用途-保持一致”创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。
638 0
C++程序中嵌入Ruby脚本系统
Ruby,一种为简单快捷面向对象编程(面向对象程序设计)而创的脚本语言,由日本人松本行弘(まつもとゆきひろ,英译:Yukihiro Matsumoto,外号matz)开发,遵守GPL协议和Ruby License。
1257 0
《JavaScript启示录》——第1章 JavaScript对象 1.1创建对象
JavaScript实际上是一种预包装若干原生对象构造函数的语言。这些构造函数用于生成一些表达特定类型值(如数字、字符串、函数、对象、数组等)的复杂对象,同样,也可以通过Function()对象创建自定义的对象构造函数(例如Person())。
1310 0
+关注
87
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载