Tutorial: Desenvolvendo um Jogo de Labirinto – Parte 2: Movendo o Personagem

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. =]

Figura 1 - Personagem movimentado até o início do labirinto
Figura 1 – Personagem movimentado até o início do labirinto
Figura 2 - Personagem movimentado até o fim do labirinto
Figura 2 – Personagem movimentado até o fim do labirinto

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. []

Santiago Viertel

Formado em Bacharelado em Ciência da Computação (UDESC), mestre e doutorando em Análise de Algoritmos (UFPR). Foi programador da Céu Games por 8 anos. Possui a preferência por jogos de estratégia e de tiro em primeira pessoa. Jogando bastante DotA 2, Left 4 Dead 2 e Age of Empires II HD.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *