![cocos2dx-Lua学习笔记:CCLuaStack,第1张 cocos2dx-Lua学习笔记:CCLuaStack,第1张](/aiimages/cocos2dx-Lua%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%9ACCLuaStack.png)
概述备注: 1 作者对于Lua的使用较少,纯粹从使用出发,对它的理解较浅,可能有错误,还请路过的各位大牛多多指正。 2 本笔记代码部分参考cocos2dx2.2.3代码,代码版权归原作者所有。 3 由于作者时间,经验,能力有限,笔记可能不完整,以后随用随补充吧。 CCLuaStack代码较多,里面实现了大部分Lua与C++代码的交互细节,这里一点点的笔记吧。 lua_print: 打印栈中的所有的内容
备注:
1 作者对于Lua的使用较少,纯粹从使用出发,对它的理解较浅,可能有错误,还请路过的各位大牛多多指正。
2 本笔记代码部分参考cocos2dx2.2.3代码,代码版权归原作者所有。
3 由于作者时间,经验,能力有限,笔记可能不完整,以后随用随补充吧。
ccluaStack代码较多,里面实现了大部分Lua与C++代码的交互细节,这里一点点的笔记吧。
lua_print:
打印栈中的所有的内容。参考网址如下:【 http://cstriker1407.info/blog/lua-basic-notes-stack/】
int lua_print(lua_State * luastate) |
int nargs = lua_gettop(luastate); |
for ( int i=1; i <= nargs; i++) |
if (lua_istable(luastate,i)) |
else if (lua_isnone(luastate,i)) |
else if (lua_isnil(luastate,i)) |
else if (lua_isboolean(luastate,i)) |
if (lua_toboolean(luastate,i) != 0) |
else if (lua_isfunction(luastate,i)) |
else if (lua_islightuserdata(luastate,i)) |
else if (lua_isthread(luastate,i)) |
const char * str = lua_tostring(luastate,i); |
t += lua_tostring(luastate,i); |
t += lua_typename(luastate,lua_type(luastate,i)); |
cclOG( "[LUA-print] %s" ,t.c_str()); |
创建与初始化:
代码虽然很简短,但是函数调用很多。这里先笔记下最上层的函数调用,底层的函数实现分别笔记。
ccluaStack *ccluaStack::create( voID ) |
ccluaStack *stack = new ccluaStack(); |
//将一个已有的lua运行环境附到一个新的LuaStacck上。 |
ccluaStack *ccluaStack::attach(lua_State *L) |
ccluaStack *stack = new ccluaStack(); |
stack->initWithLuaState(L); |
bool ccluaStack::init( voID ) |
m_state = lua_open(); //新建一个lua环境 |
luaL_openlibs(m_state); //将lua标准库注册到lua环境中 |
tolua_Cocos2d_open(m_state); //将cocos2dx的函数注册到lua环境中,后续笔记 |
// Register our version of the global "print" function |
const luaL_reg global_functions [] = { |
luaL_register(m_state, "_G" ,global_functions); //将自定义的print函数注册到全局table中,后续笔记 |
tolua_CocoStudio_open(m_state); //将cocosstudio的函数注册到lua环境中,后续笔记 |
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) |
ccluaObjcBrIDge::luaopen_luaoc(m_state); |
//将剩余的一些函数和变量注册到lua环境中,后续笔记 |
register_all_cocos2dx_manual(m_state); |
register_all_cocos2dx_extension_manual(m_state); |
register_all_cocos2dx_studio_manual(m_state); |
addLuaLoader(cocos2dx_lua_loader); |
//将一个已有的lua运行环境附到本LuaStack上,直接赋值即可。 |
bool ccluaStack::initWithLuaState(lua_State *L) |
修改变量package[“path”]:
将新的lua文件路径添加到Lua保存的路径中。参考网址如下:【http://cstriker1407.info/blog/lua-basic-notes-stack-variable-exchange/】
voID ccluaStack::addSearchPath( const char * path) |
lua_getglobal(m_state, "package" ); /* L: package */ |
lua_getfIEld(m_state,-1, "path" ); /* get package.path,L: package path */ |
const char * cur_path = lua_tostring(m_state,-1); |
lua_pushfstring(m_state, "%s;%s/?.lua" ,cur_path,path); /* L: package path newpath */ |
lua_setfIEld(m_state,-3, "path" ); /* package.path = newpath,L: package path */ |
lua_pop(m_state,2); /* L: - */ |
addLuaLoader:
将自定义的loader方法添加到Lua环境中。
voID ccluaStack::addLuaLoader(lua_CFunction func) |
// stack content after the invoking of the function |
lua_getglobal(m_state, "loaders" ); /* L: package,loaders */ |
// insert loader into index 2 |
lua_pushcfunction(m_state,func); /* L: package,loaders,func */ |
for ( int i = lua_objlen(m_state,-2) + 1; i > 2; --i) |
lua_rawgeti(m_state,-2,i - 1); /* L: package,func,function */ |
// we call lua_rawgeti,so the loader table Now is at -3 |
lua_rawseti(m_state,i); /* L: package,func */ |
lua_rawseti(m_state,2); /* L: package,loaders */ |
// set loaders into package |
lua_setfIEld(m_state, "loaders" ); /* L: package */ |
在Lua中删掉与某个Object有关的注册信息:
voID ccluaStack::removeScriptObjectByCCObject(CCObject* pObj) |
toluafix_remove_ccobject_by_refID(m_state,pObj->m_nLuaID); |
voID ccluaStack::removeScriptHandler( int nHandler) |
toluafix_remove_function_by_refID(m_state,nHandler); |
在C中调用Lua脚本:
参考网址如下:【 http://cstriker1407.info/blog/lua-basic-notes-c-call-lua/】
int ccluaStack::executeString( const char *codes) |
luaL_loadstring(m_state,codes); |
return executeFunction(0); //以0个入参执行该脚本。 |
int ccluaStack::executeScriptfile( const char * filename) |
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
std::string code( "require \"" ); |
return executeString(code.c_str()); |
std::string fullPath = CCfileUtils::sharedfileUtils()->fullPathForfilename(filename); |
int nRet = luaL_dofile(m_state,fullPath.c_str()); |
//通过对m_callFromLua的判断,来确认lua脚本是正常执行完毕的。 |
CC_ASSERT(m_callFromLua >= 0); |
// lua_gc(m_state,LUA_GCColLECT,0); |
{ //如果lua脚本文件有错误,这里把错误放到栈顶,这里打印出来。 |
cclOG( "[LUA ERROR] %s" ,lua_tostring(m_state,-1)); |
lua_pop(m_state,1); //d出栈顶的错误信息,保证栈恢复到以前。 |
int ccluaStack::executeGlobalFunction( const char * functionname) |
//首先在Lua环境中找到该函数,如果找到了,那么该函数会放到栈顶 |
lua_getglobal(m_state,functionname); /* query function by name,stack: function */ |
if (!lua_isfunction(m_state,-1)) |
{ //如果栈顶不是函数,说明没有找到,直接日志,清理栈,返回。 |
cclOG( "[LUA ERROR] name '%s' does not represent a Lua function" ,functionname); |
return executeFunction(0); |
//执行函数,默认此时栈已经OK,即函数被先压栈,参数以正序压栈, |
int ccluaStack::executeFunction( int numArgs) |
int functionIndex = -(numArgs + 1); |
if (!lua_isfunction(m_state,functionIndex)) //检查该位置是否是函数 |
cclOG( "value at stack [%d] is not function" ,functionIndex); |
lua_pop(m_state,numArgs + 1); // remove function and arguments |
//在Lua环境中找到函数__G__TRACKBACK__ |
lua_getglobal(m_state, "__G__TRACKBACK__" ); /* L: ... func arg1 arg2 ... G */ |
if (!lua_isfunction(m_state,-1)) |
{ //如果没有找到__G__TRACKBACK__,那么就把栈顶清理掉 |
lua_pop(m_state,1); /* L: ... func arg1 arg2 ... */ |
{ //找到了,就把__G__TRACKBACK__向后放,放到func后面 |
lua_insert(m_state,functionIndex - 1); /* L: ... G func arg1 arg2 ... */ |
traceback = functionIndex - 1; |
//调用lua_pcall,注意这里设置了1个返回值,而且设置了错误处理函数索引traceback |
error = lua_pcall(m_state,numArgs,1,traceback); /* L: ... [G] ret */ |
//如果有错误,那么根据是否有traceback函数来清理栈 |
cclOG( "[LUA ERROR] %s" ,- 1)); /* L: ... error */ |
lua_pop(m_state,1); // remove error message from stack |
else /* L: ... G error */ |
lua_pop(m_state,2); // remove __G__TRACKBACK__ and error message from stack |
if (lua_isnumber(m_state,-1)) |
ret = lua_tointeger(m_state,-1); |
else if (lua_isboolean(m_state,-1)) |
ret = lua_toboolean(m_state,-1); |
// remove return value from stack |
lua_pop(m_state,1); /* L: ... [G] */ |
//如果有错误处理函数,在d一次栈。使栈回复原样。 |
lua_pop(m_state,1); // remove __G__TRACKBACK__ from stack /* L: ... */ |
int ccluaStack::executeFunctionByHandler( int nHandler, int numArgs) |
if (pushFunctionByHandler(nHandler)) /* L: ... arg1 arg2 ... func */ |
//找到之后,把该函数在栈中的位置调到入参下面,以便符合函数执行的要求 |
lua_insert(m_state,-(numArgs + 1)); /* L: ... func arg1 arg2 ... */ |
ret = executeFunction(numArgs); |
bool ccluaStack::handleAssert( const char *msg) |
if (m_callFromLua == 0) return false ; |
lua_pushfstring(m_state, "ASSERT Failed ON LUA EXECUTE: %s" ,msg ? msg : "unkNown" ); |
int ccluaStack::reallocateScriptHandler( int nHandler) |
LUA_FUNCTION nNewHandle = -1; |
if (pushFunctionByHandler(nHandler)) |
nNewHandle = toluafix_ref_function(m_state,lua_gettop(m_state),0); |
toluafix_get_function_by_refID(m_state,nNewHandle); |
if (!lua_isfunction(m_state,-1)) |
//和executeFunction类似,不过这里的Lua函数会返回多个值。这里用pResultArray来保存返回值。 |
int ccluaStack::executeFunctionReturnArray( int nHandler, int nNumArgs, int nNummResults,CCArray* pResultArray) |
if (NulL == pResultArray) |
if (pushFunctionByHandler(nHandler)) /* L: ... arg1 arg2 ... func */ |
lua_insert(m_state,-(nNumArgs + 1)); /* L: ... func arg1 arg2 ... */ |
int functionIndex = -(nNumArgs + 1); |
if (!lua_isfunction(m_state,functionIndex)) |
cclOG( "value at stack [%d] is not function" ,functionIndex); |
lua_pop(m_state,nNumArgs + 1); // remove function and arguments |
lua_getglobal(m_state, "__G__TRACKBACK__" ); /* L: ... func arg1 arg2 ... G */ |
if (!lua_isfunction(m_state,-1)) |
lua_pop(m_state,1); /* L: ... func arg1 arg2 ... */ |
lua_insert(m_state,functionIndex - 1); /* L: ... G func arg1 arg2 ... */ |
traceback = functionIndex - 1; |
//执行函数调用,这里设置了需要返回nNummResults个返回值 |
error = lua_pcall(m_state,nNumArgs,nNummResults,traceback); /* L: ... [G] ret1 ret2 ... retResults*/ |
cclOG( "[LUA ERROR] %s" ,- 1)); /* L: ... error */ |
lua_pop(m_state,1); // remove error message from stack |
else /* L: ... G error */ |
lua_pop(m_state,2); // remove __G__TRACKBACK__ and error message from stack |
// get return value,don't pass LUA_MulTRET to numResults, |
if (nNummResults <= 0) return 0; //执行完毕,查询栈获取返回值,并吧返回值加到pResultArray中。 |
for ( int i = 0 ; i < nNummResults; i++) { if (lua_type(m_state,-1) == LUA_TBOolEAN) { bool value = lua_toboolean(m_state,-1); pResultArray->addobject(CCBool::create(value)) ; |
} else if (lua_type(m_state,-1) == LUA_TNUMBER) { |
double value = lua_tonumber(m_state,-1); |
pResultArray->addobject(CCDouble::create(value)); |
} else if (lua_type(m_state,-1) == LUA_TSTRING) { |
const char * value = lua_tostring(m_state,-1); |
pResultArray->addobject(CCString::create(value)); |
pResultArray->addobject( static_cast <ccobject*>(tolua_tousertype(m_state,NulL))); |
// remove return value from stack |
lua_pop(m_state,1); /* L: ... [G] ret1 ret2 ... ret*/ |
lua_pop(m_state,1); // remove __G__TRACKBACK__ from stack /* L: ... */ |
其中,关于【 __G__TRACKBACK__】,可以查看一下Hellolua工程中的hello.lua文件,有部分内容如下:
- - for ccluaEngine traceback |
function __G__TRACKBACK__(msg) |
cclog( "----------------------------------------" ) |
cclog( "LUA ERROR: " .. tostring(msg) .. "\n" ) |
cclog( "----------------------------------------" ) |
基本类型压栈的处理:
voID ccluaStack::clean( voID ) |
voID ccluaStack::pushInt( int intValue) |
lua_pushinteger(m_state,intValue); |
voID ccluaStack::pushfloat( float floatValue) |
lua_pushnumber(m_state,floatValue); |
voID ccluaStack::pushBoolean( bool boolValue) |
lua_pushboolean(m_state,boolValue); |
voID ccluaStack::pushString( const char * stringValue) |
lua_pushstring(m_state,stringValue); |
voID ccluaStack::pushString( const char * stringValue, int length) |
lua_pushlstring(m_state,stringValue,length); |
voID ccluaStack::pushNil( voID ) |
复杂类型压栈的处理:
view source
voID ccluaStack::pushCCObject(CCObject* objectValue, const char * typename) |
toluafix_pushusertype_ccobject(m_state,objectValue->m_uID,&objectValue->m_nLuaID,objectValue,typename); |
//吧ccluaValue压入堆栈,这里根据value的类型进行不同的 *** 作。 |
voID ccluaStack::pushccluaValue( const ccluaValue& value) |
const ccluaValueType type = value.getType(); |
if (type == ccluaValueTypeInt) |
return pushInt(value.intValue()); |
else if (type == ccluaValueTypefloat) |
return pushfloat(value.floatValue()); |
else if (type == ccluaValueTypeBoolean) |
return pushBoolean(value.booleanValue()); |
else if (type == ccluaValueTypestring) |
return pushString(value.stringValue().c_str()); |
else if (type == ccluaValueTypeDict) |
pushccluaValueDict(value.dictValue()); |
else if (type == ccluaValueTypeArray) |
pushccluaValueArray(value.arrayValue()); |
else if (type == ccluaValueTypeCCObject) |
pushCCObject(value.ccobjectValue(),value.getCCObjectTypename().c_str()); |
voID ccluaStack::pushccluaValueDict( const ccluaValueDict& dict) |
lua_newtable(m_state); /* L: table */ |
for (ccluaValueDictIterator it = dict.begin(); it != dict.end(); ++it) |
lua_pushstring(m_state,it->first.c_str()); /* L: table key */ |
pushccluaValue(it->second); /* L: table key value */ |
lua_rawset(m_state,-3); /* table.key = value,L: table */ |
voID ccluaStack::pushccluaValueArray( const ccluaValueArray& array) |
lua_newtable(m_state); /* L: table */ |
for (ccluaValueArrayIterator it = array.begin(); it != array.end(); ++it) |
pushccluaValue(*it); /* L: table value */ |
lua_rawseti(m_state,index); /* table[index] = value,L: table */ |
//把一个函数压入堆栈,这里由于函数已经注册到了Lua环境中,这里只要把它放到栈顶即可 |
bool ccluaStack::pushFunctionByHandler( int nHandler) |
toluafix_get_function_by_refID(m_state,nHandler); /* L: ... func */ |
if (!lua_isfunction(m_state,-1)) |
cclOG( "[LUA ERROR] function refID '%d' does not reference a Lua function" ,nHandler); |
总结
以上是内存溢出为你收集整理的cocos2dx-Lua学习笔记:CCLuaStack全部内容,希望文章能够帮你解决cocos2dx-Lua学习笔记:CCLuaStack所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
评论列表(0条)