cocos2d-x 3.0 触摸机制的使用

       cocos2d-x 3.0版本的事件分发的机制较之之前的版本进行了修改,把事件处理的逻辑分离出来,并通过不同的事件监听器来监听不同的事件。当一个节点收到了事件,就会指派一个事件分发器_eventDispatcher专门来分发这些事件。对于触摸来说,大概的过程就是我们先创建一个对应触摸事件的监听器,然后覆盖触摸事件的函数,并把它们绑定到监听器,然后可以设置一下这个监听器的属性,最后把监听器添加到分发器之中,系统就会自动进行触摸事件的处理。    

 

       我们先看看单点触摸的使用,下面是源代码中关于单点触摸监听器的类,可以看到

class EventListenerTouchOneByOne: public EventListener
{
public:
    static const std::string LISTENER_ID;
    static EventListenerTouchOneByOne* create();
    virtual~EventListenerTouchOneByOne();
    void setSwallowTouches(bool needSwallow);
    bool isSwallowTouches();
    ///Overrides
    virtual EventListenerTouchOneByOne* clone() override;
    virtual bool checkAvailable() override;
    //
public:
    std::function<bool(Touch*, Event*)>onTouchBegan;
    std::function<void(Touch*, Event*)>onTouchMoved;
    std::function<void(Touch*, Event*)>onTouchEnded;
    std::function<void(Touch*, Event*)> onTouchCancelled;
private:
    EventListener TouchOneByOne();
    bool init();
    std::vector<Touch*>_claimedTouches;
    bool _needSwallow;
    friend class EventDispatcher;
};</span>

这个类看上去比较容易理解,下面我们用代码来演示一下怎么使用。在HelloWorld的init函数中注册监听器并添加到事件分发器中去。

//添加一个测试的精灵
    autoonion = Sprite::create("onion.png");
    onion->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
    onion->setScale(0.2);
    this->addChild(onion);
 
    //创建一个触摸监听器,这里使用单点触摸事件
    autoTouchListenr = EventListenerTouchOneByOne::create();
    //设置吞噬为true,不让触摸往下传递
    TouchListenr->setSwallowTouches(true);
    //和回调函数绑定
    TouchListenr->onTouchBegan= CC_CALLBACK_2(HelloWorld::onTouchBegan,this);
    TouchListenr->onTouchMoved= CC_CALLBACK_2(HelloWorld::onTouchMoved,this);
    TouchListenr->onTouchEnded= CC_CALLBACK_2(HelloWorld::onTouchEnded,this);
    //添加监听器到事件分发器中
    _eventDispatcher->addEventListenerWithSceneGraphPriority(TouchListenr,onion);

下面我们覆盖单点触摸中提供的触摸函数:

bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
    //获取精灵对象并取得精灵的矩阵
    autosprite = static_cast<Sprite*>(event->getCurrentTarget());
    Rect rect = sprite->getBoundingBox();
    //获取触摸点的坐标
    Point point = touch->getLocation();
    //判断触摸点是否在精灵的矩阵范围内
    if(rect.containsPoint(point))
    {
       return true;
    }
    return false;
}
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
    //获取精灵对象
    autosprite = static_cast<Sprite*>(event->getCurrentTarget());
    //改变精灵的位置
    sprite->setPosition(sprite->getPosition()+ touch->getDelta());
}
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
    CCLog("touch end!");
}

点击调试运行,可以在屏幕中拉动所测试的精灵,如下图:


       在上面的例子中我们看到了,传递过来的参数主要有Touch* touch和Event* event,我们可以进入源代码中查看他们的作用。Touch类是继承了REF,查看源代码中的主要成员如下:

/**returns the current touch location in OpenGL coordinates */
    Point getLocation() const;
    /**returns the previous touch location in OpenGL coordinates */
    Point getPreviousLocation() const;
    /**returns the start touch location in OpenGL coordinates */
    Point getStartLocation() const;
    /**returns the delta of 2 current touches locations in screen coordinates */
    Point getDelta() const;
    /**returns the current touch location in screen coordinates */
    Point getLocationInView() const;
    /**returns the previous touch location in screen coordinates */
    Point getPreviousLocationInView() const;
    /**returns the start touch location in screen coordinates */
    Point getStartLocationInView() const;

       也就是Touch传入的是触摸点的坐标位置,并且Touch类为我们提供一些坐标的写法,那么我们就方便很多了。譬如上面例子中的触摸移动时,Touch就为我提供一个getDelta()来计算点的位移。

而对于Event类,主要是传入处理的对象,看源代码有以下主要成员:

 /**Gets the event type */
    inline Type getType() const { return_type; };
    /**Stops propagation for current event */
    inline void stopPropagation() { _isStopped = true; };
   
    /**Checks whether the event has been stopped */
    inline bool isStopped() const { return_isStopped; };
   
    /**@brief Gets current target of the event
     *  @return The target with which the eventassociates.
     *  @note It onlys be available when the eventlistener is associated with node.
     *        It returns 0 when the listener isassociated with fixed priority.
     */
    inline Node* getCurrentTarget() { return_currentTarget; };

         那么我们在处理触摸对象的时候和例子那样通过getCurrentTarget()来获取对象并处理即可。

         另一方面,我们在把监听器添加到事件分发器的时候,会看到代码提示两种方法,一个为:addEventListenerWithSceneGraphPriority,另一个为addEventListenerWithFixedPriority。同样可以查看源代码如下:

 /**Adds a event listener for a specified event with the priority of scene graph.
     *  @param listener The listener of a specifiedevent.
     *  @param node The priority of the listener isbased on the draw order of this node.
     *  @note The priority of scene graph will be fixed value 0. So the order oflistener item
     *          in the vector will be ' <0, scenegraph (0 priority), >0'.
     */
    voidaddEventListenerWithSceneGraphPriority(EventListener*listener, Node* node);
 
    /**Adds a event listener for a specified event with the fixed priority.
     *  @param listener The listener of a specifiedevent.
     *  @param fixedPriority The fixed priority ofthe listener.
     *  @note A lower priority will be called beforethe ones that have a higher value.
     *        0 priority is forbidden for fixedpriority since it's used for scene graph based priority.
     */
    voidaddEventListenerWithFixedPriority(EventListener*listener, int fixedPriority);

       根据注释可以知道,前者的触发优先级是按照第二个参数中的node的显示顺序来确定的,而且默认的fixedPriority为0,也就是如果精灵位置靠前,则会优先响应触摸。而后者按照第二个参数的整形变量值的大小来确定的,而且不能为0,值越小那么优先响应触摸。两者除了优先级不一样,移除的过程也有差异。前者会在触摸对象对应的node析构之后系统会帮我们调用移除触摸,但是后者就需要我们手动移除,这一点要注意。

       下面我们可以修改上述例子的代码,添加多两个精灵,然后在分发事件代码中添加:

 _eventDispatcher->addEventListenerWithSceneGraphPriority(TouchListenr->clone(),onion2);
 _eventDispatcher->addEventListenerWithSceneGraphPriority(TouchListenr->clone(),onion3);

       点击运行可以测试一下,没有问题。要是想使用addEventListenerWithFixedPriority的方式的话,虽然可以自定义优先级,但是由于没有绑定node对象,所以还需要在触摸函数中引入需要控制的对象才行。但是最后别忘了使用_eventDispatcher->removeEventListener(listerName);来实现监听器的移除。

 

       多点触摸和单点触摸类似,看下面多点触摸监听器的源码。

class EventListenerTouchAllAtOnce: public EventListener
{
public:
    static const std::string LISTENER_ID;
   
    static EventListenerTouchAllAtOnce* create();
    virtual ~EventListenerTouchAllAtOnce();
   
    ///Overrides
    virtua lEventListenerTouchAllAtOnce* clone() override;
    virtual bool checkAvailable() override;
    //
public:
    std::function<void(conststd::vector<Touch*>&,Event*)> onTouchesBegan;
    std::function<void(conststd::vector<Touch*>&,Event*)> onTouchesMoved;
    std::function<void(conststd::vector<Touch*>&,Event*)> onTouchesEnded;
    std::function<void(conststd::vector<Touch*>&,Event*)> onTouchesCancelled;
   
private:
   EventListener TouchAllAtOnce();
    bool init();
private:
   
    friend class EventDispatcher;
};

    可以发现多点触摸就是传入多个Touch对象而已,然后处理的时候可以遍历vector<Touch*>来逐个处理每一个点,例子可以参考源码自带的例子MutiTouchTest。


    文章写到这里为止,如有理解不当,请不吝赐教,谢谢。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值