AniGestureRecognizer.cpp 7.23 KB
//
//  AniGestureRecognizer.cpp
//  SteveMaggieCpp
//
//  Created by Katarzyna Kalinowska-Górska on 19.05.2017.
//
//

#include <stdio.h>
#include "AniGestureRecognizer.h"

AniGestureRecognizer::AniGestureRecognizerDirection AniGestureRecognizer::mapXToDirection(float x)
{
    if(x < 0){
        return AniGestureRecognizerDirection::LEFT;
    } else if(x > 0){
        return AniGestureRecognizerDirection::RIGHT;
    } else {
        return AniGestureRecognizerDirection::NONE;
    }
}

AniGestureRecognizer::AniGestureRecognizerDirection AniGestureRecognizer::mapYToDirection(float y)
{
    if(y < 0){
        return AniGestureRecognizerDirection::DOWN;
    } else if(y > 0){
        return AniGestureRecognizerDirection::UP;
    } else {
        return AniGestureRecognizerDirection::NONE;
    }
}

AniGestureRecognizer::AniGestureRecognizer(std::vector<cocos2d::EventListener::Type> handledEvents)
{
   _handledEvents = handledEvents;
   _view = NULL;
   _enabled = true;
}

AniGestureRecognizer::~AniGestureRecognizer(){
    this->uninstall();
}

// install gesture recognizer in given view

void AniGestureRecognizer::install(cocos2d::Node* view)
{
    if(!view){
        cocos2d::log("Gesture Recognizer install fail: view must not be null");
        return;
    }
    
    _view = view;
    
    if(std::find(_handledEvents.begin(), _handledEvents.end(), cocos2d::EventListener::Type::TOUCH_ONE_BY_ONE) != _handledEvents.end()){
        
        auto touchListener = cocos2d::EventListenerTouchOneByOne::create();
    
        touchListener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event) -> bool {
            return _enabled && this->onTouchBegan(touch, event);
        };
        
        touchListener->onTouchMoved = [&](cocos2d::Touch* touch, cocos2d::Event* event){
            if(_enabled){
                this->onTouchMoved(touch, event);
            }
        };

        touchListener->onTouchEnded = [&](cocos2d::Touch* touch, cocos2d::Event* event){
            if(_enabled){
                this->onTouchEnded(touch, event);
            }
        };

        touchListener->setSwallowTouches(false);

        _view->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, _view);
//        _view->getEventDispatcher()->addEventListenerWithFixedPriority(touchListener, -1);
//        _view->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, _view);

        _eventListener = touchListener;
    }
    
    if(std::find(_handledEvents.begin(), _handledEvents.end(), cocos2d::EventListener::Type::TOUCH_ALL_AT_ONCE) != _handledEvents.end()){
    
        auto touchListener = cocos2d::EventListenerTouchAllAtOnce::create();
    
        touchListener->onTouchesBegan = [&](const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event) -> bool{
            return _enabled && this->onTouchesBegan(touches, event);
        };
        
        touchListener->onTouchesMoved = [&](const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event){
            if(_enabled){
                this->onTouchesMoved(touches, event);
            }
        };

        touchListener->onTouchesEnded = [&](const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event){
            if(_enabled){
                this->onTouchesEnded(touches, event);
            }
        };

        _view->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, _view);

        _eventListener = touchListener;
    }
}

void AniGestureRecognizer::uninstall()
{
    if(_eventListener){
        _view->getEventDispatcher()->removeEventListener(_eventListener);
        _eventListener = nullptr;
    }
}

void AniGestureRecognizer::changeTouchListenerPriorityToFixed(int newPriority)
{
    if(_eventListener){
        _view->getEventDispatcher()->removeEventListener(_eventListener);
        _view->getEventDispatcher()->addEventListenerWithFixedPriority(_eventListener, newPriority);
    }
}

void AniGestureRecognizer::changeTouchListenerPriorityToSceneGraphPriority()
{
    if(_eventListener){
        _view->getEventDispatcher()->removeEventListener(_eventListener);
        _view->getEventDispatcher()->addEventListenerWithSceneGraphPriority(_eventListener, _view);
    }
}

void AniGestureRecognizer::setSwallowsTouches(bool swallowsTouches)
{
    auto eventListenerOneByOne = dynamic_cast<cocos2d::EventListenerTouchOneByOne*>(_eventListener);
    if(eventListenerOneByOne){
        eventListenerOneByOne->setSwallowTouches(true);
    }
}

    
///////////////////////////////////////////////////////////////////////////
// internal
///////////////////////////////////////////////////////////////////////////

// cc.EventListener.TOUCH_ONE_BY_ONE
    
bool AniGestureRecognizer::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
    return false;
}
    
void AniGestureRecognizer::onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)
{
}
    
void AniGestureRecognizer::onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)
{
}

// cc.EventListener.TOUCH_ALL_AT_ONCE

bool AniGestureRecognizer::onTouchesBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
{
    this->saveTouches(_rememberedTouches, touches);
    return false;
}

void AniGestureRecognizer::onTouchesMoved(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
{
    this->updateTouches(_rememberedTouches, touches);
}
    
void AniGestureRecognizer::onTouchesEnded(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
{
    this->filterTouches(_rememberedTouches, touches);
}

// handle remembered touches

void AniGestureRecognizer::saveTouches(std::vector<TouchData>& rememberedTouches, const std::vector<cocos2d::Touch*>& touches)
{
    for(int i = 0; i < touches.size(); ++i){
        rememberedTouches.push_back(TouchData(touches[i]->getID(), touches[i]->getLocation(), touches[i]->getPreviousLocation(), touches[i]->getLocation()));
    }
}

void AniGestureRecognizer::updateTouches(std::vector<TouchData>& rememberedTouches, const std::vector<cocos2d::Touch*>& touches)
{
    for(int i = 0; i < rememberedTouches.size(); ++i){
        for(int j = 0; j < touches.size(); ++j){
            if(rememberedTouches[i].touchId == touches[j]->getID()){
                rememberedTouches[i].currentTouchLocation = touches[j]->getLocation();
                rememberedTouches[i].previousTouchLocation = touches[j]->getPreviousLocation();
                break;
            }
        }
    }
}

void AniGestureRecognizer::filterTouches(std::vector<TouchData>& rememberedTouches, const std::vector<cocos2d::Touch*>& touches)
{
//todo: map? filter?
    for(int i = (int)rememberedTouches.size() - 1; i >= 0; --i){
        for(int j = 0; j < touches.size(); ++j){
            if(touches[j]->getID() == rememberedTouches[i].touchId){
                rememberedTouches.erase(rememberedTouches.begin() + i);
                break;
            }
        }
    }
}

cocos2d::Touch* AniGestureRecognizer::findTouchWithID(const std::vector<cocos2d::Touch*>& touches, int touchId)
{
    std::vector<cocos2d::Touch*> toReturn;
    std::copy_if(touches.begin(), touches.end(), std::back_inserter(toReturn), [&](const cocos2d::Touch* touch) { return touch->getID() == touchId; });
        
    if(toReturn.size() > 0){
        return toReturn[0];
    } else {
        return NULL;
    }
}