Tutorial: Desenvolvendo um Jogo de Batalha Naval em Cocos2d-x: Parte 3 – Respondendo aos toques na tela

Então nosso game de batalha naval em Cocos2d-x já cria cenários aleatoriamente a cada início de jogo. Porém, ainda não há nenhum tipo de interação.

Hoje implementaremos as funcionalidades de toque na tela.

Parte 1Parte 2 – Parte 3 – Parte 4

No último tutorial, nós geramos aleatoriamente o cenário com dois navios grandes, quatro médios e dois pequenos. Criamos posições e angulações aleatórias para cada um dos navios e, se ao posicionar, um navio estivesse sobre outro, nós o reposicionamos.

No tutorial de hoje, nós implementaremos as principais funcionalidades de resposta aos toques na tela. Iniciaremos o cenário com os navios (já posicionados) invisíveis e com todas as opções de lugares para atirar.

Caso o jogador encoste em uma célula (opção de tiro) que esconde um navio, o jogo retira todas as opções de tiro sob o navio abatido e o navio passa a ficar visível ao jogador.

Caso o jogador atire em uma opção que não tem navio, o jogo mostra um “X” na opção escolhida.

Mãos na massa.

 

Início do Jogo e Tela de Toque

navionamiraNo último tutorial, nós iniciamos os navios visíveis ao jogador para termos a certeza de que o cenário estava sendo criado aleatoriamente. Em um jogo de batalha naval, no entanto, os navios começam invisíveis ao jogador.

A primeira coisa que faremos no tutorial de hoje é deixar os navios já posicionados mas invisíveis. Para isso, abra o arquivo “HelloWorldScene.cpp”, e remova a seguinte linha de código:

HelloWorld::naviosG[i]->setVisible(true);

, a seguinte linha:

HelloWorld::naviosM[i]->setVisible(true);

e a seguinte linha:

HelloWorld::naviosP[i]->setVisible(true);

Isso já é o suficiente para que os navios iniciem invisíveis, dado que, ao criar as instâncias dos sprites dos navios, nós já os deixamos invisíveis. Se você não percebeu isso, veja no código adicionado no primeiro tutorial.

Agora iniciaremos a programação da resposta de toques na tela. Abra o arquivo “HelloWorldScene.h” e adicione a seguinte linha de código:

bool onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event);

logo abaixo dessa:

cocos2d::Sprite *naviosP[6];

Criamos na classe “HelloWorld” o protótipo do método responsável por realizar processamentos quando um toque na tela é iniciado. Porém, todos sabemos que o protótipo não é o suficiente. Assim sendo, salve o arquivo “HelloWorldScene.h”, abra o arquivo “HelloWorldScene.cpp” e adicione as seguintes linhas de código no final do arquivo.

bool HelloWorld::onTouchBegan(Touch *touch,Event *unused_event) {

}

Deixaremos a implementação do método “onTouchBegan” para a próxima seção. Agora instanciaremos e ativaremos um objeto gerenciador de toques na tela. No mesmo arquivo, adicione as seguintes linhas de código:

EventListenerTouchOneByOne* toqueNaTela = EventListenerTouchOneByOne::create();

toqueNaTela->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan,this);

getEventDispatcher()->addEventListenerWithSceneGraphPriority(toqueNaTela,this);

logo após essa:

HelloWorld::criaCenario();

Pronto … a tela de toque já está funcionando. Porém ainda não foi implementada nenhuma funcionalidade.

Bora para a próxima etapa.

 

Implementando a resposta de toques na tela

armanavalNos jogos de batalha naval comuns, os jogadores têm direito a tiros de forma intercalada. O primeiro jogador atira, depois o segundo e assim por diante. Caso um dos jogadores acertar uma embarcação, esse jogador tem direito a mais um tiro.

Se a embarcação ocupa mais de uma célula, ela poderá ser atingida mais de uma vez, dependendo do seu comprimento. Ao final, ganha quem acertar mais embarcações. A mecânica é simples.

O nosso jogo será um pouco diferente. Se uma embarcação grande for atingida, ela será abatida por inteiro e o jogador que acertou ganhará mais pontos em relação a uma embarcação menor. Essa será a única modificação que faremos no jogo padrão.

Não poderemos implementar tudo isso no tutorial de hoje, mas já faremos com que as embarcações sejam abatidas caso atingidas e mostraremos um “X” caso o jogador erre um tiro.

No arquivo “HelloWorldScene.cpp”, adicione as seguintes linhas de código:

int i,j,flag = 1;

int bpx,bpy;

Vec2 p = touch->getLocationInView();

p.y = Director::getInstance()->getVisibleSize().height – p.y;

for(i=0;i<2;i++)

    if(!HelloWorld::naviosG[i]->isVisible()&&HelloWorld::naviosG[i]->getBoundingBox().containsPoint(p)) {

        HelloWorld::naviosG[i]->setVisible(true);

        bpx = HelloWorld::naviosG[i]->getPositionX()/HelloWorld::grade[0][0]->getBoundingBox().size.width;

        bpy = 6 – HelloWorld::naviosG[i]->getPositionY()/HelloWorld::grade[0][0]->getBoundingBox().size.height;

        HelloWorld::grade[bpy][bpx]->setVisible(false);

        if(HelloWorld::naviosG[i]->getRotation()==0.0||HelloWorld::naviosG[i]->getRotation()==180.0) {

            HelloWorld::grade[bpy-1][bpx]->setVisible(false);

            HelloWorld::grade[bpy+1][bpx]->setVisible(false);

        } else {

            HelloWorld::grade[bpy][bpx-1]->setVisible(false);

            HelloWorld::grade[bpy][bpx+1]->setVisible(false);

        }

        flag = 0;

        i = 2;

    }

for(i=0;i<4;i++)

    if(!HelloWorld::naviosM[i]->isVisible()&&HelloWorld::naviosM[i]->getBoundingBox().containsPoint(p)) {

        HelloWorld::naviosM[i]->setVisible(true);

        bpx = HelloWorld::naviosM[i]->getPositionX()/HelloWorld::grade[0][0]->getBoundingBox().size.width;

        bpy = 6 – HelloWorld::naviosM[i]->getPositionY()/HelloWorld::grade[0][0]->getBoundingBox().size.height;

        HelloWorld::grade[bpy][bpx]->setVisible(false);

        if(HelloWorld::naviosM[i]->getRotation()==0.0||HelloWorld::naviosM[i]->getRotation()==180.0)

            HelloWorld::grade[bpy-1][bpx]->setVisible(false);

        else

            HelloWorld::grade[bpy][bpx-1]->setVisible(false);

        flag = 0;

        i = 4;

    }

for(i=0;i<6;i++)

    if(!HelloWorld::naviosP[i]->isVisible()&&HelloWorld::naviosP[i]->getBoundingBox().containsPoint(p)) {

        HelloWorld::naviosP[i]->setVisible(true);

        bpx = HelloWorld::naviosP[i]->getPositionX()/HelloWorld::grade[0][0]->getBoundingBox().size.width;

        bpy = 6 – HelloWorld::naviosP[i]->getPositionY()/HelloWorld::grade[0][0]->getBoundingBox().size.height;

        HelloWorld::grade[bpy][bpx]->setVisible(false);

        flag = 0;

        i = 6;

    }

if(flag==1) {

    bpx = p.x/HelloWorld::grade[0][0]->getBoundingBox().size.width;

    bpy = 6 – p.y/HelloWorld::grade[0][0]->getBoundingBox().size.height;

    if(HelloWorld::grade[bpy][bpx]->isVisible()&&HelloWorld::grade[bpy][bpx]->isFrameDisplayed(

      SpriteFrameCache::getInstance()->getSpriteFrameByName(“Opcao.png”))) {

        HelloWorld::grade[bpy][bpx]->setSpriteFrame(“Erro.png”);

    }

}

logo abaixo dessa:

bool HelloWorld::onTouchBegan(Touch *touch,Event *unused_event) {

Thats_all_folksA lógica não é muito complicada. Primeiramente nós verificamos se o ponto onde o jogador encostou o dedo na tela está sobre algum dos navios ainda não abatidos (invisíveis). Caso o jogador acerte algum deles, o jogo deixa o navio abatido visível e remove as opções de tiro que estão sob ele. Se o ponto onde o jogador encostou não está sobre nenhum navio ainda não abatido, o jogo muda a imagem do sprite de opção de tiro escolhido pelo jogador para um “X” vermelho. Simples assim. =]

Por hoje é só pessoal. Para os curiosos de plantão segue uma imagem do jogo executando. Note que alguns navios foram abatidos e que foram escolhidas algumas opções erradas.

Figura 1 - Jogo executando
Figura 1 – Jogo executando

O que fizemos hoje no Batalha Naval em Cocos2d?

Implementamos no tutorial de hoje as funcionalidades do toque na tela. Primeiramente deixamos os navios invisíveis. Depois nós criamos um objeto gerenciador de toques na tela. Por último, nós implementamos a lógica da resposta de toque na tela. Essa lógica consiste em identificar se o jogador encostou em algum navio ainda não abatido. Caso isso acontecer, o jogo mostra o navio abatido ao jogador e retira as opções de tiro sob o navio abatido. Caso o jogador não acerte nenhum navio, o jogo substitui o sprite que tem opção de tiro escolhido pelo jogador por um “X” informando que aquela opção já foi escolhida.

No próximo tutorial, nós implementaremos o sistema gerenciador de pontos. Faremos com que os jogadores tenham chances alternadas, faremos a contabilidade dos pontos e implementaremos 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 *