Tutorial: Programando um jogo da memória – Parte 3: Implementação da escolha das cartas

O nosso jogo da memória já está com a escolha aleatória das cartas e com o embaralhamento devidamente programados.

O jogador não tem nenhuma interação com o jogo… ainda.

Vamos implementar isso por meio da tela de toque.

No último tutorial nós vimos como escolher aleatoriamente quais empresas fariam parte do jogo corrente e também como embaralhar as cartas. Para isso, primeiramente, o jogo escolhia de forma aleatória três empresas desenvolvedoras de jogos eletrônicos e, posteriormente, ele embaralhava as cartas com diversas trocas de posições entre elas.

Nesse tutorial nós adicionaremos a interação do usuário com o jogo. Primeiramente o jogador poderá escolher uma carta e o jogo a virará para ele. Logo após, o jogador escolhe outra e o jogo mostrará a segunda carta para ele. Após o jogo mostrar as duas cartas, ele as virará novamente, sem fazer qualquer checagem de acerto ou erro. Partiu código …

Daremos início ao tutorial com a edição do arquivo “HelloWorldScene.h”. Vale lembrar que é necessário que você faça o tutorial passado para que você possa continuar nesse. Adicione as seguintes linhas de código:

int indiceCartaVirada1;

int indiceCartaVirada2;

void ccTouchesEnded(cocos2d::CCSet *pTouches,cocos2d::CCEvent *pEvent);

int verificaCarta(cocos2d::CCPoint ponto);

void mostraCarta1();

void viraCarta1();

void mostraCarta2();

void viraCarta2();

void acionaTelaDeToque();

logo abaixo dessa:

int valorCartas[6];

Note que adicionamos vários elementos novos para que possamos fazer as animações e a interação do jogador com o jogo. Primeiramente, atentamos às duas variáveis inteiras criadas: “indiceCartaVirada1” e “indiceCartaVirada2”. Elas precisam existir para sabermos, em qualquer momento, quais foram as duas cartas escolhidas pelo jogador. Ou seja, a função delas é armazenar os índices das cartas escolhidas. Se o jogador escolheu inicialmente a terceira carta, então o valor de “indiceCartaVirada1” será igual a 2, visto que um vetor se inicia na posição zero.

Nós incluímos também outros sete métodos. O “ccTouchesEnded” talvez já seja conhecido por vocês. Ele é chamado no momento que o jogador termina um toque na tela do aparelho. Eu criei o método “verificaCarta” com a função de identificar qual carta o jogador selecionou ao realizar um toque na tela. Ele recebe como parâmetro o ponto na tela onde o jogador encostou e devolve o índice da carta neste mesmo local. Os métodos “mostraCarta” e “viraCarta” servem, respectivamente, para mostrar ao jogador a carta que está escondida e para esconder do jogador a carta que está sendo mostrada. Obviamente, os índices 1 e 2 servem para definir se será mostrada ou virada a primeira carta escolhida ou a segunda carta escolhida. Por último, o método “acionaTelaDeToque” serve unicamente para voltar a acionar a tela de toque, que é desligada no momento que acontece as animações de carta girando. Salve o arquivo “HelloWorldScene.h”.

Agora realizaremos algumas modificações na nossa tela de testes criada no tutorial anterior, que mostrava todas as cartas ao jogador. Faremos com que todas as cartas iniciem viradas para baixo. Dessa forma, realize as seguintes modificações.

Na linha:

HelloWorld::cartas[0] = CCSprite::createWithSpriteFrameName(

  HelloWorld::nomes[HelloWorld::valorCartas[0]]);

modifique para:

HelloWorld::cartas[0] = CCSprite::createWithSpriteFrameName(“CartaVirada.png”);

Na linha:

HelloWorld::cartas[1] = CCSprite::createWithSpriteFrameName(

  HelloWorld::nomes[HelloWorld::valorCartas[1]]);

modifique para:

HelloWorld::cartas[1] = CCSprite::createWithSpriteFrameName(“CartaVirada.png”);

Na linha:

HelloWorld::cartas[2] = CCSprite::createWithSpriteFrameName(

  HelloWorld::nomes[HelloWorld::valorCartas[2]]);

modifique para:

HelloWorld::cartas[2] = CCSprite::createWithSpriteFrameName(“CartaVirada.png”);

Na linha:

HelloWorld::cartas[3] = CCSprite::createWithSpriteFrameName(

  HelloWorld::nomes[HelloWorld::valorCartas[3]]);

modifique para:

HelloWorld::cartas[3] = CCSprite::createWithSpriteFrameName(“CartaVirada.png”);

Na linha:

HelloWorld::cartas[4] = CCSprite::createWithSpriteFrameName(

  HelloWorld::nomes[HelloWorld::valorCartas[4]]);

modifique para:

HelloWorld::cartas[4] = CCSprite::createWithSpriteFrameName(“CartaVirada.png”);

Na linha:

HelloWorld::cartas[5] = CCSprite::createWithSpriteFrameName(

  HelloWorld::nomes[HelloWorld::valorCartas[5]]);

modifique para:

HelloWorld::cartas[5] = CCSprite::createWithSpriteFrameName(“CartaVirada.png”);

Com essas modificações, acabamos de virar todas as cartas para baixo. Não perderemos o embaralhamento realizado porque os valores dos índices das cartas estão todos armazenados no vetor “valorCartas”, este criado no último tutorial. Daremos continuidade com a inicialização das duas variáveis criadas nesse tutorial e com o acionamento da tela de toque. Insira as seguintes linhas de código:

HelloWorld::indiceCartaVirada1 = -1;

HelloWorld::indiceCartaVirada2 = -1;

setTouchEnabled(true);

logo abaixo dessa:

addChild(HelloWorld::cartas[5]);

Como o game inicia com todas as cartas viradas, então as variáveis “indiceCartaVirada” 1 e 2 são inicializadas com o valor -1. Isso porque o jogador ainda não escolheu nenhuma carta. Vamos começar com a explicação do principal método de interação com o jogo: o “ccTouchesEnded”. Adicione as seguintes linhas de código no final do arquivo:

void HelloWorld::ccTouchesEnded(CCSet *pTouches,CCEvent *pEvent) {

    int carta = HelloWorld::verificaCarta((static_cast<CCTouch*>(pTouches->anyObject()))->getLocationInView());

    if(carta!=-1) {

        if(HelloWorld::indiceCartaVirada1==-1) {

            setTouchEnabled(false);

            HelloWorld::indiceCartaVirada1 = carta;

            CCScaleTo* primeiraMetade = CCScaleTo::create(

              0.5,0.0,HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->getScale());

            CCCallFunc* mostraCarta1 = CCCallFunc::create(

              this,callfunc_selector(HelloWorld::mostraCarta1));

            CCScaleTo* segundaMetade = CCScaleTo::create(

              0.5,HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->getScale(),

            HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->getScale());

            CCCallFunc* telaDeToque = CCCallFunc::create(

              this,callfunc_selector(HelloWorld::acionaTelaDeToque));

            HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->runAction(

              CCSequence::create(primeiraMetade,mostraCarta1,segundaMetade,telaDeToque,NULL));

        }

        else if(carta!=HelloWorld::indiceCartaVirada1) {

            setTouchEnabled(false);

            HelloWorld::indiceCartaVirada2 = carta;

            CCScaleTo* primeiraMetade = CCScaleTo::create(

              0.5,0.0,HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->getScale());

            CCCallFunc* mostraCarta2 = CCCallFunc::create(

              this,callfunc_selector(HelloWorld::mostraCarta2));

            CCScaleTo* segundaMetade = CCScaleTo::create(

              0.5,HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->getScale(),

            HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->getScale());

            CCDelayTime* tempoChecagem = CCDelayTime::create(0.5);

            CCCallFunc* viraCarta2 = CCCallFunc::create(

              this,callfunc_selector(HelloWorld::viraCarta2));

            HelloWorld::cartas[HelloWorld::indiceCartaVirada2]->runAction(CCSequence::create(

              primeiraMetade,mostraCarta2,segundaMetade,tempoChecagem,

              primeiraMetade,viraCarta2,segundaMetade,NULL));

            CCDelayTime* tempoVirarCarta1 = CCDelayTime::create(1.5);

            CCCallFunc* viraCarta1 = CCCallFunc::create(

              this,callfunc_selector(HelloWorld::viraCarta1));

            CCCallFunc* telaDeToque = CCCallFunc::create(

              this,callfunc_selector(HelloWorld::acionaTelaDeToque));

            HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->runAction(CCSequence::create(

              tempoVirarCarta1,primeiraMetade->copy(),viraCarta1,segundaMetade->copy(),telaDeToque,NULL));

        }

    }

}

O método “ccTouchesEnded” primeiramente verifica se o jogador clicou em uma parte da tela que não tem nenhuma carta. Caso isso aconteça, o jogo não faz nada. Caso o jogador clique sobre qualquer carta, o método escolhe entre dois tratamentos: um que trata o toque na tela quando o jogador ainda não escolheu a primeira carta e outro que trata quando o jogador já escolheu a primeira carta.

Caso ocorra o primeiro evento, o jogo desabilita a tela de toque, preenche o valor da carta que o jogador escolheu na variável “indiceCartaVirada1” e realiza a sequência de animações: vira a metade da carta, troca a imagem da carta para que seja mostrada a logo que está posicionada nela e termina de virar a carta. Note que, ao final da sequência de animações, o jogo habilita novamente a tela de toque para que o jogador possa escolher a segunda carta.

Caso ocorra o segundo evento, o jogo desabilita a tela de toque, preenche o valor da carta que o jogador escolheu na variável “indiceCartaVirada2”, e realiza uma sequência de animações com duas cartas: a escolhida por primeiro e a escolhida por segundo. A sequência de animações da carta escolhida por segundo é a seguinte: vira a metade da carta, troca a imagem da carta para a logo que está posicionada nela, termina de virar a carta, espera meio segundo para o jogador comparar as duas cartas, vira a metade da carta, troca a imagem da carta para o verso e termina de virar a carta. A sequência de animações da carta escolhida por primeiro é mais simples: espera um segundo e meio para realizar a animação de virada da segunda carta escolhida, vira a metade da carta, troca a imagem da carta para o verso e termina de virar a carta. Note que no final dessa animação, o jogo habilita novamente a tela de toque.

A princípio, o método principal realiza várias chamadas aos métodos “verificaCarta”, “mostraCarta”, “viraCarta” e “acionaTelaDeToque”. Dessa forma, adicione a implementação desses métodos no final do arquivo:

int HelloWorld::verificaCarta(CCPoint ponto) {

    int i;

    ponto.y = CCDirector::sharedDirector()->getWinSize().height – ponto.y;

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

        if(HelloWorld::cartas[i]->boundingBox().containsPoint(ponto))

            return i;

    return -1;

}

void HelloWorld::mostraCarta1() {

    HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->setDisplayFrame(

    CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(

    HelloWorld::nomes[HelloWorld::valorCartas[HelloWorld::indiceCartaVirada1]]));

}

void HelloWorld::viraCarta1() {

    HelloWorld::cartas[HelloWorld::indiceCartaVirada1]->setDisplayFrame(

    CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“CartaVirada.png”));

    HelloWorld::indiceCartaVirada1 = -1;

}

void HelloWorld::mostraCarta2() {

    HelloWorld::cartas[HelloWorld::indiceCartaVirada2]->setDisplayFrame(

    CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(

    HelloWorld::nomes[HelloWorld::valorCartas[HelloWorld::indiceCartaVirada2]]));

}

void HelloWorld::viraCarta2() {

    HelloWorld::cartas[HelloWorld::indiceCartaVirada2]->setDisplayFrame(

    CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“CartaVirada.png”));

    HelloWorld::indiceCartaVirada2 = -1;

}

void HelloWorld::acionaTelaDeToque() {

    setTouchEnabled(true);

}

Todos esses métodos são simples de entender e deixo para vocês mesmo analisarem a lógica deles. Salve o arquivo “HelloWorldScene.cpp” e compile o código. Você verá que o jogo se comporta como mostrado na Figura 1. Quando o jogador escolhe uma carta, ela é virada e mostrada ao jogador. Quando o jogador escolhe a segunda carta, ela é virada, mostrada ao jogador e as duas cartas são escondidas do jogador.

Figura 1 - Jogo executando

Figura 1 – Jogo executando

Nesse tutorial nós incluímos a funcionalidade de interação do jogador com o game. Para isso, acionamos a tela de toque quando o jogador pode escolher a carta e a desligamos quando o jogo está no meio de uma animação. Separamos o tratamento de toque na tela em dois principais eventos: quando o jogador escolhe a primeira carta e no momento que o jogador escolhe a segunda. Realizamos as animações das cartas de acordo com o evento ocorrido. Não implementamos ainda o término do jogo e nem a checagem para saber se o jogador acertou as cartas escolhidas. Isso nós deixaremos para o próximo tutorial.

Um grande abraço e até mais. []

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