首先是层CCLayer,其实CCLayer已经继承了触摸委托类了
class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate
class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate
{
public:
...
// default implements are used to call script callback if exist
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
// default implements are used to call script callback if exist
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);
virtual void registerWithTouchDispatcher(void);//注册触摸监听
virtual bool isTouchEnabled();//是否开启触摸
virtual void setTouchEnabled(bool value);//设置该层是否允许触摸
virtual void setTouchMode(ccTouchesMode mode);//设置触摸模式
virtual int getTouchMode();//获取触摸模式
/** priority of the touch events. Default is 0 */
virtual void setTouchPriority(int priority)//设置触摸优先级
virtual int getTouchPriority();//获取触摸优先级
...
protected:
bool m_bTouchEnabled;//记录是否允许触摸
...
private:
...
int m_nTouchPriority;//记录触摸优先级
ccTouchesMode m_eTouchMode;//记录触摸模式
...
};
其实要开启该层的触摸只要调用setTouchEnabled方法即可,因为里面已经帮我们实现了注册触摸事件到分发器中。
void CCLayer::setTouchEnabled(bool enabled)
{
if (m_bTouchEnabled != enabled)//判断是否需要执行下面操作
{
m_bTouchEnabled = enabled;//更新是否允许触摸
if (m_bRunning)//如果是正在运行的层
{
if (enabled)//如果是开启
{
this->registerWithTouchDispatcher();//注册触摸事件到分发器
}
else
{
// have problems?
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);//从分发器中移除,关闭触摸
}
}
}
}
void CCLayer::registerWithTouchDispatcher()
{
CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();
// Using LuaBindings
if (m_pScriptTouchHandlerEntry)//脚本相关
{
if (m_pScriptTouchHandlerEntry->isMultiTouches())
{
pDispatcher->addStandardDelegate(this, 0);
LUALOG("[LUA] Add multi-touches event handler: %d", m_pScriptTouchHandlerEntry->getHandler());
}
else
{
pDispatcher->addTargetedDelegate(this,
m_pScriptTouchHandlerEntry->getPriority(),
m_pScriptTouchHandlerEntry->getSwallowsTouches());
LUALOG("[LUA] Add touch event handler: %d", m_pScriptTouchHandlerEntry->getHandler());
}
}
else
{
if( m_eTouchMode == kCCTouchesAllAtOnce ) {//判断是否是标准触摸
pDispatcher->addStandardDelegate(this, 0);//注册到标准触摸分发器中
} else {
pDispatcher->addTargetedDelegate(this, m_nTouchPriority, true);//注册到目标触摸分发器中,默认优先级m_nTouchPriority为0
}
}
}
默认情况下层开启的是标准触摸,如果要改成目标触摸,设置该层的触摸模式即可,即调用setTouchMode方法。
当然当层被移除时要从分发器中移除触摸事件,如果有开启触摸的话:
void CCLayer::onExit()
{
CCDirector* pDirector = CCDirector::sharedDirector();
if( m_bTouchEnabled )//如果开启了触摸
{
pDirector->getTouchDispatcher()->removeDelegate(this);//移除触摸
// [lua]:don't unregister script touch handler, or the handler will be destroyed
// unregisterScriptTouchHandler();
}
// remove this layer from the delegates who concern Accelerometer Sensor
if (m_bAccelerometerEnabled)
{
pDirector->getAccelerometer()->setDelegate(NULL);
}
// remove this layer from the delegates who concern the keypad msg
if (m_bKeypadEnabled)
{
pDirector->getKeypadDispatcher()->removeDelegate(this);
}
CCNode::onExit();
}
其次是菜单的触摸操作。菜单是继承自于CCLayerRGBA,而CCLayerRGBA又继承自与CCLayer,所有菜单同样是继承了触摸委托类。
class CC_DLL CCMenu : public CCLayerRGBA
class CC_DLL CCLayerRGBA : public CCLayer, public CCRGBAProtocol
默认情况下,菜单的触摸优先级非常高,是-128,被声明在一个枚举中
enum {
//* priority used by the menu for the event handler
kCCMenuHandlerPriority = -128,//菜单默认的触摸优先级
};
菜单的触摸实现几乎跟层的一样,只不过菜单默认是开启触摸的,而层是没有开启,需要手动开启,并也已经重写触摸的4个操作方法
virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
virtual void ccTouchCancelled(CCTouch *touch, CCEvent* event);
virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
这样一来开发者就无需去处理这些触摸方法,所以在初始化菜单就已经帮我们开启了触摸,设置为目标触摸和并带有吞噬。
bool CCMenu::init()
{
return initWithArray(NULL);
}
bool CCMenu::initWithArray(CCArray* pArrayOfItems)
{
if (CCLayer::init())
{
setTouchPriority(kCCMenuHandlerPriority);//设置菜单的触摸优先级(kCCMenuHandlerPriority = -128)
setTouchMode(kCCTouchesOneByOne);//设置菜单的触摸模式为目标触摸,并带有吞噬
setTouchEnabled(true);//开启触摸
m_bEnabled = true;//记录已开启触摸
...
return true;
}
return false;
}
同样,在移除菜单也要把触摸事件从分发器中移除:
void CCMenu::onExit()
{
if (m_eState == kCCMenuStateTrackingTouch)
{
if (m_pSelectedItem)
{
m_pSelectedItem->unselected();
m_pSelectedItem = NULL;
}
m_eState = kCCMenuStateWaiting;
}
CCLayer::onExit();//调用父类的onExit,它会帮菜单将触摸事件从分发器中移除掉,取消掉触摸监听
}
所以只要理解了触摸原理,如何处理这些触摸事件简直就是很easy!