Iniciamos desenvolvimento de um jogo de labirinto com a mecânica clássica.
Já criamos o projeto e implementamos a tela de gameplay.
Continuaremos a implementação movendo o personagem no cenário.
No último tutorial, nós criamos o projeto Cocos2d-x de um jogo de labirinto com a mecânica clássica. Também implementamos a tela de gameplay como um protótipo do jogo final.
Ainda precisamos fazer com que o personagem ande pelo labirinto, contar a quantidade de passos que o jogador deu e finalizar o jogo quando ele alcançar o final do labirinto. No tutorial de hoje, faremos com que o personagem se mova pelo labirinto.
Detectando Toques na Tela
O personagem se moverá apenas quando o jogador inicia um toque na tela. Nesse jogo, não há a necessidade de identificar quando o jogador move o dedo encostado pela tela nem quando o jogador desencosta o dedo. Dessa forma, precisaremos apenas instanciar na classe HelloWorld um objeto gerenciador de toques na tela e declarar o método “onTouchBegan”. Com isso, abra o arquivo “HelloWorldScene.h” e adicione as seguintes linhas de código:
cocos2d::EventListenerTouchOneByOne* toqueNaTela;
bool onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event);
logo abaixo dessa:
cocos2d::Sprite* personagem;
Essa é a única modificação que precisamos fazer nesse arquivo. Salve-o e você já pode fechá-lo. Agora, precisamos instanciar o objeto “toqueNaTela” e implementar o método “onTouchBegan”. Para instanciar o objeto gerenciador de toques na tela, abra o arquivo “HelloWorldScene.cpp” e adicione as seguintes linhas de código:
HelloWorld::toqueNaTela = EventListenerTouchOneByOne::create();
HelloWorld::toqueNaTela->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan,this);
getEventDispatcher()->addEventListenerWithSceneGraphPriority(HelloWorld::toqueNaTela,this);
logo abaixo dessa:
HelloWorld::labirinto->addChild(HelloWorld::personagem);
Com isso, nós instanciamos o objeto “toqueNaTela” e fizemos com que o método “onTouchBegan”, da classe HelloWorld, seja chamado sempre quando o jogador encostar o dedo na tela. Porém, o método “onTouchBegan” ainda não foi implementado. Adicione no final do arquivo as seguintes linhas de código.
bool HelloWorld::onTouchBegan(Touch *touch,Event *unused_event) {
return true;
}
Não é muito difícil de notar que, na verdade, ainda não implementamos nenhuma resposta ao toque na tela. O método “onTouchBegan” é chamado quando isso acontece, porém, nada é feito a respeito.
Agora faremos o personagem andar quando o jogador encosta o dedo na tela, caso o cenário possibilite.
Movendo o Personagem
Existem alguns requisitos para que o personagem se locomova na tela. O mais óbvio é que ele somente pode estar em células possíveis de andar, ou seja, somente naquelas que não são paredes (pretas). Além disso, existe o problema de identificar para qual direção o jogador deseja que o personagem ande.
Resolveremos o problema de identificar a direção que o jogador deseja que o personagem ande calculando um ângulo. Esse ângulo é calculado com base na posição do personagem e no ponto onde o jogador encostou o dedo na tela. É traçado um segmento de reta que se inicia no centro do personagem e termina no ponto onde o jogador encostou o dedo na tela. Logo após, é calculado o ângulo entre o segmento e o eixo de coordenadas X. Com base nesse ângulo, é identificada a direção que o jogador deseja mover o personagem. Se é para a direita, para cima, para a esquerda ou para baixo.
Após identificar a direção, verificaremos se o personagem se movimentará para uma célula que não é parede. Caso não seja parede, nós movimentaremos o personagem para a nova célula, simples assim. Abra o arquivo “HelloWorldScene.cpp” e adicione as seguintes linhas de código:
int i,j;
float angulo;
Sprite* tile;
Vec2 p = touch->getLocationInView();
p.y = Director::getInstance()->getVisibleSize().height – p.y;
p.subtract(HelloWorld::personagem->getPosition().operator*(HelloWorld::labirinto->getScale()));
if(!p.isZero()) {
i = (HelloWorld::personagem->getPositionX()*HelloWorld::labirinto->getScale())/
(HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->
getTileAt(Vec2(0,0))->getBoundingBox().size.width*HelloWorld::labirinto->getScale());
j = (HelloWorld::labirinto->getBoundingBox().size.height –
(HelloWorld::personagem->getPositionY()*HelloWorld::labirinto->getScale()))/
(HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->
getTileAt(Vec2(0,0))->getBoundingBox().size.height*HelloWorld::labirinto->getScale());
p.normalize();
angulo = acos(p.x);
if(angulo<=M_PI/4.0) {
//APERTOU PARA A DIREITA
if(i<7&&HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->getTileGIDAt(Vec2(i+1,j))!=1) {
tile = HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->getTileAt(Vec2(i+1,j));
HelloWorld::personagem->setPosition(Vec2(
tile->getPositionX() + tile->getBoundingBox().size.width/2,
tile->getPositionY() + tile->getBoundingBox().size.height/2));
}
} else if(angulo<=(3.0*M_PI)/4.0) {
if(p.y>0.0) {
//APERTOU PARA CIMA
if(j>0&&HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->
getTileGIDAt(Vec2(i,j-1))!=1) {
tile = HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->
getTileAt(Vec2(i,j-1));
HelloWorld::personagem->setPosition(Vec2(
tile->getPositionX() + tile->getBoundingBox().size.width/2,
tile->getPositionY() + tile->getBoundingBox().size.height/2));
}
} else {
//APERTOU PARA BAIXO
if(j<4&&HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->
getTileGIDAt(Vec2(i,j+1))!=1) {
tile = HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->
getTileAt(Vec2(i,j+1));
HelloWorld::personagem->setPosition(Vec2(
tile->getPositionX() + tile->getBoundingBox().size.width/2,
tile->getPositionY() + tile->getBoundingBox().size.height/2));
}
}
} else {
//APERTOU PARA A ESQUERDA
if(i>0&&HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->getTileGIDAt(Vec2(i-1,j))!=1) {
tile = HelloWorld::labirinto->getLayer(“Camada de Tiles 1”)->getTileAt(Vec2(i-1,j));
HelloWorld::personagem->setPosition(Vec2(
tile->getPositionX() + tile->getBoundingBox().size.width/2,
tile->getPositionY() + tile->getBoundingBox().size.height/2));
}
}
}
logo abaixo dessa:
bool HelloWorld::onTouchBegan(Touch *touch,Event *unused_event) {
Note que a variável “angulo” armazena o ângulo comentado anteriormente. Esse ângulo pode variar entre 0 e 180 graus. Se ele estiver entre 0 e 45 graus, então o jogador encostou o dedo na direita do personagem. Se o ângulo estiver entre 45 e 135 graus, então o jogador encostou o dedo logo acima ou abaixo do personagem. Se o sinal da variável “p.y” for positivo, então o jogador encostou o dedo acima do personagem, senão ele encostou abaixo. Em último caso, o jogador encostou o dedo à esquerda do personagem. Identificada a direção, é verificado se a célula respectiva à direção escolhida não é parede, ou seja, se o seu GID é diferente de 1. Caso sim, então o personagem é posicionado sobre a célula identificada.
O resultado da implementação de hoje é um jogo de labirinto onde o jogador pode movimentar o personagem em turnos para células adjacentes que não são paredes. As Figuras 1 e 2 ilustram o personagem posicionado sobre o início e sobre o fim, respectivamente, após uma série de movimentações realizadas por mim. =]


Nesse tutorial nós implementamos a movimentação do personagem no labirinto. O personagem se move com base na direção onde o jogador encostou o dedo na tela em relação ao personagem. Além disso, o personagem se move somente se a célula para onde ele se movimentará não for parede.
Implementaremos no próximo tutorial o contador de passos do personagem e o término do jogo.
Um grande abraço e até mais. []