离线下载
PDF版 ePub版

偶尔e网事 · 更新于 2018-11-28 11:00:43

触摸事件和优先级

飞机也登场了,子弹也可以正常发射了,但是不能动的飞机算神马回事,坑爹呢!!!

整个游戏的触摸事件处理我们把它放在GameLayer中,比较直观。

1.CCTargetedTouch

我们先看一下CCLayer的声明:

    class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate

它是从CCNode继承来的,同时也继承了3个硬件相关接口事件,分别是触摸事件,加速器事件和键盘事件。

所以我们可以直接在CCLayer中进行触摸事件的处理。

触摸事件中有两个类,CCStandradTouch,CCTargetedTouch。前者为多点触摸,后者为单点触摸,而系统默认注册前者分发事件,我们这里要进行继续重载虚函数registerWithTouchSpatcher,对单点有效。

    //init()中设置可触摸
    this->setTouchEnabled(true);
    void GameLayer::registerWithTouchDispatcher()
    {
        CCDirector *pDirector=CCDirector::sharedDirector();
        pDirector->getTouchDispatcher()->addTargetedDelegate(this,0,true);
    }

CCStandradTouch这里就不进行讨论了。

2.触摸的回调函数

    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);//一般是系统级调用,比如触摸过程中来电之类的

这里我们只要重写前两个就够了。

其中ccTouchBegan返回的是bool值。

A.如果返回true,表示当前层接收触摸事件,同时允许ccTouchMoved,ccTouchEnded和ccTouchCancelled的调用。

B.如果返回false,表示当前层不接受触摸事件,后面的ccTouchMoved等等也就不往下走了。

而ccTouchMoved就是我们进行飞机移动处理的主战场了。

    //GameLayer.cpp
    bool GameLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
    {
        return true;//表示当前层接收触摸事件处理
    }

    void GameLayer::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
    {
        if (this->planeLayer->isAlive)//isAlive是AirPlane的一个成员属性,表示飞机是否还活着
        {
            CCPoint beginPoint=pTouch->locationInView();
            beginPoint=CCDirector::sharedDirector()->convertToGL(beginPoint); //获取触摸坐标
            //juggle the area of drag
            CCRect planeRect=this->planeLayer->getChildByTag(AIRPLANE)->boundingBox();//获取飞机当前位置形状位置
            planeRect.origin.x-=15;
            planeRect.origin.y-=15;
            planeRect.size.width+=30;
            planeRect.size.height+=30;//允许稍微加大一点触摸位置,游戏实际需要
            if(CCRect::CCRectContainsPoint(planeRect,
                this->getParent()->convertTouchToNodeSpace(pTouch))==true) //判断触摸点是否在飞机范围内
            {
                CCPoint endPoint=pTouch->previousLocationInView();//获取触摸的前一个位置
                endPoint=CCDirector::sharedDirector()->convertToGL(endPoint);

                CCPoint offSet =ccpSub(beginPoint,endPoint);//获取offset
                CCPoint toPoint=ccpAdd(this->planeLayer->getChildByTag(AIRPLANE)->getPosition(),offSet); //获取真正移动位置
                this->planeLayer->MoveTo(toPoint); //移动飞机
            }
        }
    }
    //PlaneLayer.cpp
    void PlaneLayer::MoveTo(CCPoint location)
    {
        //飞机及游戏状态判断
        if(isAlive && !CCDirector::sharedDirector()->isPaused())
        {
            //进行边界判断,不可超出屏幕
            CCPoint actualPoint;
            CCSize winSize=CCDirector::sharedDirector()->getWinSize();
            CCSize planeSize=this->getChildByTag(AIRPLANE)->getContentSize();
            if (location.xwinSize.width-planeSize.width/2)
            {
                location.x=winSize.width-planeSize.width/2;
            }
            if (location.ywinSize.height-planeSize.height/2)
            {
                location.y=winSize.height-planeSize.height/2;
            }
            this->getChildByTag(AIRPLANE)->setPosition(location);
        }
    }

3.触摸优先级和触摸事件的吞噬

大家看到触摸事件的分派注册中,addTargetdDelegate第二个和第三个函参,又是什么意思呢?

A.第二个参数表示触摸事件的优先级,值越小,优先级越高,比如层1的优先级是-50,层2的优先级是-100,那么层2会先接收并处理触摸事件,然后才有机会轮到层1来接收处理。

B.第三个参数表示swallow事件,表示当前层是否吞噬掉这个触摸,即不往优先级更低的层传送。

要注意的是触摸事件的触发是根据添加的顺序依次触发的,后添加的层先捕获触摸事件,当然,这是没有设置事件优先级的情况下,若要是定义了事件的优先级,则先按照事件的优先级依次被触发,然后根据添加的顺序依次被触发。CCMenu的优先级是-128,而CCControlButton的优先级是0。

好了,这一节后,我们就可以控制飞机移动并且发射子弹了,而子弹一旦超出屏幕就会被回收,飞机也不会超出屏幕外。

效果图