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.