在使用Cocos Studio制作游戏UI等元素时,一定会使用到“动画”功能:
这种“动画”反应到代码中会被作为Cocos2d-x的ActionTimeline处理,而在应用过程中免不了要进行一些时间轴上的事件监测处理,其中最常用的莫过于动画结束时的侦听。
简单看下源码可以找到很明显的回调设置函数:
/** Set ActionTimeline's frame event callback function */ void setFrameEventCallFunc(std::function<void(Frame *)> listener); void clearFrameEventCallFunc(); /** Last frame callback will call when arriving last frame */ void setLastFrameCallFunc(std::function<void()> listener); void clearLastFrameCallFunc();
上面的setFrameEventCallFunc是用来配合编辑器中设置的帧事件用的,可以用来实现比如UI打开到指定位置时播放特定音效等效果,下面的setLastFrameCallFunc则是刚刚提到的更为常用的动画播放结束后的回调函数!
不过,很遗憾,在不使用原生方式开发而使用lua脚本作为主要编程语言时,发现setLastFrameCallFunc的Lua Binding代码并没有实现实际功能(最新3.7版本也是):
std::function<void ()> arg0; do { // Lambda binding for lua is not supported. assert(false); } while(0) ; if(!ok) { tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_studio_ActionTimeline_setLastFrameCallFunc'", nullptr); return 0; } cobj->setLastFrameCallFunc(arg0); lua_settop(tolua_S, 1); return 1;
binding代码中直接assert(false)了,注释说lambda binding lua不支持…
首先想到的是用setFrameEventCallFunc对付一下,于是在编辑器中timeline结尾处加入了frame event,测试发现有一点小问题:事件不能加在动画最后一帧上,而只能加载倒数第二帧上,否则事件不会触发(原因貌似是update时的计算问题,代码过多,看着头大),除了这点外,基本可以完成在lua中对动画完成事件的处理,但是依然觉得这样不太根本,还会带来UI编辑过程中不必要的工作量,于是又开始看lua_cocos2dx_coco_studio_manual.cpp中的setFrameEventCallFunc实现,感觉问题其实应该是官方忘记实现这个回调的binding了…还是手动修改一下加上吧:
首先,在lua_cocos2dx_studio_auto.cpp中注释掉关于setLastFrameCallFunc的注册调用:
tolua_function(tolua_S,"clearFrameEventCallFunc",lua_cocos2dx_studio_ActionTimeline_clearFrameEventCallFunc); //tolua_function(tolua_S,"setLastFrameCallFunc",lua_cocos2dx_studio_ActionTimeline_setLastFrameCallFunc); tolua_function(tolua_S,"getTimelines",lua_cocos2dx_studio_ActionTimeline_getTimelines);
要彻底点的话lua_cocos2dx_studio_ActionTimeline_setLastFrameCallFunc也可以整个注掉,又或者auto中都不动也是没问题的,后面manual注册时会重新覆盖这个函数的lua binding:
static int lua_cocos2dx_ActionTimeline_setLastFrameCallFunc(lua_State* L) { if (nullptr == L) return 0; int argc = 0; cocostudio::timeline::ActionTimeline* self = nullptr; #if COCOS2D_DEBUG >= 1 tolua_Error tolua_err; if (!tolua_isusertype(L, 1, "ccs.ActionTimeline", 0, &tolua_err)) goto tolua_lerror; #endif self = static_cast<cocostudio::timeline::ActionTimeline*>(tolua_tousertype(L, 1, 0)); #if COCOS2D_DEBUG >= 1 if (nullptr == self) { tolua_error(L, "invalid 'self' in function 'lua_cocos2dx_ActionTimeline_setLastFrameCallFunc'\n", NULL); return 0; } #endif argc = lua_gettop(L) - 1; if (1 == argc) { #if COCOS2D_DEBUG >= 1 if (!toluafix_isfunction(L, 2, "LUA_FUNCTION", 0, &tolua_err)) { goto tolua_lerror; } #endif LUA_FUNCTION handler = (toluafix_ref_function(L, 2, 0)); self->setLastFrameCallFunc([=]() { LuaEngine::getInstance()->getLuaStack()->executeFunctionByHandler(handler, 1); }); return 0; } luaL_error(L, "'setLastFrameCallFunc' function of ActionTimeline has wrong number of arguments: %d, was expecting %d\n", argc, 1); #if COCOS2D_DEBUG >= 1 tolua_lerror: tolua_error(L, "#ferror in function 'setFrameEventCallFunc'.", &tolua_err); #endif return 0; } static void extendActionTimeline(lua_State* L) { lua_pushstring(L, "ccs.ActionTimeline"); lua_rawget(L, LUA_REGISTRYINDEX); if (lua_istable(L,-1)) { tolua_function(L, "setFrameEventCallFunc", lua_cocos2dx_ActionTimeline_setFrameEventCallFunc); tolua_function(L, "setLastFrameCallFunc", lua_cocos2dx_ActionTimeline_setLastFrameCallFunc); } lua_pop(L, 1); }
其实,binding的实现基本就是照抄lua_cocos2dx_ActionTimeline_setFrameEventCallFunc,所以怀疑是官方忘记补上这个了…
UPDATE:
发现GitHub上已经有人为这个问题提交了PR了:https://github.com/cocos2d/cocos2d-x/pull/10655,不过3月份提的至今还没有merge。。。。
博主友情提示:
如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。
1 Response