关于Cocos2d-x Lua Binding中ActionTimeline的setLastFrameCallFunc不可用问题

在使用Cocos Studio制作游戏UI等元素时,一定会使用到“动画”功能:
QQ截图20150731104206
这种“动画”反应到代码中会被作为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号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具v2<<加密后发布,原文只有博主可以看到。