2dx关于js响应layer触摸消息的bug

cocos2dx关于js响应layer触摸消息的bug

cocos2d-x 3.7


问题描述:

目前这个版本中(3.7),c++层的layer触摸消息只能通过消息的方式发送给js,不能像lua一样直接回调js注册的触摸回调接口,为了方便,我们更改一下layer类的onTouchBegan/onTouchMove...等接口,使其支持在layer的触摸响应中直接回调js接口。
具体实现见:http://www.cnblogs.com/songcf/p/4764444.html


ok,在这之后就会发现ScriptingCore中有一个触摸响应判断的bug:
只要c++对js的ontouchbegan函数调用成功,都会被视为当前layer捕捉到了该触摸(即return true)
如果该layer开启了吞噬触摸,那么此次touch永远被该layer捕获,不再传递下去,即使你在js层中注册的onTouchBegan是return false,也无济于事。
那么造成该bug的原因如下:

//Layer判断是否捕获该touch,取决于executeScriptTouchHandler函数调用的返回值
bool Layer::onTouchBegan(Touch *touch, Event *event)
{
#if CC_ENABLE_SCRIPT_BINDING
    if (kScriptTypeNone != _scriptType)
    {
        return executeScriptTouchHandler(EventTouch::EventCode::BEGAN, touch, event) == 0 ? false : true;
    }
#endif
    CC_UNUSED_PARAM(event);
    CCASSERT(false, "Layer#ccTouchBegan override me");
    return true;
}

//再来看看executeScriptTouchHandler的返回值,取决于ScriptingCore::sendEvent
int Layer::executeScriptTouchHandler(EventTouch::EventCode eventType, Touch* touch, Event* event)
{
#if CC_ENABLE_SCRIPT_BINDING
    if (kScriptTypeNone != _scriptType)
    {
        TouchScriptData data(eventType, this, touch, event);
        ScriptEvent scriptEvent(kTouchEvent, &data);
        return ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);
    }
#endif
    //can not reach it
    return 0;
}

//再看sendEvent中发送触摸消息的代码
//这里可以看出layer是否捕获触摸取决于handleTouchEvent的返回值
int ScriptingCore::sendEvent(ScriptEvent* evt)
{
	//......
        case kTouchEvent:
            {
                TouchScriptData* data = (TouchScriptData*)evt->data;
                return handleTouchEvent(data->nativeObject, data->actionType, data->touch, data->event);
            }
            break;
        case kTouchesEvent:
            {
                TouchesScriptData* data = (TouchesScriptData*)evt->data;
                return handleTouchesEvent(data->nativeObject, data->actionType, data->touches, data->event);
            }
            break;
	//......
}

//你可以继续往下跟进去就会知道,最终返回的值到底是什么

没错!如你所见,最后的返回值是JS_CallFunctionName是否调用成功,即这里c++调用js的onTouchBegan函数是否成功
只要调用成功,touch就会被该layer捕获!跟onTouchBegan的返回值没半毛钱关系。那么正确的返回值应该是js端onTouchBegan的返回值。

解决方案:

修改ScriptingCorehandleTouchEvent/handleTouchesEvent两个接口,让它们的返回值为js端onTouchBegan的返回值:

bool ScriptingCore::handleTouchEvent(void* nativeObj, cocos2d::EventTouch::EventCode eventCode, cocos2d::Touch* touch, cocos2d::Event* event)
{
    JS::RootedValue ret(_cx);
    if (handleTouchEvent(nativeObj, eventCode, touch, event, &ret)){
		return JS::ToBoolean(ret);
	}
	else {
		return false;
	}
}

bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::EventCode eventCode, const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
{
	JS::RootedValue ret(_cx);
	if (handleTouchesEvent(nativeObj, eventCode, touches, event, &ret)){
		return JS::ToBoolean(ret);
	}
	else {
		return false;
	}
}

其实我不太明白官方为什么在layer的触摸响应中,只用c++回调lua接口,而js使用发消息的方式(不用c++回调js接口),性能?!

原文地址:https://www.cnblogs.com/songcf/p/4765452.html