cocos2d-x 3.3 lua 相关修改
在 从 quick 转向 cocos2d-x 3.3 lua 中,我提到会将转换过程中积累的经验进行分享。这是其中一篇。要查看更多,请点击:查看所有 quick 移植到 cocos2d-x lua 的文章 。
- 2015-02-26更新: 修正解决方案。
cocos2d-x 3.3 的 lua 项目在运行时,会出现一些不符合人类习惯的问题。下面是我碰到的以及解决方案。
1. SpriteFrameCache.addSpriteFrameWithFile 调用错误
问题描述:
SpriteFrameCache 的 addSpriteFramesWithFile 方法是支持重载的。
在 tolua 中,addSpriteFrameWithFile 也同样支持重载。从 lua_cocos2dx_auth.cpp
中的 lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile
可以看出:
:::C++
int lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile(lua_State* tolua_S)
{
int argc = 0;
cocos2d::SpriteFrameCache* cobj = nullptr;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
if (!tolua_isusertype(tolua_S,1,"cc.SpriteFrameCache",0,&tolua_err)) goto tolua_lerror;
#endif
cobj = (cocos2d::SpriteFrameCache*)tolua_tousertype(tolua_S,1,0);
#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function 'lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile'", nullptr);
return 0;
}
#endif
argc = lua_gettop(tolua_S)-1;
do{
if (argc == 2) {
std::string arg0;
ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.SpriteFrameCache:addSpriteFramesWithFile");
if (!ok) { break; }
std::string arg1;
ok &= luaval_to_std_string(tolua_S, 3,&arg1, "cc.SpriteFrameCache:addSpriteFramesWithFile");
if (!ok) { break; }
cobj->addSpriteFramesWithFile(arg0, arg1);
return 0;
}
}while(0);
ok = true;
do{
if (argc == 1) {
std::string arg0;
ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.SpriteFrameCache:addSpriteFramesWithFile");
if (!ok) { break; }
cobj->addSpriteFramesWithFile(arg0);
return 0;
}
}while(0);
ok = true;
do{
if (argc == 2) {
std::string arg0;
ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.SpriteFrameCache:addSpriteFramesWithFile");
if (!ok) { break; }
cocos2d::Texture2D* arg1;
ok &= luaval_to_object<cocos2d::Texture2D>(tolua_S, 3, "cc.Texture2D",&arg1);
if (!ok) { break; }
cobj->addSpriteFramesWithFile(arg0, arg1);
return 0;
}
}while(0);
ok = true;
CCLOG("%s has wrong number of arguments: %d, was expecting %d \n", "cc.SpriteFrameCache:addSpriteFramesWithFile",argc, 2);
return 0;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile'.",&tolua_err);
#endif
return 0;
}
但是,在 lua 里面调用 addSpriteFramesWithFile 时,如果第二个参数传递 Texture2D,就会报错。信息如下:
cocos2d: error: cc.SpriteFrameCache:addSpriteFramesWithFile argument #3 is 'cc.Texture2D'; 'string' expected.
解决方案:
不解决。
问题分析:
因为这是个误报。
从上面 lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile
的绑定代码可以看出,第二个参数是字符串的重载版本(版本1)是先调用的。当使用第二个参数是 Texture2D 的重载版本时,版本1也会被调用,但不会执行。
不过参数判断总是会执行,因此就出现了误报。
误报的输出发生在 LuaBasicConversions.cpp
的 luaval_to_native_err
函数中:
:::C++
void luaval_to_native_err(lua_State* L,const char* msg,tolua_Error* err, const char* funcName)
{
if (NULL == L || NULL == err || NULL == msg || 0 == strlen(msg))
return;
if (msg[0] == '#')
{
const char* expected = err->type;
const char* provided = tolua_typename(L,err->index);
if (msg[1]=='f')
{
int narg = err->index;
if (err->array)
CCLOG("%s\n %s argument #%d is array of '%s'; array of '%s' expected.\n",msg+2,funcName,narg,provided,expected);
else
CCLOG("%s\n %s argument #%d is '%s'; '%s' expected.\n",msg+2,funcName,narg,provided,expected);
}
else if (msg[1]=='v')
{
if (err->array)
CCLOG("%s\n %s value is array of '%s'; array of '%s' expected.\n",funcName,msg+2,provided,expected);
else
CCLOG("%s\n %s value is '%s'; '%s' expected.\n",msg+2,funcName,provided,expected);
}
}
}
终极解决方案就是取消这个方法的自动导出,改为手动导出。但本着尽量少修改 cocos2d-x 源码的初衷,知道就好,不必改动。
2. 不能载入 luac 文件
问题描述:
在载入 main.lua
文件的时候,明明已经载入成功,但却一直会收到下面的提示:
can not get file data of main.luac
如果有多个 lua 文件,那么载入每个 lua 文件都会收到这个提示,只是扩展名变成了 luac
。
解决方案:
找到 Cocos2dxLuaLoader.cpp
文件,找到其中的 cocos2dx_lua_loader
方法,将下面这段删除或注释:
:::C++
chunkName = prefix.substr(0, pos) + filename + BYTECODE_FILE_EXT;
if (utils->isFileExist(chunkName))
{
chunk = utils->getFileData(chunkName.c_str(), "rb", &chunkSize);
break;
}
注意,上面的代码是一段 if ... else 结构的一部分,因此删除或注释后,还需要做一些其它的修改才能通过编译。
2015-02-26 修正解决方案:
上面的解决方案会导致进行正式打包(使用 luac 格式)的时候无法显示界面。因此,正确的修改应该是在 main.lua
中加入这一行:
:::lua
cc.FileUtils:getInstance():setPopupNotify(false)
问题分析:
cocos2d-x 的 lua 载入代码会优先载入 luac 文件,然后再处理 lua 文件。取消载入 luac 文件即可解决这个问题。
3. print 内容净化
问题描述:
使用 lua 的 print 方法打印出来的内容,在控制台中显示如下:
cocos2d: [LUA-print] -------- require(root.pretreatent.init)
这个 cocos2d: [LUA-print]
看起来相当讨厌,要干掉它。
解决方案:
在 CCLuaStack.cpp
中找到 lua_print
方法,将其中的:
:::C++
CCLOG("[LUA-print] %s", t.c_str());
改为:
:::C++
CCLOG("%s", t.c_str());
在 CCConsole.cpp
中找到 _log
方法,将其中的:
:::C++
fprintf(stdout, "cocos2d: %s", buf);
改为:
:::C++
fprintf(stdout, "%s", buf);
4. print 中加入时间戳显示
问题描述:
以前使用 quick 的时候,每一句 print 之前,都有一个当前 print 时刻的时间戳显示。单位是从程序执行开始的秒数。
cocos2d-x 3.3 lua 版本中没有这个时间显示。
解决方案:
在 CCLuaStack.cpp
中,在全局命名空间中(namespace { 之下)加入下面的内容,定义一个全局变量和一个全局函数:
:::C++
static timeval lua_print_lasttime = {0};
std::string lua_print_gettime()
{
timeval now;
float deltatime = 0;
if(gettimeofday(&now, nullptr) != 0)
{
CCLOG("lua_print_gettime() - error in gettimeofday");
}
else
{
if (lua_print_lasttime.tv_sec)
{
deltatime = now.tv_sec - lua_print_lasttime.tv_sec + (now.tv_usec - lua_print_lasttime.tv_usec) / 1000000.0f;
}
else
{
lua_print_lasttime = now;
deltatime = 0;
}
}
std::string t("[");
char timestr[32];
memset(timestr, 0, sizeof(timestr));
sprintf(timestr, "%.4f", deltatime);
t += timestr;
t += "] ";
return t;
}
在 LuaStack::init
方法的第一行加入 gettimeofday(&lua_print_lasttime, nullptr);
,修改完毕的函数如下所示:
:::C++
bool LuaStack::init(void)
{
gettimeofday(&lua_print_lasttime, nullptr);
//.........原来的内容
_state = lua_open();
luaL_openlibs(_state);
toluafix_open(_state);
//.........原来的内容
}
修改 lua_print
方法,将其中的:
:::C++
std::string t;
改为:
:::C++
std::string t(lua_print_gettime());
- 文章ID:2194
- 原文作者:zrong
- 原文链接:https://blog.zengrong.net/post/fix-cocos2d-x-33-lua/
- 版权声明:本作品采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可,非商业转载请注明出处(原文作者,原文链接),商业转载请联系作者获得授权。