Tickle2GestureRecognizer.cpp 6.34 KB
//
//  Tickle2GestureRecognizer.cpp
//  SteveMaggieCpp
//
//  Created by Katarzyna Kalinowska-Górska on 19.05.2017.
//
//

#include <stdio.h>
#include "Tickle2GestureRecognizer.h"
#include "AniGeometryUtils.h"
#include "AniMathUtils.h"
#include "AniMiscUtils.h"

//constructor

Tickle2GestureRecognizer::Tickle2GestureRecognizer() : AniGestureRecognizer({cocos2d::EventListener::Type::TOUCH_ONE_BY_ONE})
{
    this->clearTemps();
    _currentDirectionX = AniGestureRecognizerDirection::NONE;
    _currentDirectionY = AniGestureRecognizerDirection::NONE;
    _onTicklingStartedCallback = [](){};
    _onTicklingCallback = [](){};
    _onTicklingEndedCallback = [](){};
    _isTickling = false;
}

Tickle2GestureRecognizer::~Tickle2GestureRecognizer()
{
};

void Tickle2GestureRecognizer::setOnTicklingStartedCallback(std::function<void()> callback)
{
    _onTicklingStartedCallback = callback;
}

void Tickle2GestureRecognizer::setOnTicklingCallback(std::function<void()> callback)
{
    _onTicklingCallback = callback;
}

void Tickle2GestureRecognizer::setOnTicklingEndedCallback(std::function<void()> callback)
{
    _onTicklingEndedCallback = callback;
}

// internal

void Tickle2GestureRecognizer::clearTemps()
{
    _directionChangeTimes.clear();
    _lastXDeltas.clear();
    _lastYDeltas.clear();
    _tickleStartedTime = -1;
}

void Tickle2GestureRecognizer::endTickling()
{
    _onTicklingEndedCallback();
    _isTickling = false;
    _tickleStartedTime = -1;
}

// touch handlers

bool Tickle2GestureRecognizer::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
    if(!AniGeometryUtils::getBoundingBoxToWorld(_view).containsPoint(touch->getLocation())){
        return false;
    }
    
    this->clearTemps();
    _currentDirectionX = AniGestureRecognizerDirection::NONE;
    _currentDirectionY = AniGestureRecognizerDirection::NONE;
    
    return true;
}
    
void Tickle2GestureRecognizer::onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)
{
//    if(!AniGeometryUtils::getBoundingBoxToWorld(_view).containsPoint(touch->getLocation())){
    if(!AniMiscUtils::getExtendedActiveArea(_view, 20, 10).containsPoint(touch->getLocation())){
        this->endTickling();
        this->clearTemps();
        return;
    }

    auto touchLocation = touch->getLocation();
    auto prevLocation = touch->getPreviousLocation();
    auto deltaX = touchLocation.x - prevLocation.x;
    auto deltaY = touchLocation.y - prevLocation.y;
    
    bool newTickling = false;
    
    //todo into separate function ? !!!
    _lastXDeltas.push_back(deltaX);
    
    if(_lastXDeltas.size() >= N_LAST_SAMPLES){
    
        while(_lastXDeltas.size() > N_LAST_SAMPLES){
            _lastXDeltas.pop_front();
        }
        
        float averageDeltaX = 0;
        AniMathUtils::averageValue(_lastXDeltas, averageDeltaX);
        
//            log("delta:  "+averageDeltaX);
        if(std::abs(averageDeltaX) >= MIN_DELTA_VALUE){
        
            auto xDirection = AniGestureRecognizer::mapXToDirection(averageDeltaX);
            if(xDirection != _currentDirectionX && xDirection != AniGestureRecognizerDirection::NONE){
                
                _currentDirectionX = xDirection;
                
                while(_directionChangeTimes.size() > N_DIRECTION_CHANGES_TO_DETECT_TICKLE-1){
                    _directionChangeTimes.pop_front();
                }
                
                double now = cocos2d::utils::getTimeInMilliseconds();
                _directionChangeTimes.push_back(now);
                
                if(_directionChangeTimes.size() == N_DIRECTION_CHANGES_TO_DETECT_TICKLE){
                    auto deltaTime = now - _directionChangeTimes[0];
//                    log("delta time: "+deltaTime);
                    if(deltaTime <= MAX_DETECTION_TIME){
                        
                        newTickling = true;
//                        this->clearTemps();
                    }
                }
                
//                return;
            }
        }
        
    }
    
    _lastYDeltas.push_back(deltaY);
    
    if(!newTickling && _lastYDeltas.size() >= N_LAST_SAMPLES){
    
        while(_lastYDeltas.size() > N_LAST_SAMPLES){
            _lastYDeltas.pop_front();
        }
        
        float averageDeltaY = 0;
        AniMathUtils::averageValue(_lastYDeltas, averageDeltaY);
//        cocos2d::log("average delta y: %f", averageDeltaY);
        
        if(std::abs(averageDeltaY) >= MIN_DELTA_VALUE){
        
            auto yDirection = AniGestureRecognizer::mapYToDirection(averageDeltaY);
            if(yDirection != _currentDirectionY && yDirection != AniGestureRecognizerDirection::NONE){
                _currentDirectionY = yDirection;
                
//                cocos2d::log("current y dir: %s",_currentDirectionY.c_str());
//                cocos2d::log("dir change count: %d",_directionChangeCount);
                
                while(_directionChangeTimes.size() > N_DIRECTION_CHANGES_TO_DETECT_TICKLE-1){
                    _directionChangeTimes.pop_front();
                }

                double now = cocos2d::utils::getTimeInMilliseconds();
                _directionChangeTimes.push_back(now);
                
                if(_directionChangeTimes.size() == N_DIRECTION_CHANGES_TO_DETECT_TICKLE){
                    auto deltaTime = now - _directionChangeTimes[0];
//                    cocos2d::log("delta time: %f", deltaTime);
                    if(deltaTime <= MAX_DETECTION_TIME){
                        
                        newTickling = true;
                        
//                        this->clearTemps();
                    }
                }
            }
        }
    }
    
    if(newTickling == true){
        if(_isTickling){
            _onTicklingCallback();
        } else {
            if(!_isTickling){
                _isTickling = true;
                _onTicklingStartedCallback();
            }
            _tickleStartedTime = cocos2d::utils::getTimeInMilliseconds();
        }
        
    } /*else if(_isTickling) {
        double currentTime = cocos2d::utils::getTimeInMilliseconds();
        if(currentTime - _tickleStartedTime > TIME_TO_ASSUME_TICKLE_FINISHED){
            this->endTickling();
        }
    }*/
    
}

void Tickle2GestureRecognizer::onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)
{
    if(_isTickling){
        this->endTickling();
    }
    
    this->clearTemps();
}