Tutorial: Desenvolvendo um jogo de guiar bolinha em labirinto – Parte 5: Adicionando as bocas

Nosso game de guiar a bolinha no labirinto já está quase pronto.

Para terminarmos, basta incluirmos as bocas que a bola cai.

Vamos terminar mais esse desafio?

No último tutorial nós colamos imagens em cada objeto rígido como se fossem figurinhas. Deixamos o nosso cenário bem legal, com aspecto de um labirinto de madeira com uma bola de aço sobre esse labirinto. Nesse tutorial, daremos término ao desenvolvimento do jogo com a inclusão das bocas: são elas que fazem o jogador perder se a bolinha de aço cair nelas e as bocas que fazem o jogador ganhar.

 

Adicionando as bocas

Nesse tipo de jogo, é normal que hajam dois tipos diferentes de bocas: aquelas que se a bolinha de aço cair você perde o jogo e, aquelas que se a bolinha de aço cair você ganha o jogo. Na verdade, a única forma de terminar uma fase é fazendo a bolinha cair em alguma dessas bocas. Implementaremos no nosso game várias bocas que fazem o jogador perder e somente uma única boca como objetivo final e que faz o jogador ganhar.

Notem que no tutorial passado nós não incluímos qualquer sprite frame que representa as bocas. Dessa forma, precisamos incluir dois novos sprites frames no nosso sprite sheet: um para a boca “certa” e outro para a boca “errada”. Para isso, baixem esse arquivo e o descompacte na pasta “Resources”. Substitua os dois arquivos de sprite sheet que copiamos no tutorial anterior. Para vocês saberem o que fizemos agora, acabamos de adicionar um novo sprite sheet que contém todos os sprites frames do tutorial passado adicionados com esses dois novos que representam as bocas. Se você está “boiando” nesses termos (sprite frame e sprite sheet) ou quer saber como eu criei esses arquivos, leia esse tutorial.

Adicionados os novos sprite frames, agora podemos incluir as bocas no nosso game. Como exemplo, adicionaremos três bocas que fazem o jogador perder e uma boca objetivo. As bocas que devem ser evitadas estarão uma no canto inferior esquerdo, outra no canto superior esquerdo e outra no canto superior direito. A boca que deve ser alcançada pelo jogador ficará no canto inferior direito. Para fazer isso, adicionaremos quatro novos sprites no cenário, um representando cada boca. Codificando isso, abra o arquivo “HelloWorldScene.h” e adicione as seguintes linhas de código:

cocos2d::CCSprite* bocasErradas[3];

cocos2d::CCSprite* bocaCerta;

logo abaixo dessa linha:

cocos2d::CCSprite* bolinhaSprite;

Essas modificações já são suficientes nesse arquivo. Agora abra o arquivo “HelloWorldScene.cpp” e adicione as seguintes linhas de código:

HelloWorld::bocasErradas[0] = CCSprite::createWithSpriteFrameName(“BocaErrada.png”);

HelloWorld::bocasErradas[0]->setPosition(ccp(size.width/2 – 213 + HelloWorld::bocasErradas[0]->boundingBox().size.width/2,size.height/2 – 160 + HelloWorld::bocasErradas[0]->boundingBox().size.width/2));

addChild(HelloWorld::bocasErradas[0]);

HelloWorld::bocasErradas[1] = CCSprite::createWithSpriteFrameName(“BocaErrada.png”);

HelloWorld::bocasErradas[1]->setPosition(ccp(size.width/2 – 213 + HelloWorld::bocasErradas[1]->boundingBox().size.width/2,size.height/2 + 160 – HelloWorld::bocasErradas[1]->boundingBox().size.width/2));

addChild(HelloWorld::bocasErradas[1]);

HelloWorld::bocasErradas[2] = CCSprite::createWithSpriteFrameName(“BocaErrada.png”);

HelloWorld::bocasErradas[2]->setPosition(ccp(size.width/2 + 213 – HelloWorld::bocasErradas[2]->boundingBox().size.width/2,size.height/2 + 160 – HelloWorld::bocasErradas[2]->boundingBox().size.width/2));

addChild(HelloWorld::bocasErradas[2]);

HelloWorld::bocaCerta = CCSprite::createWithSpriteFrameName(“BocaCerta.png”);

HelloWorld::bocaCerta->setPosition(ccp(size.width/2 + 213 – HelloWorld::bocaCerta->boundingBox().size.width/2,size.height/2 – 160 + HelloWorld::bocaCerta->boundingBox().size.width/2));

addChild(HelloWorld::bocaCerta);

logo abaixo dessa linha:

addChild(fundoSprite);

Notem que criamos quatro novo sprites: três para as bocas que o jogador deve evitar e um para a boca que o jogador deve levar a bola. Após criarmos, nós posicionamos cada boca no seu respectivo lugar, exatamente como falei antes. Para terminar, adicionamos os quatro sprites como filhos da camada “HelloWorld”, fazendo com que eles apareçam na tela do aparelho. Se você executar o jogo nesse momento, você verá o que é mostrado na Figura 1 (notem que eu retirei o debug draw). Nessa figura, vocês podem ver que as bocas a serem evitadas estão circundadas de vermelho e a boca objetivo está circundada de verde. Ainda está faltando uma coisa, que é a principal: adicionar as funcionalidades das bocas.

Figura 1 - Jogo executando com as bocas

Figura 1 – Jogo executando com as bocas

 

Incluindo as funcionalidades nas bocas

Nesse momento, se você passar a bola de aço sobre as bocas, nada acontecerá. Isso porque elas aparecem graficamente, mas não têm nenhuma funcionalidade implementada. Para isso, precisamos fazer que o jogo reaja de uma forma, se a bola de aço cair em uma boca a ser evitada, e reaja de outra forma, se a bola de aço cair na boca objetivo. Nesse nosso game, apenas pararemos o jogo se a bola cair em qualquer boca e avisaremos na tela se o jogador perdeu ou se ele ganhou. Para incluirmos essas funcionalidades, abra o arquivo “HelloWorldScene.cpp” e adicione essas linhas de código:

float pBolaX = HelloWorld::bolinhaSprite->getPosition().x;

float pBolaY = HelloWorld::bolinhaSprite->getPosition().y;

float pBocaX;

float pBocaY;

CCSize size = CCDirector::sharedDirector()->getWinSize();

for(int i=0;i<3;i++) {

    pBocaX = HelloWorld::bocasErradas[i]->getPosition().x;

    pBocaY = HelloWorld::bocasErradas[i]->getPosition().y;

    if((pBocaX-pBolaX)*(pBocaX-pBolaX) + (pBocaY-pBolaY)*(pBocaY-pBolaY)<400.0) {

        cleanup();

        CCLabelTTF* label = CCLabelTTF::create(“Voce perdeu!”,“”,40);

        label->setColor(ccc3(0,0,0));

        label->setPosition(ccp(size.width/2,size.height/2));

        addChild(label);

    }

}

pBocaX = HelloWorld::bocaCerta->getPosition().x;

pBocaY = HelloWorld::bocaCerta->getPosition().y;

if((pBocaX-pBolaX)*(pBocaX-pBolaX) + (pBocaY-pBolaY)*(pBocaY-pBolaY)<400.0) {

    cleanup();

    CCLabelTTF* label = CCLabelTTF::create(“Voce ganhou!”,“”,40);

    label->setColor(ccc3(0,0,0));

    label->setPosition(ccp(size.width/2,size.height/2));

    addChild(label);

}

logo abaixo dessa linha:

HelloWorld::bolinhaSprite->setPosition(ccp(HelloWorld::bolinha->GetPosition().x*PTM_RATIO,HelloWorld::bolinha->GetPosition().y*PTM_RATIO));

O que fizemos nessas novas linhas de código adicionadas? Note que incluímos duas novas checagens, uma para identificar se a bolinha de aço caiu em uma boca a ser evitada e uma para identificar se a bolinha caiu na boca objetivo. Essas checagens são feitas por meio de cálculos de distâncias. Caso a bolinha esteja a uma distância menor do que 20 pixels (isso porque o quadrado de 20 é igual a 400, como pode ser visto no código) de uma boca, o jogo identifica isso como “a bola caiu na boca”. É possível ver que essas checagens são feitas para cada uma das bocas, para as três bocas a serem evitadas e para a boca objetivo. Note que, independente em qual boca cair, a função “cleanup” é chamada, dando término ao game. Dependendo de onde a bola cair, será mostrado na tela “Você perdeu!” ou “Você ganhou!”.
Para finalizar o desenvolvimento desse game, retire o debug draw para que não sejam mostradas na tela quaisquer informações sobre os objetos rígidos do Box2D. Para isso, é suficiente comentar (adicionar duas barras no início da linha “//”) a seguinte linha de código:

addChild(HelloWorld::debugDrawLayer,9999);

As Figuras 2 e 3 mostram, respectivamente, quando o jogador ganha e quando o jogador perde o jogo.

Figura 2 - Momento quando o jogador vence

Figura 2 – Momento quando o jogador vence

Figura 3 - Momento quando o jogador perde

Figura 3 – Momento quando o jogador perde

 

Nesse tutorial nós fizemos as últimas modificações necessárias no nosso game de guiar a bolinha no labirinto de madeira. Vimos como adicionar as bocas no nosso cenário e incluímos as funcionalidades para que o game tenha término.

Fizemos nessa sequência de tutoriais um jogo similar ao aTilt (créditos à FridgeCat Software) e vale lembrar que ninguém do blog Fábrica de Jogos e nem o próprio blog estão ganhando dinheiro com o game aqui desenvolvido. Esse jogo apenas nos serviu como um bom exemplo e com propósitos didáticos.

No próximo tutorial será quebrada essa sequência, visto que acabamos por aqui o desenvolvimento desse game. Veremos como criar menus no Cocos2d-x. Isso não é algo trivial e merece a nossa devida atenção para que possamos fazer jogos de qualidade.

Um grande abraço pessoal e até o próximo tutorial. []

Santiago Viertel

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