以上篇为例,编写一个pkg文件,接下来单独解析这个pkg文件
创建一个新的批处理脚本,命名为TestBuild.bat,输入以下内容
@echo off
:begin
set/p a1=请输入pkg文件名称并按回车:
rem echo 你输入的pkg文件名称是:%a1%,如果确认请按y
set/p a2=你输入的pkg文件名称是:%a1%,如果确认请按y并回车:
if %a2% NEQ y goto begin
D:\cocos2d\cocos2d-x-2.2.2\cocos2d-x-2.2.2\tools\tolua++\tolua++.exe -o %a1%.cpp %a1%.pkg
pause运行此文件,输入上一篇文件的pkg文件的名称TestSprite.pkg,如果在当前目录看到生成了一个TestSprite.cpp,则说明已经单独为这个pkg文件生成了一个中间转换类。
cocos2d-x2.2.2中是用tolua++第三方库来专门处理LUA脚本,它可以很好的帮助开发者完成lua访问c++类的成员函数的功能。
先看下lua用传统的方式访问c++的类。
首先,用lua调用c++的成员函数是以函数指针的形式进行调用,即要满足以下类型的函数才能被lua调用
typedef int (*lua_CFunction) (lua_State *L);
其中lua_State用于存储栈中的信息,返回函数返回值个数的一个整形值,返回值的内容存在栈中,用lua_State取。
测试cpp如下:
#include <string>
#include <math.h>
#include <iostream>
using namespace std;
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
lua_State* l = NULL;
//求总和
static int addSum(lua_State* l) {
int n = lua_gettop(l);//获取栈顶的编号,即栈中的个数
double sum = 0;
for(int i = 1; i <= n; i++) {
if(!lua_isnumber(l, i)) {//存在非数字的跳过,并提示错误
lua_pushstring(l, "Not a Number"); //压入字符串到栈
lua_error(l);
}else {
sum += lua_tonumber(l, i);
}
}
lua_pushnumber(l, sum);//将相加的结果压入栈中
lua_pushnumber(l, n);//将相加数也压入栈中
return 2;//两个返回值
}
//主函数
int main(int argc, char *argv[]) {
//初始化lua_State
l = lua_open();
//打开lua库
luaL_openlibs(l);
//注册c++函数供lua调用("addSum" -- lua调用的名字, addSum--自定义函数的函数指针)
lua_register(l, "addSum", addSum);
//执行一个脚本
luaL_dofile(l, "test.lua");
//下面是用c++取出lua执行完函数后的结果
//获取脚本变量sum的值,放入栈顶
lua_getglobal(l, "sum");
//从栈顶取值
cout<<"c++: The sum is "<<lua_tointeger(l, -1)<<endl;
//从栈顶弹出一个值
lua_pop(l, 1);
//获取脚本变量n的值,放入栈顶
lua_getglobal(l, "n");
//从栈顶取值
cout<<"c++: The num is "<<lua_tointeger(l, -1)<<endl;
//回收内存
lua_close(l);
return 0;
}
lua脚本
sum, n = addSum(1, 2, 3, 4)
print("lua: The sum is", sum)
print("lua: The num is", n)运行结果:
以上的过程说明了要用lua调用c++的成员函数必须要进行栈操作,当一个类的成员函数一庞大的话处理起来就会相当麻烦。
接上一篇的内容,看下用tolua++执行完自定义的pkg文件后LuaCocos2d.cpp新增的内容
打开LuaCocos2d.cpp搜索自定义的类,如TestSprite,发现找到了以下代码
tolua_usertype(tolua_S,"TestSprite");找到执行这行代码的方法,如下/* function to register type */
static void tolua_reg_types (lua_State* tolua_S)借助注释,由这个方法体可以推断出任何可供被lua调用的类都应该要在这个方法中注册。
再往下搜索,找到下面的一个方法
/* method: create of class TestSprite */
#ifndef TOLUA_DISABLE_tolua_Cocos2d_TestSprite_create00
static int tolua_Cocos2d_TestSprite_create00(lua_State* tolua_S)
...再找到这个方法的调用的(搜索tolua_Cocos2d_TestSprite_create00),看到如下代码
tolua_cclass(tolua_S,"TestSprite","TestSprite","CCSprite",NULL);
tolua_beginmodule(tolua_S,"TestSprite");
tolua_function(tolua_S,"create",tolua_Cocos2d_TestSprite_create00);
tolua_function(tolua_S,"init",tolua_Cocos2d_TestSprite_init00);
tolua_function(tolua_S,"setPosCenter",tolua_Cocos2d_TestSprite_setPosCenter00);
tolua_function(tolua_S,"createLabel",tolua_Cocos2d_TestSprite_createLabel00);
tolua_endmodule(tolua_S);由此可以推断上面的那个方法是一个转换方法,即lua要调用自定义类的函数时进行的一些压栈出栈等操作,而且上面也列出了自定义类可供lua调用的方法,每个方法对应一个转换函数。再看执行上面那段代码的方法。
/* Open function */
TOLUA_API int tolua_Cocos2d_open (lua_State* tolua_S)借助注释可以看出就是c++暴露给lua调用的函数,而且是模块的形式进行。
再回过头来看下tolua_Cocos2d_TestSprite_create00这个转换函数
/* method: create of class TestSprite */
#ifndef TOLUA_DISABLE_tolua_Cocos2d_TestSprite_create00
static int tolua_Cocos2d_TestSprite_create00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertable(tolua_S,1,"TestSprite",0,&tolua_err) ||
!tolua_isnoobj(tolua_S,2,&tolua_err)
)
goto tolua_lerror;
else
#endif
{
{
TestSprite* tolua_ret = (TestSprite*) TestSprite::create();
tolua_pushusertype(tolua_S,(void*)tolua_ret,"TestSprite");
}
}
return 1;
#ifndef TOLUA_RELEASE
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'create'.",&tolua_err);
return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE首先是判断参数是否合法,不合法跳过解析块,直接跳到tolua_lerror处,否则tolua++执行转换解析。再看下tolua_pushusertype这个方法,打开cocos2d引擎的根目录\scripting\lua\tolua\tolua_push.c,找到tolua_pushusertype方法的定义
TOLUA_API void tolua_pushusertype (lua_State* L, void* value, const char* type)
{
tolua_pushusertype_internal(L, value, type, 0);
}
再跳到tolua_pushusertype_internal,void tolua_pushusertype_internal (lua_State* L, void* value, const char* type, int addToRoot)
{
if (value == NULL)
lua_pushnil(L);
else
{
luaL_getmetatable(L, type); /* stack: mt */
if (lua_isnil(L, -1)) { /* NOT FOUND metatable */
lua_pop(L, 1);
return;
}
lua_pushstring(L,"tolua_ubox");
lua_rawget(L,-2); /* stack: mt ubox */
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
lua_pushstring(L, "tolua_ubox");
lua_rawget(L, LUA_REGISTRYINDEX);
};
lua_pushlightuserdata(L,value); /* stack: mt ubox key<value> */
lua_rawget(L,-2); /* stack: mt ubox ubox[value] */
if (lua_isnil(L,-1))
{
lua_pop(L,1); /* stack: mt ubox */
lua_pushlightuserdata(L,value);
*(void**)lua_newuserdata(L,sizeof(void *)) = value; /* stack: mt ubox value newud */
lua_pushvalue(L,-1); /* stack: mt ubox value newud newud */
lua_insert(L,-4); /* stack: mt newud ubox value newud */
lua_rawset(L,-3); /* ubox[value] = newud, stack: mt newud ubox */
lua_pop(L,1); /* stack: mt newud */
/*luaL_getmetatable(L,type);*/
lua_pushvalue(L, -2); /* stack: mt newud mt */
lua_setmetatable(L,-2); /* update mt, stack: mt newud */
#ifdef LUA_VERSION_NUM
lua_pushvalue(L, TOLUA_NOPEER); /* stack: mt newud peer */
lua_setfenv(L, -2); /* stack: mt newud */
#endif
}
else
{
/* check the need of updating the metatable to a more specialized class */
lua_insert(L,-2); /* stack: mt ubox[u] ubox */
lua_pop(L,1); /* stack: mt ubox[u] */
lua_pushstring(L,"tolua_super");
lua_rawget(L,LUA_REGISTRYINDEX); /* stack: mt ubox[u] super */
lua_getmetatable(L,-2); /* stack: mt ubox[u] super mt */
lua_rawget(L,-2); /* stack: mt ubox[u] super super[mt] */
if (lua_istable(L,-1))
{
lua_pushstring(L,type); /* stack: mt ubox[u] super super[mt] type */
lua_rawget(L,-2); /* stack: mt ubox[u] super super[mt] flag */
if (lua_toboolean(L,-1) == 1) /* if true */
{
lua_pop(L,3); /* mt ubox[u]*/
lua_remove(L, -2);
return;
}
}
/* type represents a more specilized type */
/*luaL_getmetatable(L,type); // stack: mt ubox[u] super super[mt] flag mt */
lua_pushvalue(L, -5); /* stack: mt ubox[u] super super[mt] flag mt */
lua_setmetatable(L,-5); /* stack: mt ubox[u] super super[mt] flag */
lua_pop(L,3); /* stack: mt ubox[u] */
}
lua_remove(L, -2); /* stack: ubox[u]*/
if (0 != addToRoot)
{
lua_pushvalue(L, -1);
tolua_add_value_to_root(L, value);
}
}
}可以看出tolua_pushusertype确实是一个转换函数,里面执行了lua调用c++函数时所需要的栈操作。
356

被折叠的 条评论
为什么被折叠?



