加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

cocos2dx与lua

发布时间:2020-12-14 21:35:36 所属栏目:百科 来源:网络整理
导读:闲来无事,搞了搞cocos2dx的lua脚本,话说lua这东西几年前学过一段时间,也自己开发过c++接口,做过一些小东西,不过时间久远,记忆模糊。捡起来还是费了点功夫,下面就是我的一些体会。 cocos2dx使用的是tolua++来制作的lua接口,tolua++文档不多,网上的一
闲来无事,搞了搞cocos2dx的lua脚本,话说lua这东西几年前学过一段时间,也自己开发过c++接口,做过一些小东西,不过时间久远,记忆模糊。捡起来还是费了点功夫,下面就是我的一些体会。 cocos2dx使用的是tolua++来制作的lua接口,tolua++文档不多,网上的一些文章也是答非所问,所以自己看代码是最佳学习途径。 cocos2dx操作lua的类是CCLuaEngine,其中实现了加载与实行lua脚本,以及操作lua stack。 LuaCocos2d.cpp很主要,文件的开头注释也说明其是由tolua++自动生成的,我们想在lua中操作自己定义的类就是通过修改此文件实现的,两个重要函数是void tolua_reg_types (lua_State* tolua_S)与int tolua_Cocos2d_open (lua_State* tolua_S),前者是注册自定义类型,后者是定义其接口,调用关系是tolua_Cocos2d_open调用tolua_reg_types,而tolua_Cocos2d_open是在CCLuaEngine的init中调用的。 假设我要向lua注册新类,那么首先我要在tolua_reg_types中添加一行注册代码,然后在tolua_Cocos2d_open添加其接口说明,我将这两个步骤定义成两个函数,单独在一个文件中实现,文件名为cwLuaReg.cpp,内容为: #include "cwLuaReg.h" #include "cwGameObject.h" #include "cwCollisionObject.h" #include "cwGravityObject.h" #ifdef __cplusplus static int tolua_collect_cwGameObject(lua_State* tolua_S) { cwGameObject* self = (cwGameObject*) tolua_tousertype(tolua_S,1,0); delete self; return 0; } static int tolua_collect_cwGravityObject(lua_State* tolua_S) { cwGravityObject* self = (cwGravityObject*) tolua_tousertype(tolua_S,0); delete self; return 0; } #ifndef TOLUA_DISABLE_tolua_cw_GameObject_create00 static int tolua_cw_GameObject_create00(lua_State* tolua_S) { tolua_Error tolua_err; if(!tolua_isusertable(tolua_S,"cwGameObject",&tolua_err) || !tolua_isnoobj(tolua_S,2,&tolua_err)) goto tolua_lerror; else { { cwGameObject* tolua_ret = (cwGameObject*) cwGameObject::create(); int nID = (tolua_ret) ? (int)tolua_ret->m_uID : -1; int* pLuaID = (tolua_ret) ? &tolua_ret->m_nLuaID : NULL; toluafix_pushusertype_ccobject(tolua_S,nID,pLuaID,(void*)tolua_ret,"cwGameObject"); } } return 1; tolua_lerror: return 0; } #endif //#ifndef TOLUA_DISABLE #ifndef TOLUA_DISABLE_tolua_cw_GameObject_getSpeed00 static int tolua_cw_GameObject_getSpeed00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (!tolua_isusertype(tolua_S,&tolua_err)) goto tolua_lerror; else #endif { cwGameObject* self = (cwGameObject*) tolua_tousertype(tolua_S,0); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'speed'",NULL); #endif { float tolua_ret = (float) self->speed(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'speed'.",&tolua_err); return 0; #endif } #endif #ifndef TOLUA_DISABLE_tolua_cw_GameObject_setSpeed00 static int tolua_cw_GameObject_setSpeed00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (!tolua_isusertype(tolua_S,&tolua_err) || !tolua_isnumber(tolua_S,3,0); float speed = ((float) tolua_tonumber(tolua_S,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'setSpeed'",NULL); #endif { self->setSpeed(speed); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'setSpeed'.",&tolua_err); return 0; #endif } #endif #ifndef TOLUA_DISABLE_tolua_cw_GameObject_getMoveDir00 static int tolua_cw_GameObject_getMoveDir00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (!tolua_isusertype(tolua_S,"invalid 'self' in function 'getMoveDir'",NULL); #endif cwVector2D& dir = self->moveDir(); tolua_pushnumber(tolua_S,(lua_Number)dir.x); tolua_pushnumber(tolua_S,(lua_Number)dir.y); } return 2; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'getMoveDir'.",&tolua_err); return 0; #endif } #endif #ifndef TOLUA_DISABLE_tolua_cw_GameObject_setMoveDir00 static int tolua_cw_GameObject_setMoveDir00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (!tolua_isusertype(tolua_S,4,0); float dirX = ((float) tolua_tonumber(tolua_S,0)); float dirY = ((float) tolua_tonumber(tolua_S,"invalid 'self' in function 'setMoveDir'",NULL); #endif self->setMoveDir(dirX,dirY); } return 0; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,&tolua_err); return 0; #endif } #endif #endif TOLUA_API int tolua_cwLua_reg_types(lua_State* tolua_S) { //add by sunny tolua_usertype(tolua_S,"cwGameObject"); tolua_usertype(tolua_S,"cwGravityObject"); //end sunny return 1; } TOLUA_API int tolua_cwLua_reg(lua_State* tolua_S) { #ifdef __cplusplus tolua_cclass(tolua_S,"CCSprite",tolua_collect_cwGameObject); #else tolua_cclass(tolua_S,NULL); #endif tolua_beginmodule(tolua_S,"cwGameObject"); tolua_function(tolua_S,"create",tolua_cw_GameObject_create00); tolua_function(tolua_S,"speed",tolua_cw_GameObject_getSpeed00); tolua_function(tolua_S,"setSpeed",tolua_cw_GameObject_setSpeed00); tolua_function(tolua_S,"moveDir",tolua_cw_GameObject_getMoveDir00); tolua_function(tolua_S,"setMoveDir",tolua_cw_GameObject_setMoveDir00); tolua_endmodule(tolua_S); #ifdef __cplusplus tolua_cclass(tolua_S,"cwGravityObject",tolua_collect_cwGravityObject); #else tolua_cclass(tolua_S,"cwGravityObject"); tolua_endmodule(tolua_S); return 1; } 将tolua_cwLua_reg_types和tolua_cwLua_reg分别加到LuaCocos2d.cpp对应函数末尾,这样两个类cwGameObject与cwGravityObject就可以在lua中使用了。 做到这还不能达到我的期望,原因是cocos2d的lua工程里,在AppDelegate::applicationDidFinishLaun ching函数中只是加载并执行了hello.lua脚本文件,然后一切就都交给lua了,而我只是想使用lua实现一些AI方面的功能,即cwGameObject在需要执行AI时,调用lua中的一个函数。所以我需要的是一个可以调用lua函数的功能,查看了一下CCLuaEngine类,貌似没有我想要的,只能自己添了个函数: virtual int executeGlobalFunction(const char* functionName,float dt,CCObject* pObject,const char* typeName); functionName:被调lua函数名;dt:帧时间间隔;pObject:调用lua的对象;typeName:pObject对象类型 实现如下: int CCLuaEngine::executeGlobalFunction(const char* functionName,const char* typeName) { lua_getglobal(m_state,functionName); if (!lua_isfunction(m_state,-1)) { CCLOG("[LUA ERROR] name '%s' does not represent a Lua function",functionName); lua_pop(m_state,1); return 0; } pushFloat(dt); pushCCObject(pObject,typeName); int error = lua_pcall(m_state,0); if (error) { CCLOG("[LUA ERROR] %s",lua_tostring(m_state,- 1)); lua_pop(m_state,1); // clean error message return 0; } // get return value if (!lua_isnumber(m_state,-1)) { lua_pop(m_state,1); return 0; } int ret = lua_tointeger(m_state,-1); lua_pop(m_state,1); return ret; } 基本上是照着其他函数扒下来的,不同之处就是加了两个push。 函数写的比较死,可以写一个接受可变参数的函数,做的通用些。 假设我要在cwGameObject的upadte函数中调用“do_obj_update”lua函数,写法如下: void cwGameObject::update(float dt) { CCLuaEngine::defaultEngine()->executeGlobalFunction("do_obj_update",dt,this,"cwGameObject"); } 这样在创建cwGameObject时scheduleUpdate一下就可以了。 lua脚本: -- for CCLuaEngine traceback function __G__TRACKBACK__(msg) print("----------------------------------------") print("LUA ERROR: " .. tostring(msg) .. "n") print(debug.traceback()) print("----------------------------------------") end winSize = CCDirector:sharedDirector():getWinSize() -- avoid memory leak collectgarbage("setpause",100) collectgarbage("setstepmul",5000) function do_obj_update(dt,obj) local x,y = obj:getPosition() local vx,vy = obj:moveDir() x = x + vx*dt*obj:speed() y = y + vy*dt*obj:speed() if x < 0 then x = 0 obj:setMoveDir(-vx,vy) end if x > winSize.width then x = winSize.width obj:setMoveDir(-vx,vy) end if y < 0 then y = 0 obj:setMoveDir(vx,-vy) end if y > winSize.height then y = winSize.height obj:setMoveDir(vx,-vy) end obj:setPosition(x,y) end print("test.lua loaded.") 脚本很简单,do_obj_update函数只是做了一些边框判断。 别忘了修改AppDelegate::applicationDidFinishLaun ching中加载的脚本文件名~~ cocos2dx版本:cocos2d-2.0-x-2.0.3

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读