Cocos2d-x MultipleTouch & CCControllButton's confusion

来源:互联网 发布:淘宝如何申请子账号 编辑:程序博客网 时间:2024/04/29 11:23

在cocos2dx的程序设计中有时候会遇到需要多点触摸的功能,下面先介绍一下在cocos2dx中多点触摸的一般规则,然后介绍我遇到的一个有关多点触摸的情景的解决方案。


(一)使用多点触摸规则:

关于多点触摸在TestCPP中有一个例子展示,通过这个例子就可以知道多点触摸是如何使用的了。

简单说一下步骤:

①开启多点触摸

在ios文件夹中的AppController.mm文件的

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法中:

[__glView setMultipleTouchEnabled:true]; 


②注册触摸事件( StandardDelegate )

a)可以在onEnter方法中: CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);

b)也可以重写: virtual void registerWithTouchDispatcher(void); 在这个方法中:

CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this0);

而且注意要在init方法中: setTouchEnabled(true);

为什么呢?因为在init方法中,setTouchEnabled(true); 会自动回调 registerWithTouchDispatcher 方法。


③触摸事件委托方法

virtual void ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);    virtual void ccTouchesMoved(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);    virtual void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);    virtual void ccTouchesCancelled(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);


在每一个委托方法中,可以用下面的遍历方法,获取每一个触摸点的信息。
CCSetIterator iter = pTouches->begin();        for (; iter != pTouches->end(); iter++)    {        CCTouch* pTouch = (CCTouch*)(*iter);        CCPoint location = pTouch->getLocation();            }


(二)一个类似多点触摸情景解决方法

情景介绍:在layer中,需要按住某一个按键,然后在按键保持按下的时候,执行某一个事件(也是要触摸屏幕执行的),如果松开按键,那么执行这个事件结束。

A)那么我的第一个反应就是使用多点触摸,理论上是可以解决的,但是感觉判断起来有点繁琐,所有暂时放弃了这个解决方法。

B)我就想到要CCMenu item 或者 CCControllButton 这类的“按键” 实现,当按键 保持按下 的时候,那么就可以判断它的状态(isSelected),在一个定时器方法中判断按键的状态,根据这个状态值,就可以进行相应处理,恩,这样似乎简单了许多。


注意:在这个情景中其实也是多点触摸的,注意到按键按下是一个触摸点,然后在执行某一个事件,也是要触摸屏幕执行,那么又是一个触摸点。那么我们同样要开启多点触摸,这一点很重要。

然而,如果我们 在按键按下的时候执行的事件,只是需要一个触摸点,那么注册为TargetedDelegate 就可以了;如果需要多个触摸点,那么注册为 StandardDelegate。


①首先用到 CCMenuItem

在这类按键中 有两个 属性:

bool m_bSelected;bool m_bEnabled;

确定按键是否选中,和是否可用。

那么在这个情景中,我们使用 它的是否选中 这个属性,通过 virtualbool isSelected(); 方法就可以获取到这个属性的值。

在定时器方法中:

 if (item->isSelected()) {        CCLOG("selected");    }    else    {        CCLOG("unselected");    }

②然后再试一下 CCControllButton


A)首先注意CCControllButton 中的触摸优先级是 1 ,所以 layer 注册的接收触摸事件优先级 就必须 大于等于 1.

下面看看为什么CCControllButton 中的触摸优先级是 1:

CCControllButton 是继承自:CCControl 

在 CCControl 中的init 方法中:

bool CCControl::init(){    if (CCLayer::init())    {        //this->setTouchEnabled(true);        //m_bIsTouchEnabled=true;        // Initialise instance variables        m_eState=CCControlStateNormal;        setEnabled(true);        setSelected(false);        setHighlighted(false);        // Set the touch dispatcher priority by default to 1        this->setTouchPriority(1);        // Initialise the tables        m_pDispatchTable = new CCDictionary();         // Initialise the mapHandleOfControlEvents        m_mapHandleOfControlEvent.clear();                return true;    }    else    {        return false;    }}

注意到了吧:

// Set the touch dispatcher priority by default to 1

this->setTouchPriority(1);

B) CCControllButton 中检测按键是否选中的状态 是使用 isHighlighted 方法,而不是 isSelected() .很奇怪吧!奋斗

在CCMenuItem 中是用 isSelected ,那么理论上,在 CCControllButton 也是类似的。

下面分析一下问题:

我们 CCControllButton 继承CCControl ,而 CCControl 继承 CCLayerRGBA ,那么说到底,其实 CCControllButton 就是继承自 

CCLayer。

那么肯定是要在 触摸事件的回调方法中 对CCControllButton的状态进行设置的。

可以发现:

virtual void setEnabled(bool enabled);    virtual void setSelected(bool enabled);    virtual void setHighlighted(bool enabled);

居然,有一个 setHighlighted方法,这个和 setSelected 方法有什么区别呢? 两个方法所对应的属性应该都是在button选中的吧!疑问


带着疑问,继续-----

我们找到触摸事件的回调方法(只显示前两个touch began 和 moved 方法):

bool CCControlButton::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){    if (!isTouchInside(pTouch) || !isEnabled() || !isVisible() || !hasVisibleParents() )    {        return false;    }        for (CCNode *c = this->m_pParent; c != NULL; c = c->getParent())    {        if (c->isVisible() == false)        {            return false;        }    }        m_isPushed = true;    this->setHighlighted(true);    sendActionsForControlEvents(CCControlEventTouchDown);    return true;}void CCControlButton::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){        if (!isEnabled() || !isPushed() || isSelected())    {        if (isHighlighted())        {            setHighlighted(false);        }        return;    }        bool isTouchMoveInside = isTouchInside(pTouch);    if (isTouchMoveInside && !isHighlighted())    {        setHighlighted(true);        sendActionsForControlEvents(CCControlEventTouchDragEnter);    }    else if (isTouchMoveInside && isHighlighted())    {        sendActionsForControlEvents(CCControlEventTouchDragInside);    }    else if (!isTouchMoveInside && isHighlighted())    {        setHighlighted(false);                sendActionsForControlEvents(CCControlEventTouchDragExit);            }    else if (!isTouchMoveInside && !isHighlighted())    {        sendActionsForControlEvents(CCControlEventTouchDragOutside);            }}

终于有点发现了,原来,都是只用到了 setHighlighted 设置button的是否选中状态,根本就和 setSelected 没有半点关系,难怪,我们只能用 isHighlighted 方法来检测 button 的是否选中状态了。


到这里,似乎问题就结束了。但是我内心有一个深深的好奇:为什么要设多一个这样用处不是很大的 setSelected 方法呢?或者说,setHighlighted 方法抢占了 setSelected 本该有的作用呢?

我在 官方网站论坛上,发了一个帖子,欢迎大神回复指导一下:点击打开链接


其实我为他们找到了两个可能的理由:

① CCMenuItem 和 CCControllButton 这两个类是不同的两个程序员编写的,他们之间缺少交流,所以导致了这个差异。但是这个很明显对我们来说是一个潜在的坑呀!敲打


CCControllButton 提供 setSelected 是为了给我们提供一个手动设置 按键是否选中状态 的方法。但是这样的方法实际过程中,用处大吗?,大吗?敲打


好咯,大致就是这么些个内容了,关于最后的问题,欢迎大神指导。吐舌头






原创粉丝点击