Tutorial: Desenvolvendo um jogo ao estilo Duck Hunt: Parte 4 – HUDs e término do jogo

Olá pessoal, o nosso jogo ao estilo Duck Hunt já está quase pronto.

Já programamos praticamente toda a sua mecânica.

Nesse tutorial, vamos finalizar esse jogo incluindo os elementos de HUD.

Parte 1Parte 2Parte 3 – Parte 4

Vimos no último tutorial como programar o sistema de toque na tela e a resposta aos toques. Toda vez que o jogador encosta em um balão que está passando na tela, esse balão é estourado. Para esse sistema funcionar, nós precisamos de uma lista de sprites de balão para que seja possível detectar quando o jogador encosta sobre um balão e identificar qual foi.

Nesse tutorial, nós adicionaremos elementos de HUD que mostram a pontuação ao jogador e implementaremos o término do jogo. Os elementos de HUD pertencentes à pontuação são: uma etiqueta que mostra a quantidade de balões estourados e uma etiqueta de mostra a quantidade de tentativas executadas pelo jogador. Então, faremos com que o jogo termine após passar um total de 30 segundos. Isso requisita outro elemento de HUD que mostra quanto tempo o jogador ainda tem de jogo.

Mãos na massa.

HUDs de pontuação

scorePara que seja possível criar dois elementos de HUD que funcionem, precisamos armazenar os valores que eles apresentam em algum lugar. Além isso, precisamos ter em mãos as referências das etiquetas que mostram as informações na tela, para que possamos modificar os valores quando necessário.

Precisaremos, então, declarar na classe “HelloWorld” duas variáveis que armazenam valores inteiros. Uma correspondente a quantidade de balões estourados e outra correspondente a quantidade de tentativas executadas pelo jogador. Precisaremos declarar, também, duas variáveis que armazenam a referência de duas etiquetas de HUD. Assim, abra o arquivo “HelloWorldScene.h” e adicione as seguintes linhas de código:

int tnt;

int ptn;

cocos2d::Label* tntTexto;

cocos2d::Label* ptnTexto;

logo abaixo dessa:

std::list<cocos2d::Sprite*> baloes;

Agora que as variáveis estão devidamente declaradas, precisaremos inicializá-las. Faremos com que as variáveis de pontuação armazenem o valor inicial zero, instanciaremos as duas etiquetas na memória e as incluiremos na tela. Para fazer isso tudo, abra o arquivo “HelloWorldScene.cpp” e adicione as seguintes linhas de código:

HelloWorld::tnt = 0;

HelloWorld::ptn = 0;

HelloWorld::tntTexto = Label::createWithTTF(“Tentativas: 0″,”fonts/Marker Felt.ttf”,30);

HelloWorld::tntTexto->setPosition(Vec2(visibleSize.width/2,visibleSize.height));

HelloWorld::tntTexto->setAnchorPoint(Vec2(0.5,1));

HelloWorld::tntTexto->setTextColor(Color4B::BLACK);

addChild(HelloWorld::tntTexto,1);

HelloWorld::ptnTexto = Label::createWithTTF(“Pontos: 0″,”fonts/Marker Felt.ttf”,30);

HelloWorld::ptnTexto->setPosition(Vec2((3*visibleSize.width)/4,visibleSize.height));

HelloWorld::ptnTexto->setAnchorPoint(Vec2(0.5,1));

HelloWorld::ptnTexto->setTextColor(Color4B::BLACK);

addChild(HelloWorld::ptnTexto,1);

logo abaixo dessa:

addChild(fundo);

Vale lembrar que deixamos as etiquetas com a coloração preta, pois o fundo do jogo é claro e fica ruim de enxergar com a cloração padrão. Também é importante dizer que as etiquetas estão com a fonte “Marker Felt”, que já vem por padrão nos arquivos do projeto Cocos2d-x.

congeladoCom isso, nós já temos na tela os elementos de HUD responsáveis por informar a pontuação ao jogador. Porém, esses elementos estão estáticos. Isso significa que, caso o jogador realize um toque na tela ou exploda algum balão, os elementos de HUD não são atualizados. Portanto, para atualizar a quantidade de tentativas do jogador, adicione as seguintes linhas de código:

char txt[16];

HelloWorld::tnt++;

sprintf(txt,”Tentativas: %i”,HelloWorld::tnt);

HelloWorld::tntTexto->setString(txt);

logo abaixo dessa:

p.y = visibleSize.height – p.y;

Para atualizar a quantidade de balões estourados, adicione as seguintes linhas de código:

HelloWorld::ptn++;

sprintf(txt,”Pontos: %i”,HelloWorld::ptn);

HelloWorld::ptnTexto->setString(txt);

logo abaixo dessa:

if(s->getBoundingBox().containsPoint(p)) {

Pronto. Com essas modificações no código nós acabamos de implementar o sistema de HUDs de pontuação. Se você executar o jogo, perceberá que o número de tentativas será incrementado se o jogador encostar o dedo em qualquer parte da tela. Além disso, o número de pontos será incrementado se o jogador conseguir estourar um balão.

HUDs de tempo e término de jogo

NoUm dos pontos cruciais que definem o término do jogo é a incapacidade do jogador fazer qualquer interação. Quando o jogo termina, é necessário desativar a tela de toque. Para isso, precisamos ter a referência do objeto ouvinte criado no tutorial passado. Assim, precisamos criar um atributo na classe “HelloWorld” que armazena tal informação. Para isso, abra o arquivo “HelloWorldScene.h” e adicione a seguinte linha de código:

cocos2d::EventListenerTouchOneByOne* listener;

logo abaixo dessa:

cocos2d::Label* ptnTexto;

Agora, para que seja armazenada a referência nessa variável recém-declarada, abra o arquivo “HelloWorldScene.cpp” e modifique a seguinte linha de código:

EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();

de forma que ela fique assim:

listener = EventListenerTouchOneByOne::create();

Nós não modificamos nada em relação a tela de toque. O que foi feito serve apenas para podermos desativá-la posteriormente. Tal momento acontece quando o jogo for finalizado. O jogo é finalizado após decorrer um total de 30 segundos, partindo do início da aplicação. Nesse período, a tela de toque fica ativa e o jogador pode estourar os balões que passam na tela. Percebe-se, então, a necessidade de inclusão de mais um elemento de HUD: um cronômetro para fim de jogo.

Como de praxe, nós precisamos de mais uma etiqueta e de sua referência para que o seu texto possa ser atualizado a cada segundo. Para declarar um atributo na classe “HelloWorld” que armazena a referência desse novo elemento de HUD, abra o arquivo “HelloWorldScene.h” e adicione a seguinte linha de código:

cocos2d::Label* tempo;

logo abaixo dessa:

cocos2d::EventListenerTouchOneByOne* listener;

forgetEssa nova etiqueta também precisa ser instanciada na memória e incluída na tela. Para isso, abra o arquivo “HelloWorldScene.cpp” e adicione as seguintes linhas de código:

HelloWorld::tempo = Label::createWithTTF(“Tempo: 30″,”fonts/Marker Felt.ttf”,30);

HelloWorld::tempo->setPosition(Vec2(visibleSize.width/4,visibleSize.height));

HelloWorld::tempo->setAnchorPoint(Vec2(0.5,1));

HelloWorld::tempo->setTextColor(Color4B::BLACK);

addChild(HelloWorld::tempo,1);

logo abaixo dessa:

addChild(HelloWorld::ptnTexto,1);

Se você executar o jogo, perceberá que isso não fará com que o jogo termine após decorrer 30 segundos. Muito menos o cronômetro funcionará. Note que o elemento de HUD está estático. Para que o texto dessa etiqueta seja editado corretamente, é necessário implementar um método que realiza essa edição a cada segundo. Chamaremos esse método de “reduzSegundo”. Mas, antes de tudo, precisamos declará-lo na classe “HelloWorld”. Abra o arquivo “HelloWorldScene.h” e adicione a seguinte linha de código:

void reduzSegundo(float dt);

logo abaixo dessa:

cocos2d::Label* tempo;

O método “reduzSegundo” possui a função de, a cada segundo, modificar o texto que a etiqueta de cronômetro apresenta ao jogador. Nota-se, também, que esse método possui outras funções. Além de modificar a etiqueta a cada segundo, ele também precisa verificar se os 30 segundos já acabaram. Caso isso aconteça, o método deve finalizar o jogo.

Figura 1 - Gameplay
Figura 1 – Gameplay

Os procedimentos de finalização do jogo têm três tarefas. Uma delas é a paralisação de todos os sprites de balão. Outra é a apresentação de um novo elemento de HUD que informa o término do jogo.  E a ultima, faz o reposicionamento no centro da tela dos elementos de HUD referentes a pontuação do jogador. Para implementar o método “reduzSegundo”, adicione as seguintes linhas de código no final do arquivo “HelloWorldScene.cpp”.

void HelloWorld::reduzSegundo(float dt) {

    static int tmp = 30;

    tmp–;

    if(tmp>=0) {

        char txt[10];

        sprintf(txt,”Tempo: %i”,tmp);

        HelloWorld::tempo->setString(txt);

    } else {

        Size visibleSize = Director::getInstance()->getVisibleSize();

        HelloWorld::listener->setEnabled(false);

        cleanup();

        Label* fdj = Label::createWithTTF(“Fim de Jogo”,”fonts/Marker Felt.ttf”,50);

        fdj->setPosition(Vec2(visibleSize.width/2,(3*visibleSize.height)/4));

        fdj->setTextColor(Color4B::BLACK);

        addChild(fdj,1);

        HelloWorld::tntTexto->setPosition(Vec2(

          visibleSize.width/2,visibleSize.height/2+HelloWorld::tntTexto->getBoundingBox().size.height/2));

        HelloWorld::ptnTexto->setPosition(Vec2(

          visibleSize.width/2,visibleSize.height/4+HelloWorld::ptnTexto->getBoundingBox().size.height/2));

        removeChild(HelloWorld::tempo);

    }

}

A declaração e implementação do método “reduzSegundo” não garante que a etiqueta de cronômetro seja atualizada a cada segundo e nem que jogo seja finalizado. Para que isso aconteça, é necessário programar a execução desse método a cada segundo. Para isso, adicione a seguinte linha de código:

schedule(schedule_selector(HelloWorld::reduzSegundo),1);

logo abaixo dessa:

schedule(schedule_selector(HelloWorld::entraNovoBalao),0.5);

Figura 2 - Término de jogo
Figura 2 – Término de jogo

Pronto. Agora é só compilar e ver o resultado. Note que, a cada clique na tela, é somado em um no número de tentativas. Também é somada a pontuação em um, caso o jogador acerte o clique sobre um balão, fazendo com ele estoure. Também é possível ver que, após decorrer 30 segundos, o jogo é finalizado. Quando isso acontece, a tela de toque é desativada e é informado ao jogador que o jogo terminou e mostra a pontuação dele. Curiosos de plantão já podem ver como ficou o gameplay na Figura 1, como ficou a tela de término de jogo na Figura 2 e também conferir a execução do jogo no vídeo a seguir.


Vimos no tutorial de hoje como incluir os elementos de HUD pertencentes à pontuação do jogador. Também vimos como o jogo é finalizado e adicionamos outro elemento de HUD referente ao cronômetro. Com o correto funcionamento desses elementos gráficos e com o término do jogo implementado, terminamos o desenvolvimento de mais um jogo. Weee.

No próximo tutorial, eu darei início a uma sequência de tutoriais que mostrarão como configurar o ambiente de desenvolvimento para Android com Cocos2d-x no Linux Debian. Atendendo a algumas requisições dos nossos fiéis leitores. Vocês não perdem por esperar. =]

Um grande abraço. []

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.

Send this to a friend