cocos2d-x学习笔记(12)屏幕触摸事件(单点触摸)

常用的触摸事件一般有4个:

onTouchBegan:触摸事件开始,也就是手指按下时;

onTouchMoved:触摸移动事件,也就是手指在屏幕滑动的过程;

onTouchEnded:触摸事件结束,也就是手指松开时。

onTouchCancelled:打断触摸事件事件,一般是系统层级的消息,如手机来电话,触摸事件就会被中断。

auto listener = EventListenerTouchOneByOne::create();

      listener->onTouchBegan = [](Touch* touch, Event* event){

        Point pos = touch->getLocation();

        Point pos1 = touch->getLocation();        /* 获取单击坐标,基于3D */
        Point pos2 = touch->getLocationInView();   /* 获取单击坐标,基于2D */
        Point pos3 = Director::getInstance()->convertToGL(pos2);   /* 获取单击坐标,基于Cocos2d-x */

        log("HelloWorldScene onTouchBegan! pos1 x=%f, y=%f", pos1.x, pos1.y);
        log("HelloWorldScene onTouchBegan! pos2 x=%f, y=%f", pos2.x, pos2.y);
        log("HelloWorldScene onTouchBegan! pos3 x=%f, y=%f", pos3.x, pos3.y);
        return true;
    };

    listener->onTouchMoved = [](Touch* touch, Event* event){
        log("HelloWorldScene onTouchMoved");
    };

    listener->onTouchEnded = [=](Touch* touch, Event* event){
        log("HelloWorldScene onTouchEnded");
    };
  
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
   
获取单击屏幕时的坐标:

Point pos1 = touch->getLocation();        获取单击坐标,基于3D 

Point pos2 = touch->getLocationInView();    获取单击坐标,基于2D 

Point pos3 = Director::getInstance()->convertToGL(pos2);    获取单击坐标,基于Cocos2d-x 

第一种方式获取的是三维坐标,而Cocos2d-x开发的游戏一般都是二维的,所以这种方式比较少用。

第二种方式获取的是二维坐标,这种方式获取的坐标是以左上角为原点的,而Cocos2d-x使用的坐标是以左下角为原点的,也就是我们数学里常用的笛卡尔坐标系。

所以还要用convertToGL函数将坐标转换为笛卡尔坐标,这就是第三种方式。


触摸事件的函数回调用的也是lambda函数,然后调用addEventListenerWidthSceneGraphPriority函数注册监听事件。

_eventDispatcher是事件管理器,其实它相当于Director::getInstance()->getEventDispatcher(),是一个单例类。只不过为了方便 ,在Node类里使用了一个_eventDispatcher变量保存了这个单例类的引用。

addEventListenerWidthSceneGraphPriority函数的两个参数作用:

EventListener* listener:事件监听对象,当触摸事件发生时通过它来回调;

Node* node:绑定的对象,当node对象被释放时,监听事件的注册也会被取消,同时,有多个触摸事件发生时(比如几个按钮叠加在一起),会根据node的层次优先回调(越在上面的对象越先回调);

addEventListenerWithFixedPriority,它也是用于注册监听事件,但这个函数需要手动指定触摸事件回调的优先级,并且需要手动取消监听事件。


    Sprite* sp1 = Sprite::create("sprite1.png");
    sp1->setPosition(Point(visibleSize.width * 0.5f, visibleSize.height * 0.5f));
    this->addChild(sp1);

    Sprite* sp2 = Sprite::create("sprite2.png");
    sp2->setPosition(Point(visibleSize.width * 0.5f, visibleSize.height * 0.5f));
    this->addChild(sp2);

    auto listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    listener->onTouchBegan = [](Touch* touch, Event* event){
        /* 注册监听事件的时候不是绑定了一个Node对象么?在这里就可以取出这个对象 */
        auto target = static_cast<Sprite*>(event->getCurrentTarget());

        Point pos = Director::getInstance()->convertToGL(touch->getLocationInView());

        /* 判断点击的坐标是否在精灵的范围内 */
        if (target->getBoundingBox().containsPoint(pos))
        {
            /* 设置精灵的透明度为100 */
            target->setOpacity(100);

            return true;
        }
        
        return false;
    };
    listener->onTouchEnded = [](Touch* touch, Event* event){
        /* 恢复精灵的透明度 */
        auto target = static_cast<Sprite*>(event->getCurrentTarget());
        target->setOpacity(255);
    };
  
    /* 注册监听事件,绑定精灵1 */
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, sp1);

    /* 注册监听事件,绑定精灵2,这里要注意,listener对象拷贝了一个 */
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener->clone(), sp2);
1、创建两个精灵,让这两个精灵刚好有部分位置是重叠的;

2、创建EventListenerTouchOneByOne监听事件;
3、在onTouchBegan函数里获取事件绑定的精灵对象,判断单击的坐标是否在精灵的范围内,是的话,则修改精灵的透明度为100;

4、在onTouchEnded函数里恢复精灵的透明度为255;

5、调用addEventListenerWidthSceneGraphPriority函数分别添加两个精灵的监听事件。

通常需要得到的效果是,在单击重叠部位的时候,只有上面的按钮能获得响应。

listener->setSwallowTouches(true);
setSwallowTouches函数用于设置是否吞没事件,也就是说,当某个触摸事件回调时,截断这个事件,让它不能继续传递给其他人。

为什么要调用两次addEventListenerWithSceneGraphPriority。

其实,注册监听事件就是把listener对象添加到一个列表而已,然后触摸事件发生时,遍历列表,调用这些listener对应的onTouchBegan等函数。

在注册监听事件时绑定了精灵对象,但这不代表系统会自动判断单击屏幕时是否在精灵范围内,这些都需要我们自己来判断。系统只会对所有listener对象进行回调,仅此而已。

那绑定的精灵对象有什么作用?之前说过,绑定的对象用于判断触摸事件回调优先级,以及在绑定对象释放的时候,自动取消触摸事件的监听。注册触摸监听事件后,只要事件没有被吞没,那所有注册过的listener对象都会被回调。


auto target = static_cast<Sprite*>(event->getCurrentTarget());

我们再注册事件时绑定了一个对象,那么,在触摸事件回调时,可以通过getCurrentTarget函数获取这个绑定的对象。由于获取的对象类型的Node,而这个对象实际上是Sprite,所以需要转化一下类型。

target->getBoundingBox().containsPoint(pos)
所有继承了Node的类都拥有getBoundingBox函数,它用于返回对象的矩形碰撞范围,于是,containsPoint当然就是判断某个坐标是否在对象的矩形碰撞范围内了。


  target->setOpacity(100);

setOpacity函数用于设置精灵的透明度。


还有,当我们判断触摸坐标进入了精灵的碰撞范围后,调用了return true,否则就调用return false。如果返回true,代表要吞没触摸事件,其他注册了触摸事件监听但没来得及回调的,就没法获得回调了,需要配合setSwallowTouches使用。返回false,就代表不吞没触摸事件,即使setSwallowTouches设置为true也不吞没。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值