简单手势识别

模拟iOS原生手势,简单实现点击(双击)、长按、滑动、拖动等功能。

代码如下:

//
// CGesture.h
// ActionLabel
//
// Created by xujw on 16/3/15.

/* 手势识别 仿iphone 简单长按 点击(双击等) 滑动 拖动等。 * 使用方法: * auto gesture = CGesture::createTapGesture(target,callback,taps); * this->addChild(gestrue) */

#ifndef CGesture_h
#define CGesture_h

#include <stdio.h>
#include "cocos2d.h"
USING_NS_CC;

typedef enum gestureDirection
{
    kDirectUp = 0,kDirectDown = 1,kDirectLeft = 2,kDirectRight = 3
}GestureDirection;

typedef std::function<void(Touch*)> GestureCallback;
typedef std::function<void(Touch*,GestureDirection)> SwipeGestureCallback;

#define SHAKE_LENGTH 100

class CGesture:public Layer
{
private:
    bool _isCanTouch;
    int _tapNum;
public:
    CGesture();
    ~CGesture();
    bool init();
    CREATE_FUNC(CGesture);
public:
    //点击
    static CGesture* createTapGesture(Node*target,GestureCallback callback,int tapsRequired=1);
    //长按
    static CGesture* createLongPressGesture(Node*target,float delay = 1.0f);
    //滑动
    static CGesture* createSwipeGesture(Node*target,SwipeGestureCallback callback);
    //拖动
    static CGesture* createPanGestrue(Node*target,GestureCallback callback);
};
#endif /* CGesture_h */

//
// CGesture.cpp
// ActionLabel
//
// Created by xujw on 16/3/15.
//
//

#include "CGesture.h"
#include <time.h>

CGesture::CGesture()
:_isCanTouch(false),_tapNum(0)
{}
CGesture::~CGesture()
{}

bool CGesture::init()
{
    if (!Layer::init())
    {
        return false;
    }

    return true;
}

CGesture* CGesture::createTapGesture(Node*target,int tapsRequired)
{
    CCASSERT(callback && target,"callback or target is null");

    auto parent = target->getParent();

    auto gesture = CGesture::create();

    auto lis = EventListenerTouchOneByOne::create();
    lis->onTouchBegan = [=](Touch *touch,Event *event)
    {
        auto box = target->getBoundingBox();
        auto pos = touch->getLocation();
        if (parent) {
            pos = parent->convertToNodeSpace(pos);
        }
        if (box.containsPoint(pos))
        {
            gesture->_tapNum ++;
        }

        return true;
    };
    lis->onTouchMoved = [=](Touch *touch,Event *event)
    {
        auto startPos = touch->getStartLocation();
        auto curPos = touch->getLocation();
        auto subPos = curPos - startPos;
        if (fabs(subPos.x)>=10 || fabs(subPos.y)>=10)
        {
            gesture->_tapNum = 0;
            gesture->unschedule("GestureTapNumReset");
        }        
    };
    lis->onTouchEnded = [=](Touch *touch,Event *event)
    {
        if (gesture->_tapNum >= tapsRequired)
        {
            auto box = target->getBoundingBox();
            auto pos = touch->getLocation();
            auto parent = target->getParent();
            if (parent) {
                pos = parent->convertToNodeSpace(pos);
            }
            if (box.containsPoint(pos))
            {
                gesture->_tapNum = 0;
                gesture->unschedule("GestureTapNumReset");
                callback(touch);
            }
        }
        gesture->scheduleOnce([=](float dt)
        {
            gesture->_tapNum = 0;
        },0.5,"GestureTapNumReset");
    };

    gesture->getEventDispatcher()->addEventListenerWithSceneGraphPriority(lis,target);

    return gesture;
}

CGesture* CGesture::createLongPressGesture(Node*target,float delay)
{
    CCASSERT(callback && target,Event *event)
    {
        auto box = target->getBoundingBox();
        auto pos = touch->getLocation();
        if (parent) {
            pos = parent->convertToNodeSpace(pos);
        }
        if (box.containsPoint(pos))
        {
            gesture->scheduleOnce([=](float){
                gesture->_isCanTouch = true;
            },delay,"GestureChangeTouchState");
            return true;
        }
        else
        {
            return false;
        }
    };
    lis->onTouchMoved = [=](Touch *touch,Event *event)
    {
        //长按时滑动算取消
        auto startPos = touch->getStartLocation();
        auto curPos = touch->getLocation();
        auto subPos = curPos - startPos;
        if (fabs(subPos.x)>=10 || fabs(subPos.y)>=10)
        {
            gesture->unschedule("GestureChangeTouchState");
            gesture->_isCanTouch = false;
        }
    };
    lis->onTouchEnded = [=](Touch *touch,Event *event)
    {
        auto box = target->getBoundingBox();
        auto pos = touch->getLocation();
        if (parent) {
            pos = parent->convertToNodeSpace(pos);
        }

        if (gesture->_isCanTouch)
        {
            if (box.containsPoint(pos))
            {
                callback(touch);
            }
        }
        else
        {
            gesture->unschedule("GestureChangeTouchState");
        }
        gesture->_isCanTouch = false;
    };

    gesture->getEventDispatcher()->addEventListenerWithSceneGraphPriority(lis,target);

    return gesture;
}

CGesture* CGesture::createSwipeGesture(Node*target,SwipeGestureCallback callback)
{
    CCASSERT(callback && target,"callback or target is null");

    auto parent = target->getParent();
    auto gesture = CGesture::create();

    auto lis = EventListenerTouchOneByOne::create();
    lis->onTouchBegan = [=](Touch *touch,Event *event)
    {
        auto pos = touch->getLocation();
        auto box = target->getBoundingBox();
        if (parent) {
            pos = parent->convertToNodeSpace(pos);
        }
        if (box.containsPoint(pos))
        {
            gesture->_isCanTouch = true;
        }
        else{
            gesture->_isCanTouch = false;
        }
        return gesture->_isCanTouch;
    };
    lis->onTouchMoved = [=](Touch *touch,Event *event){};
    lis->onTouchEnded = [=](Touch *touch,Event *event)
    {
        auto pos = touch->getLocation();
        auto box = target->getBoundingBox();
        if (parent) {
            pos = parent->convertToNodeSpace(pos);
        }
        //起始点都在target范围内才响应
        if (!gesture->_isCanTouch || !box.containsPoint(pos))
        {
            gesture->_isCanTouch = false;
            return ;
        }

        auto startPos = touch->getStartLocation();
        auto curPos = touch->getLocation();
        auto subPos = curPos - startPos;

        if (fabs(subPos.x) > fabs(subPos.y))
        {
            //左右移动
            if (subPos.x > SHAKE_LENGTH)
            {
                //向右移动
                callback(touch,kDirectRight);
            }
            else if (subPos.x < -SHAKE_LENGTH)
            {
                //向左移动
                callback(touch,kDirectLeft);
            }
        }
        else
        {
            if (subPos.y > SHAKE_LENGTH)
            {
                //向上移动
                callback(touch,kDirectUp);
            }
            else if (subPos.y < -SHAKE_LENGTH)
            {
                //向下移动
                callback(touch,kDirectDown);
            }
        }
    };
    gesture->getEventDispatcher()->addEventListenerWithSceneGraphPriority(lis,gesture);
    return gesture;
}

CGesture* CGesture::createPanGestrue(Node*target,GestureCallback callback)
{
    CCASSERT(callback && target,Event *event)
    {
        auto box = target->getBoundingBox();
        auto pos = touch->getLocation();
        if (parent) {
            pos = parent->convertToNodeSpace(pos);
        }
        if (box.containsPoint(pos))
        {
            gesture->_isCanTouch = true;
        }
        return true;
    };
    lis->onTouchMoved = [=](Touch *touch,Event *event)
    {
        if (gesture->_isCanTouch)
        {
            callback(touch);
        }
    };
    lis->onTouchEnded = [=](Touch *touch,Event *event)
    {
        gesture->_isCanTouch = false;
    };
    gesture->getEventDispatcher()->addEventListenerWithSceneGraphPriority(lis,target);
    return gesture;
}

代码下载Git

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...