移动设备玩家的交互基本是触摸,闲来翻看了一下cocos具体的触摸分发,主要思路就是通过ios的触摸,然后回调cocos的事件分发
1.具体目录 项目底下cocos2d/cocos/platform 这个目录下面有对应不同平台的相关代码我们主要看 /ios
//CCEAGLView-ios,这个类继承了UIView并实现了触摸代理,UIView
//是IOS的系统的相关类,想了解更多IOS的触摸机制可以百度,我能看懂的
//代码主要如下
//#pragma mark CCEAGLView - Touch Delegate
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
...
//主要代码
auto glview = cocos2d::Director::getInstance()->getOpenGLView();
glview->handleTouchesBegin(i, (intptr_t*)ids, xs, ys);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
...
//主要代码
auto glview = cocos2d::Director::getInstance()->getOpenGLView();
glview->handleTouchesMove(i, (intptr_t*)ids, xs, ys);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
...
//主要代码
auto glview = cocos2d::Director::getInstance()->getOpenGLView();
glview->handleTouchesEnd(i, (intptr_t*)ids, xs, ys);
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
...
//主要代码
auto glview = cocos2d::Director::getInstance()->getOpenGLView();
glview->handleTouchesCancel(i, (intptr_t*)ids, xs, ys);
}
//以上4个方法对应cocos里面的4个回调方法具体是怎么调用的需要继续看
2.glview->handleTouchesCancel(),从这继续
//GLView类
void GLView::handleTouchesBegin(int num, intptr_t ids[], float xs[], float ys[])
{
intptr_t id = 0;
float x = 0.0f;
float y = 0.0f;
int unusedIndex = 0;
EventTouch touchEvent;//触摸事件
for (int i = 0; i < num; ++i)
{
id = ids[i];
x = xs[i];
y = ys[i];
auto iter = g_touchIdReorderMap.find(id);
// it is a new touch
if (iter == g_touchIdReorderMap.end())
{
unusedIndex = getUnUsedIndex();
// The touches is more than MAX_TOUCHES ?
if (unusedIndex == -1) {
CCLOG("The touches is more than MAX_TOUCHES, unusedIndex = %d", unusedIndex);
continue;
}
Touch* touch = g_touches[unusedIndex] = new (std::nothrow) Touch();//触摸
touch->setTouchInfo(unusedIndex, (x - _viewPortRect.origin.x) / _scaleX,
(y - _viewPortRect.origin.y) / _scaleY);
CCLOGINFO("x = %f y = %f", touch->getLocationInView().x, touch->getLocationInView().y);
g_touchIdReorderMap.insert(std::make_pair(id, unusedIndex));
touchEvent._touches.push_back(touch);//压入
//vector中
}
}
if (touchEvent._touches.size() == 0)
{
CCLOG("touchesBegan: size = 0");
return;
}
//
touchEvent._eventCode = EventTouch::EventCode::BEGAN;
auto dispatcher = Director::getInstance()->getEventDispatcher();
dispatcher->dispatchEvent(&touchEvent);
}
3.dispatcher->dispatchEvent(&touchEvent);
//EventDispatcher类
void EventDispatcher::dispatchEvent(Event* event)
{
if (!_isEnabled)
return;
updateDirtyFlagForSceneGraph();
DispatchGuard guard(_inDispatch);
//触摸事件
if (event->getType() == Event::Type::TOUCH)
{
//看这里
dispatchTouchEvent(static_cast<EventTouch*>(event));
return;
}
auto listenerID = __getListenerID(event);
sortEventListeners(listenerID);
auto pfnDispatchEventToListeners = &EventDispatcher::dispatchEventToListeners;
if (event->getType() == Event::Type::MOUSE) {
pfnDispatchEventToListeners = &EventDispatcher::dispatchTouchEventToListeners;
}
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);
return event->isStopped();
};
(this->*pfnDispatchEventToListeners)(listeners, onEvent);
}
updateListeners(event);
}
//
void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
// If there aren't any touch listeners, return directly.
if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)
return;
bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners);
const std::vector<Touch*>& originalTouches = event->getTouches();//刚刚压入的触摸点
std::vector<Touch*> mutableTouches(originalTouches.size());
std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin());
//
// process the target handlers 1st
//
if (oneByOneListeners)
{
auto mutableTouchesIter = mutableTouches.begin();
auto touchesIter = originalTouches.begin();
for (; touchesIter != originalTouches.end(); ++touchesIter)
{
bool isSwallowed = false;
//lambda 表达式
auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break
EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l);
// Skip if the listener was removed.
if (!listener->_isRegistered)
return false;
event->setCurrentTarget(listener->_node);
bool isClaimed = false;
std::vector<Touch*>::iterator removedIter;
EventTouch::EventCode eventCode = event->getEventCode();
if (eventCode == EventTouch::EventCode::BEGAN)
{
if (listener->onTouchBegan)
{
//这里就是调用我们注册的触摸事件
isClaimed = listener->onTouchBegan(*touchesIter, event);
if (isClaimed && listener->_isRegistered)
{
listener->_claimedTouches.push_back(*touchesIter);
}
}
}
else if (listener->_claimedTouches.size() > 0
&& ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
{
isClaimed = true;
switch (eventCode)
{
case EventTouch::EventCode::MOVED:
if (listener->onTouchMoved)
{
listener->onTouchMoved(*touchesIter, event);
}
break;
case EventTouch::EventCode::ENDED:
if (listener->onTouchEnded)
{
listener->onTouchEnded(*touchesIter, event);
}
if (listener->_isRegistered)
{
listener->_claimedTouches.erase(removedIter);
}
break;
case EventTouch::EventCode::CANCELLED:
if (listener->onTouchCancelled)
{
listener->onTouchCancelled(*touchesIter, event);
}
if (listener->_isRegistered)
{
listener->_claimedTouches.erase(removedIter);
}
break;
default:
CCASSERT(false, "The eventcode is invalid.");
break;
}
}
// If the event was stopped, return directly.
if (event->isStopped())
{
updateListeners(event);
return true;
}
CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(),
"touchesIter ID should be equal to mutableTouchesIter's ID.");
if (isClaimed && listener->_isRegistered && listener->_needSwallow)
{
if (isNeedsMutableSet)
{
mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);
isSwallowed = true;
}
return true;
}
return false;
};
//lambda表达式传入这里
dispatchTouchEventToListeners(oneByOneListeners, onTouchEvent);
if (event->isStopped())
{
return;
}
if (!isSwallowed)
++mutableTouchesIter;
}
}
...
}
//到这里就是分情况去执行相应的触摸事件了
void EventDispatcher::dispatchTouchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
{
bool shouldStopPropagation = false;
auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
ssize_t i = 0;
//先执行 priority < 0,onEvent(l)就是上面lambda表达式执行了
if (fixedPriorityListeners)
{
CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");
if (!fixedPriorityListeners->empty())
{
for (; i < listeners->getGt0Index(); ++i)
{
auto l = fixedPriorityListeners->at(i);
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
}
//再执行 priority == 0,因为sceneGraphPriority事件都
//是priority = 0的
auto scene = Director::getInstance()->getRunningScene();
if (scene && sceneGraphPriorityListeners)
{
if (!shouldStopPropagation)
{
// priority == 0, scene graph priority
// first, get all enabled, unPaused and registered listeners
std::vector<EventListener*> sceneListeners;
for (auto& l : *sceneGraphPriorityListeners)
{
if (l->isEnabled() && !l->isPaused() && l->isRegistered())
{
sceneListeners.push_back(l);
}
}
// second, for all camera call all listeners
// get a copy of cameras, prevent it's been modified in linstener callback
// if camera's depth is greater, process it earler
auto cameras = scene->getCameras();
Camera* camera;
for (int j = int(cameras.size()) - 1; j >= 0; --j)
{
camera = cameras[j];
if (camera->isVisible() == false)
{
continue;
}
Camera::_visitingCamera = camera;
for (auto& l : sceneListeners)
{
if (onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
if (shouldStopPropagation)
{
break;
}
}
Camera::_visitingCamera = nullptr;
}
}
if (fixedPriorityListeners)
{
if (!shouldStopPropagation)
{
//最后 priority > 0
ssize_t size = fixedPriorityListeners->size();
for (; i < size; ++i)
{
auto l = fixedPriorityListeners->at(i);
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
}
}