『Game』lua和c/c++互相调用实例分析

来源:互联网 发布:caffe axis 编辑:程序博客网 时间:2024/06/05 06:23

原文地址:lua和c/c++互相调用实例分析


lua作为小巧精悍的脚本语言,易于嵌入c/c++中 , 广泛应用于游戏AI ,实际上在任何经常变化的逻辑上(其灵活性可应对经常变化的逻辑,在lua与c交互上也得有办法,让它们易用才行。)都可以使用lua实现,配合c/c++实现的底层接口服务,能够大大降低系统的维护成本。下面对lua和c/c++的交互调用做一个实例分析:
lua提供了API用于在c/c++中构造lua的运行环境,相关接口如下:
//创建lua运行上下文
lua_State* luaL_newstate(void) ;
//加载lua脚本文件
int luaL_loadfile(lua_State *L, const char *filename);

lua和c/c++的数据交互通过"栈"进行 ,操作数据时,首先将数据拷贝到"栈"上,然后获取数据,栈中的每个数据通过索引值进行定位,索引值为正时表示相对于栈底的偏移索引,索引值为负时表示相对于栈顶的偏移索引,索引值以1或-1为起始值,因此栈顶索引值永远为-1 ,栈底索引值永远为1 。 "栈"相当于数据在lua和c/c++之间的中转地。每种数据都有相应的存取接口 。
数据入"栈"接口:
void  (lua_pushnil) (lua_State *L);
void  (lua_pushnumber) (lua_State *L, lua_Number n);
void  (lua_pushinteger) (lua_State *L, lua_Integer n);
void  (lua_pushlstring) (lua_State *L, const char *s, size_t l);
void  (lua_pushstring) (lua_State *L, const char *s);
void  (lua_pushboolean) (lua_State *L, int b);
void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);

数据获取接口:
lua_Number      (lua_tonumber) (lua_State *L, int idx);
lua_Integer     (lua_tointeger) (lua_State *L, int idx);
int             (lua_toboolean) (lua_State *L, int idx);
const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len);
lua_CFunction   (lua_tocfunction) (lua_State *L, int idx);


"栈"操作接口:
int   (lua_gettop) (lua_State *L);
void  (lua_settop) (lua_State *L, int idx);
void  (lua_pushvalue) (lua_State *L, int idx);
void  (lua_remove) (lua_State *L, int idx);
void  (lua_insert) (lua_State *L, int idx);
void  (lua_replace) (lua_State *L, int idx);
int   (lua_checkstack) (lua_State *L, int sz);

lua中定义的变量和函数存放在一个全局table中,索引值为LUA_GLOBALSINDEX ,table相关操作接口:
void  (lua_gettable) (lua_State *L, int idx);
void  (lua_getfield) (lua_State *L, int idx, const char *k);
void  (lua_settable) (lua_State *L, int idx);
void  (lua_setfield) (lua_State *L, int idx, const char *k);

当"栈"中包含执行脚本需要的所有要素(函数名和参数)后,调用lua_pcall执行脚本:
int   (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);

下面进行实例说明:
func.lua

--变量定义width=1 ;height=2 ;--lua函数定义,实现加法function sum(a,b)    return a+b ;end--lua函数定义,实现字符串相加function mystrcat(a,b)    return a..b ;end--lua函数定义,通过调用c代码中的csum函数实现加法function mysum(a,b)    return csum(a,b) ;end

test_lua.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>//lua头文件#include <lua.h>#include <lualib.h>#include <lauxlib.h>#define err_exit(num,fmt,args)  \    do{printf("[%s:%d]"fmt"\n",__FILE__,__LINE__,##args);exit(num);} while(0)#define err_return(num,fmt,args)  \    do{printf("[%s:%d]"fmt"\n",__FILE__,__LINE__,##args);return(num);} while(0)//lua中调用的c函数定义,实现加法int csum(lua_State* l){    int a = lua_tointeger(l,1) ;    int b = lua_tointeger(l,2) ;    lua_pushinteger(l,a+b) ;    return 1 ;}int main(int argc,char** argv){    lua_State * l = luaL_newstate() ;        //创建lua运行环境    if ( l == NULL ) err_return(-1,"luaL_newstat() failed");     int ret = 0 ;    ret = luaL_loadfile(l,"func.lua") ;      //加载lua脚本文件    if ( ret != 0 ) err_return(-1,"luaL_loadfile failed") ;    ret = lua_pcall(l,0,0,0) ;    if ( ret != 0 ) err_return(-1,"lua_pcall failed:%s",lua_tostring(l,-1)) ;    lua_getglobal(l,"width");              //获取lua中定义的变量    lua_getglobal(l,"height");    printf("height:%ld width:%ld\n",lua_tointeger(l,-1),lua_tointeger(l,-2)) ;    lua_pop(l,1) ;                        //恢复lua的栈    int a = 11 ;    int b = 12 ;    lua_getglobal(l,"sum");               //调用lua中的函数sum    lua_pushinteger(l,a) ;    lua_pushinteger(l,b) ;    ret = lua_pcall(l,2,1,0) ;    if ( ret != 0 ) err_return(-1,"lua_pcall failed:%s",lua_tostring(l,-1)) ;    printf("sum:%d + %d = %ld\n",a,b,lua_tointeger(l,-1)) ;    lua_pop(l,1) ;    const char str1[] = "hello" ;    const char str2[] = "world" ;    lua_getglobal(l,"mystrcat");          //调用lua中的函数mystrcat    lua_pushstring(l,str1) ;    lua_pushstring(l,str2) ;    ret = lua_pcall(l,2,1,0) ;    if ( ret != 0 ) err_return(-1,"lua_pcall failed:%s",lua_tostring(l,-1)) ;    printf("mystrcat:%s%s = %s\n",str1,str2,lua_tostring(l,-1)) ;    lua_pop(l,1) ;    lua_pushcfunction(l,csum) ;         //注册在lua中使用的c函数    lua_setglobal(l,"csum") ;           //绑定到lua中的名字csum    lua_getglobal(l,"mysum");           //调用lua中的mysum函数,该函数调用本程序中定义的csum函数实现加法    lua_pushinteger(l,a) ;    lua_pushinteger(l,b) ;    ret = lua_pcall(l,2,1,0) ;    if ( ret != 0 ) err_return(-1,"lua_pcall failed:%s",lua_tostring(l,-1)) ;    printf("mysum:%d + %d = %ld\n",a,b,lua_tointeger(l,-1)) ;    lua_pop(l,1) ;    lua_close(l) ;                     //释放lua运行环境    return 0 ;}

除去图像这一层极端效率敏感的部分外,其他部分其实用效率适当下降换取灵活是值得的



原文地址:目前服務器需要做c++和lua對接,做遊戲的童鞋有比較好的庫和類推薦嗎?

我们游戏用的是lua_tinker, 一个韩国人写根据LuaBind改的,它的优点是简单,就2个文件,并且很容易自己修改。

另外一个常用的是tolua,可以很容易把C++的类导到lua里,供lua调用,不过在C++里调用Lua不太方便。


用过LuaBind,LuaPlus,lua_tinker几个库。
LuaBind大概是05年的样子,功能最全面,效率也很好,不过恶心的是库很大,构建环境比较麻烦,而且那时候还需要Boost库的支持(现在不知道了),比较繁琐,后来不用了;
LuaPlus是之前用的比较广泛的一个库,印象里用到Lua的客户端网游,用他的比较多,特点是中庸(不是贬义);
lua_tinker是现在的游戏使用到的,的确是简单清爽的感觉,个人比较喜欢;

我个人觉得要是客户端游戏用LuaPlus比较好(比如想做那种wowUI的),服务器Lua用lua_tinker。轻量级用lua_tinker,否则就LuaPlus。

另有次无意在HomeWorld 2的游戏中看到了Lua脚本,那是2000-2002年的产物,那时候Lua还没太多人用,可见wow的影响力:(



他们改进了大话和梦幻的服务器设计,把处理连接的部分独立出来放到单独的进程中 ,使服务器性能大大提高。


原文地址:http://www.cnblogs.com/hmxp8/archive/2011/11/23/2259777.html


这一篇对lua堆栈操作讲的很通俗易懂:lua堆栈操作

(1)lua 和 C++之间的交互的基本知识:

      lua 和 C++ 之间的数据交互通过堆栈进行,栈中的数据通过索引值进行定位,(栈就像是一个容器一样,放进去的东西都要有标号)
其中栈顶是-1,栈底是1,也就是第 1 个入栈的在栈底;也可以这么说:正数表示相对于栈底的位置(位移),负数表示相对于栈顶的位置(位移);
(2)计算和清空栈中元素的操作:
1、函数lua_gettop()
用于返回栈中元素的个数,同时也是栈顶元素的索引,因为栈底是1,所以栈中有多少个元素,栈顶索引就是多少;呵呵
2、函数lua_settop()
函数原型:void lua_settop(lua_State *L , int index);
用于把堆栈的栈顶索引设置为指定的数值,比如说,一个栈原来有8个元素,调用函数设置index为7,就是把堆栈的元素数设置为7,也就是删掉一个元素,而且是栈顶元素;这个是用的正数,也就是相对于栈底元素设置的;如果是相对于栈顶元素,则要求用负值;也就是说如果设置索引为-2(index = -2),也相当于删除掉栈顶元素;呵呵,画个图就很方便了;为了说明方便,干脆设置一个宏:
#define lua_pop(L,n) lua_settop(L,-(n)-1)
这里的n是相对于栈顶的第几个元素,主要是为了理解;后面的lua_settop(L,-(n)-1) 用的就是相对于栈顶位移的负数表示;
3、lua_pushvalue()
函数原型:void lua_pushvalue (lua_State *L, int index);
英文原意:Pushes a copy of the element at the given valid index onto the stack. 
    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶)有:
    lua_pushvalue(L, 3)    --> 10 20 30 40 50 30*
lua_pushvalue(L,3)是取得原来栈中的第三个元素,压到栈顶;
4、lua_remove()
void lua_remove(lua_State *L, int index);
lua_remove删除给定索引的元素,并将这一索引之上的元素来填补空缺;
    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    lua_remove(L, -3)      --> 10 20 40 50*

    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    lua_settop(L, -3)      --> 10 20 30 *
    lua_settop(L,  6)      --> 10 20 30 nil nil nil *
5、lua_replace
void    lua_replace    (lua_State* L, int index);
Lua_replace将栈顶元素压入指定位置而不移动任何元素(因此指定位置的元素的值被替换)。
    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    lua_replace(L, 2)      --> 10 50 30 40 *    //把50替换到索引的位置,同时去掉栈顶元素

 

(3)C中加载lua时一些函数的用法

lua_getgobal ------void lua_getglobal (lua_State *L, const char *name);把全局的name的值压到栈顶。

lua_is***(lua_State *L,int index) 检查变量是不是某个类型,index指示变量的顺序,栈顶为-1。

lua_to***(lua_State *L,int index) 获取栈中的变量,然后转换为某个指定的类型,并返回。

lua_close()   销毁所有在指定的Lua State上的所有对象,同时释放所有该State使用的动态分配的空间。





原创粉丝点击