在lua中我们这么注册touch事件
local listenner = cc.EventListenerTouchOneByOne:create()
listenner:registerScriptHandler(function(touch, event)
return true;
end, cc.Handler.EVENT_TOUCH_BEGAN)
在c++里面
typedef std::function<bool(Touch*, Event*)> ccTouchBeganCallback;
ccTouchBeganCallback onTouchBegan;
auto lis = EventListenerTouchOneByOne::create();
lis->onTouchBegan = CC_CALLBACK_2(TestLayer::touchBegan, this);
很明显onTouchBegin是一个std::function,如果在c++中,如果我们的参数是一个function,那么生成的lua binding代码中会有这么一段逻辑:
std::function<void ()> arg0;
do {
// Lambda binding for lua is not supported.
assert(false);
} while(0)
;
很明显,这里主动报错了,注释中也说明了,function在lua中是不支持的
void scheduleOnce(const std::function<void(float)>& callback, float delay, const std::string &key);
static EventListenerCustom* create(const std::string& eventName, const std::function<void(EventCustom*)>& callback);
EventCustom
在lua中创建自定义事件:
local lis = cc.EventListenerCustom:create("APP_EVENT", function (){
log("EVENT")
});
cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(lis, 1)
cc.EventListenerCustom:create对应的c++ lua binding代码:
const std::string eventName = ((const std::string) tolua_tocppstring(tolua_S,2,0));
LUA_FUNCTION handler = toluafix_ref_function(tolua_S,3,0);
cocos2d::EventListenerCustom* tolua_ret = LuaEventListenerCustom::create(eventName);
// 你会发现最终其实它也是到了ScriptHandlerMgr.addObjectHandler,会将lua function存储在map表
ScriptHandlerMgr::getInstance()->addObjectHandler((void*)tolua_ret, handler, ScriptHandlerMgr::HandlerType::EVENT_CUSTIOM);
在tolua工具模板代码中并没有出现以上的c++片段,那么就是后期人为修正的一段逻辑
lua中触发
local event = cc.EventCustom:new("APP_EVENT")
event.data="12";
cc.Director:getInstance():getEventDispatcher():dispatchEvent(event)
void EventDispatcher::dispatchEvent(Event* event){
auto iter = _listenerMap.find(listenerID);
if (iter != _listenerMap.end())
{
auto listeners = iter->second;
auto onEvent = [&event](EventListener* listener) -> bool{
event->setCurrentTarget(listener->getAssociatedNode());
listener->_onEvent(event); // 响应触发事件,对于custom
return event->isStopped();
};
(this->*pfnDispatchEventToListeners)(listeners, onEvent);
}
}
bool EventListenerCustom::init(const ListenerID& listenerId, const std::function<void(EventCustom*)>& callback)
{
bool ret = false;
_onCustomEvent = callback;
auto listener = [this](Event* event){
if (_onCustomEvent != nullptr)
{
// 所以事件会派发到这里,lambda套娃,真实的函数实体在callback参数
_onCustomEvent(static_cast<EventCustom*>(event));
}
};
// 第三个参数就是一个lambda,对应的是listener->_onEvent
if (EventListener::init(EventListener::Type::CUSTOM, listenerId, listener))
{
ret = true;
}
return ret;
}
// lua_cocos2dx_manual.cpp
EventListenerCustom* LuaEventListenerCustom::create(const std::string& eventName)
{
EventListenerCustom* eventCustom = new (std::nothrow) EventListenerCustom();
if (nullptr == eventCustom)
return nullptr;
// callback参数
if ( eventCustom->init(eventName, [=](EventCustom* event){
// 最终是到达了这里
BasicScriptData data((void*)eventCustom,(void*)event);
LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::EVENT_CUSTIOM, (void*)&data );
}))
{
eventCustom->autorelease();
}
else
{
CC_SAFE_DELETE(eventCustom);
}
return eventCustom;
}
// 最后完成到lua层的调用,里面会有对参数的转换
int LuaEngine::handleEvenCustom(void* data){
// ↓ 绑定的数据
EventCustom* eventCustom = static_cast<EventCustom*>(basicData->value);
// 处理要传递到lua层的参数
lua_State* L = _stack->getLuaState();
toluafix_pushusertype_ccobject(L, eventCustom->_ID, &(eventCustom->_luaID), (void*)(eventCustom),"cc.EventCustom");
int ret = _stack->executeFunctionByHandler(handler, 1);
_stack->clean();
}
TOLUA_API int toluafix_pushusertype_ccobject(lua_State* L,
int refid,
int* p_refid,
void* ptr,
const char* type)
{
tolua_pushusertype_and_addtoroot(L, vPtr, vType);
}
custrom 数据怎么传递
vector<EditorDragInfo> files;
for (int i = 0;i < data->urls().size();i++)
{
QString file = data->urls().at(i).toLocalFile();
files.push_back(file.toStdString());
}
EventCustom eventCustom(EditorDragInfo::getEventName());
eventCustom.setUserData(&files);
auto dispatcher = cocos2d::Director::getInstance()->getEventDispatcher();
dispatcher->dispatchEvent(&eventCustom);
local lis = cc.EventListenerCustom:create("drag-event", function(event)
log("event drag file")
log(event:getUserData())
end);
c++层处理button传递参数的处理
LUA_FUNCTION handler = ( toluafix_ref_function(L,2,0));
self->addTouchEventListener([=](cocos2d::Ref* ref,Widget::TouchEventType eventType){
handleUIEvent(handler, ref, (int)eventType);
});
static int handleUIEvent(int handler, cocos2d::Ref* sender, int eventType)
{
LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
stack->pushObject(sender, "cc.Ref");
stack->pushInt(eventType);
stack->executeFunctionByHandler(handler, 2);
stack->clean();
return 0;
}
保存lua回调函数的逻辑分析
先看下_mapObjectHandlers的数据结构
enum class HandlerType: int
{
}
typedef int Handler;
typedef std::pair<HandlerType, Handler> HandlerPair;
typedef std::vector<HandlerPair> VecHandlerPairs;
typedef std::map<void*,VecHandlerPairs> MapObjectHandlers;
MapObjectHandlers _mapObjectHandlers;
合并一下类型看的更加清楚
std::map<
void*, // first
std::vector<
std::pair<enum int,int>
>
>
json格式举例:
{
"0x1234": [
{"EVENT_TOUCH_BEGAN": "lua handler"}
]
}
具体的代码逻辑分析:
int ScriptHandlerMgr::getObjectHandler(void* object,ScriptHandlerMgr::HandlerType handlerType)
{
if (nullptr == object || _mapObjectHandlers.empty() )
return 0;
auto iter = _mapObjectHandlers.find(object);// 指针是key
if (_mapObjectHandlers.end() != iter)
for (auto &handlerPair : iter->second) // 遍历vector< pair<int, int> >
if (handlerPair.first == handlerType)
return handlerPair.second;// 其实这里找到的是第一个
return 0;
}
ScriptHandlerMgr::HandlerType ScriptHandlerMgr::addCustomHandler(void* object, int handler)
{
assert(nullptr != object);
auto iter = _mapObjectHandlers.find(object);
VecHandlerPairs vecHandlers;
vecHandlers.clear();
HandlerType handlerType = HandlerType::EVENT_CUSTOM_BEGAN;
if (_mapObjectHandlers.end() != iter)// 找到object
{
vecHandlers = iter->second;// vector< pair<int, int> >
if (!vecHandlers.empty())
// ↓找到末尾的 enum int
handlerType = static_cast<HandlerType>((int)vecHandlers.back().first + 1);
}
// EVENT_CUSTOM_BEGAN = 10000,
// EVENT_CUSTOM_ENDED = 11000,
// 因为是EVENT_CUSTOM_BEGAN开头,判断是不是到达了EVENT_CUSTOM_ENDED
assert(handlerType <= HandlerType::EVENT_CUSTOM_ENDED);
// ↓ 此时已经被递增1了
HandlerPair eventHanler = std::make_pair(handlerType, handler);
vecHandlers.push_back(eventHanler);
_mapObjectHandlers[object] = vecHandlers;
// 不会重复
return handlerType;
}
void ScriptHandlerMgr::addObjectHandler(void* object,int handler,ScriptHandlerMgr::HandlerType handlerType)
{
if (nullptr == object)
return;
//may be not need
removeObjectHandler(object,handlerType);
// 移除重复的type,保证了接下来只有一个
// 这样也保证了get正常,逻辑有点危险
auto iter = _mapObjectHandlers.find(object);
VecHandlerPairs vecHandlers;
vecHandlers.clear();
if (_mapObjectHandlers.end() != iter)
vecHandlers = iter->second;
HandlerPair eventHanler = std::make_pair(handlerType, handler);
vecHandlers.push_back(eventHanler);
_mapObjectHandlers[object] = vecHandlers;
}
仔细分析过后:CUSTOM类型会递增,其他的类型不会重复
{
"0x1234": [
{"EVENT_TOUCH_BEGAN": "lua handler"},
{"EVENT_CUSTOM_BEGAN": "lua handler"},
{"EVENT_CUSTOM_BEGAN + 1": "lua handler"}
]
}