Resposta a Toques no Cocos2d-x 3.0

No Cocos2d-x 3.0, o tratamento de eventos de toque passou por uma reformulação substancial, eliminando limitações anteriores. Na versão 2.0, apenas a classe CCLayer suportava eventos de toque, exigindo registro manual e implementação de métodos como onTouchBegan, com transmissão baseada em prioridades que frequentemente causava bugs complexos. A nova abordagem introduz flexibilidade e simplicidade.

Existem dois métodos principais para manipular eventos de toque no Cocos2d-x 3.0:

1. Retorno de Chamada de Função

Este método utiliza funções de retorno vinculadas a objetos, simplificado com macros como CC_CALLBACK_1. Veja um exemplo reescrito:

// Declaração da função de retorno
void manipularCliqueFechar(Ref* remetente);

// Criação do item de menu com vinculação
auto itemFechar = MenuItemImage::create("FecharNormal.png", "FecharSelecionado.png",
    CC_CALLBACK_1(ManipuladorCena::manipularCliqueFechar, this));

// Implementação da função
void ManipuladorCena::manipularCliqueFechar(Ref* remetente) {
    Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

A macro CC_CALLBACK_1 associa a função ao objeto, indicando um parâmetro. Ao clicar no botão, a função é invocada.

2. Método de Resposta por Listener

Com listeners, qualquer sprite pode responder a eventos de toque sem herdar de Layer. Basta criar um listener, vinculá-lo ao sprite e adicioná-lo ao despachante de eventos. Cada listener pode ser clonado para reutilização. Exemplo reescrito:

#ifndef __TESTE_SPRITE_TOCAVEL_H__
#define __TESTE_SPRITE_TOCAVEL_H__

#include "cocos2d.h"
USING_NS_CC;

class TesteSpriteTocavel : public Layer {
public:
    CREATE_FUNC(TesteSpriteTocavel);
    virtual void aoEntrar() override;
    virtual void aoSair() override;
};

#endif
#include "TesteSpriteTocavel.h"

void TesteSpriteTocavel::aoEntrar() {
    Layer::aoEntrar();
    Point origem = Director::getInstance()->getVisibleOrigin();
    Size tamanho = Director::getInstance()->getVisibleSize();

    auto conteudoSprite1 = Node::create();
    this->addChild(conteudoSprite1, 10);
    auto spriteA = Sprite::create("imagens/QuadradoCiano.png");
    spriteA->setPosition(origem + Point(tamanho.width * 0.5, tamanho.height * 0.5) + Point(-80, 80));
    conteudoSprite1->addChild(spriteA);

    auto spriteB = Sprite::create("imagens/QuadradoMagenta.png");
    spriteB->setPosition(origem + Point(tamanho.width / 2, tamanho.height / 2));
    addChild(spriteB, 20);

    auto spriteC = Sprite::create("imagens/QuadradoAmarelo.png");
    spriteC->setPosition(Point(0, 0));
    spriteB->addChild(spriteC, 1);

    // Configurar listener para spriteA
    auto ouvinteToque = EventListenerTouchOneByOne::create();
    ouvinteToque->setSwallowTouches(true);

    ouvinteToque->onTouchBegan = [](Touch* toque, Event* evento) {
        auto alvo = static_cast<sprite>(evento->getCurrentTarget());
        Point posicaoNoNode = alvo->convertToNodeSpace(toque->getLocation());
        Size dimensoes = alvo->getContentSize();
        Rect areaRetangular = Rect(0, 0, dimensoes.width, dimensoes.height);

        if (areaRetangular.containsPoint(posicaoNoNode)) {
            log("toque iniciado... x = %f, y = %f", posicaoNoNode.x, posicaoNoNode.y);
            alvo->setOpacity(180);
            return true;
        }
        return false;
    };

    ouvinteToque->onTouchMoved = [](Touch* toque, Event* evento) {
        auto alvo = static_cast<sprite>(evento->getCurrentTarget());
        alvo->setPosition(alvo->getPosition() + toque->getDelta());
    };

    ouvinteToque->onTouchEnded = [=](Touch* toque, Event* evento) {
        auto alvo = static_cast<sprite>(evento->getCurrentTarget());
        log("toque finalizado.. ");
        alvo->setOpacity(255);
        if (alvo == spriteB) {
            conteudoSprite1->setLocalZOrder(100);
        } else if (alvo == spriteA) {
            conteudoSprite1->setLocalZOrder(0);
        }
    };

    _eventDispatcher->addEventListenerWithSceneGraphPriority(ouvinteToque, spriteA);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(ouvinteToque->clone(), spriteB);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(ouvinteToque->clone(), spriteC);

    // Adicionar item de menu para demonstração
    Rect areaVisivel = Director::getInstance()->getOpenGLView()->getVisibleRect();
    Point pontoDireito = Point(areaVisivel.origin.x + areaVisivel.size.width, areaVisivel.origin.y + areaVisivel.size.height / 2);

    auto itemRemoverTodos = MenuItemFont::create("Remover Todos Listeners ", [&](Ref* remetente) {
        auto item = static_cast<menuitemfont>(remetente);
        item->setString("Somente o próximo item pode ser clicado ");
        _eventDispatcher->removeEventListenersForType(EventListener::Type::TOUCH_ONE_BY_ONE);

        auto itemProximo = MenuItemFont::create("Próximo", [&](Ref* remetente) {});
        itemProximo->setFontSizeObj(16);
        itemProximo->setPosition(pontoDireito + Point(-100, -30));
        auto menuSecundario = Menu::create(itemProximo, NULL);
        menuSecundario->setPosition(Point(0, 0));
        menuSecundario->setAnchorPoint(Point(0, 0));
        this->addChild(menuSecundario);
    });

    itemRemoverTodos->setFontSizeObj(16);
    itemRemoverTodos->setPosition(pontoDireito + Point(-100, 0));
    auto menuPrincipal = Menu::create(itemRemoverTodos, nullptr);
    menuPrincipal->setPosition(Point(0, 0));
    menuPrincipal->setAnchorPoint(Point(0, 0));
    addChild(menuPrincipal);
}

void TesteSpriteTocavel::aoSair() {
    Layer::aoSair();
}</menuitemfont></sprite></sprite></sprite>

Para uma compreensão mais profunda, é recomendável estudar a implementação subjacente do sistema de eventos no Cocos2d-x 3.0.

Tags: cocos2d-x Eventos de Toque C++11 sistema de eventos Desenvolvimento de Jogos

Publicado em 7-17 16:28