Tutorial: Criando um jogo ao estilo Robot Unicorn Attack – Parte 4: Plataformas aleatórias

Falta pouco para finalizarmos a implementação de mais um game.

As plataformas do nosso jogo já estão se movimentando, disponibilizando interação.

Agora faremos com que elas estejam em alturas diferentes.

Vimos no último tutorial como criar as plataformas e como adicionar um desafio ao jogo, movimentando as plataformas da direita para a esquerda. Para isso, tivemos que criar uma variável de tileset para que o jogo possua duas plataformas ao mesmo tempo na tela. Quando uma plataforma chegava ao fim, ela era reposicionada para o lado direto da tela e era adicionada uma animação que a movimentava para o outro lado da tela.

Nesse tutorial, nós faremos com que as plataformas sejam criadas em alturas aleatórias, de forma que o nosso personagem jogável consiga alcançá-las durante o salto. Além de adicionarmos imprevisibilidade ao jogo, nós animaremos o sprite do Sonic (créditos a SEGA) de forma que ele corra sobre as plataformas e mude o sprite frame quando ele pula. Partiu.

Inicialmente, realizaremos a única modificação necessária no arquivo “HelloWorldScene.h”. Será adicionada uma variável que armazena valores lógicos com o intuito de modificar o sprite frame do Sonic quando o jogador solta o dedo da tela. Essa modificação consiste em adicionar a seguinte linha de código:

bool salto;

logo abaixo dessa:

float tempoCorrido;

Salve esse arquivo e abra o arquivo “HelloWorldScene.cpp”. Primeiramente, realizaremos uma edição no código que fará com que a mudança de sprite frame do Sonic não afete o sistema de detecção de colisão com o chão que implementamos no segundo tutorial. Como assim? Quando nós trocamos a imagem do sprite do personagem jogável, ele aumenta a sua altura. Isso faz com que, quando o jogador realize um salto, o sistema de colisão detecte colisão com o chão antes mesmo do personagem sair da plataforma. Quando isso acontece, o jogo acaba fazendo com que o Sonic não salte. Para solucionar esse problema, basta posicionar o ponto âncora do sprite na parte central inferior. Isso fará com que o Sonic sempre esteja posicionado logo acima da plataforma, independente se houver uma troca de sprite frame. Seguem as modificações necessárias para adequar a versão atual do game com essa nova configuração de ponto âncora. Adicione a seguinte linha de código:

sonic->setAnchorPoint(ccp(0.5,0.0));

logo abaixo dessa:

sonic->setScale((0.1*size.height)/sonic->boundingBox().size.height);

Agora modifique a seguinte linha de código:

plataforma->setPosition(ccp(size.width/5,size.height/2-plataforma->boundingBox().size.height-sonic->boundingBox().size.height/2));

de forma que ela fique assim:

plataforma->setPosition(ccp(size.width/5,size.height/2-plataforma->boundingBox().size.height));

Da mesma forma, modifique a seguinte linha de código:

HelloWorld::posicaoYInicial = plat->getPositionY()+plat->boundingBox().size.height+HelloWorld::sonic->boundingBox().size.height/2;

deixando ela assim:

HelloWorld::posicaoYInicial = plat->getPositionY()+plat->boundingBox().size.height;

Na primeira modificação, nós posicionamos o ponto âncora do sprite do Sonic na posição central inferior. Na segunda modificação, nós posicionamos a primeira plataforma logo abaixo do Sonic. Notem que, pelo fato do ponto âncora ter sido modificado, não se faz mais necessário adicionar metade da altura do sprite, como fazíamos anteriormente. Na terceira modificação, nós também retiramos a soma da metade da altura do sprite do Sonic.

Continuando, faremos com que as plataformas sejam criadas em alturas aleatórias, o principal objetivo desse tutorial. Na verdade, são poucas as modificações necessárias para isso. Começaremos adicionando as seguintes linhas de código:

float altura,delta = 3.5;

static unsigned int r = time(NULL);

srand(r);

r = rand();

altura = (((float)r)/RAND_MAX)*delta – delta/2;

logo abaixo dessas:

else

    plat = HelloWorld::plataforma2;

Para concluir a implementação dessa funcionalidade, modifique a seguinte linha de código:

plat->setPosition(ccp(size.width,plat->getPositionY()));

de forma que ela fique assim:

plat->setPosition(ccp(size.width,size.height/2+altura*HelloWorld::sonic->boundingBox().size.height));

Isso é o suficiente para que as plataformas sejam criadas em alturas aleatórias. Note que, primeiramente, nós sorteamos um número aleatório que varia de -1,75 até 1,75 e o armazenamos na variável “altura”. Logo após, nós o multiplicamos pelo valor da altura do sprite do Sonic e adicionamos com a metade do valor da altura da tela, sendo esse o ponto referência para o posicionamento da plataforma. Isso fará com que elas sejam posicionadas em alturas que o jogador poderá alcançar com os saltos do Sonic.

Agora realizaremos uma sequência de modificações com o intuito de adicionar a animação do Sonic correndo e a mudança de sprite frame quando ele pula. Começaremos adicionando as seguintes linhas de código:

CCArray* spriteFrames = CCArray::create();

spriteFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“SonicCorrendo1.png”));

spriteFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“SonicCorrendo2.png”));

spriteFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“SonicCorrendo3.png”));

spriteFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“SonicCorrendo2.png”));

HelloWorld::sonic->runAction(CCRepeatForever::create(CCAnimate::create(

  CCAnimation::createWithSpriteFrames(spriteFrames,0.1))));

logo abaixo dessa:

CCMoveTo::create(dist/VELOCIDADE,ccp(plataforma2->getPositionX()-dist,plataforma2->getPositionY())),chao,NULL));

e dessa:

if(plat!=NULL) {

Essas duas inclusões fará com que o Sonic inicie correndo sobre a primeira plataforma e comece a correr toda vez que ele cai sobre uma plataforma, após um salto. Não obstante, faremos com que ele mude para o sprite frame de salto quando o jogador salta. Se você abrir os arquivos de sprite frame que você baixou no primeiro tutorial, notará que temos dois sprite frames para salto: um que o Sonic está com a mão levantada e outro que ele está com ela um pouco mais abaixada. Faremos com que o primeiro sprite frame seja mostrado enquanto o jogador está com o dedo encostado na tela, e o segundo seja mostrado quando o jogador desencosta da tela. Para isso, adicione as seguintes linhas de código:

HelloWorld::sonic->cleanup();

HelloWorld::sonic->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“SonicSaltando1.png”));

logo abaixo dessa:

if(HelloWorld::gravidade==0.0) {

Adicione, também, a seguinte linha de código:

HelloWorld::sonic->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“SonicSaltando2.png”));

logo abaixo dessa:

if(HelloWorld::gravidade==-20.0*HelloWorld::sonic->boundingBox().size.height) {

Note que, fazemos com que o sprite do Sonic mude para o sprite frame nomeado “SonicSaltando1.png” quando o jogador encosta o dedo na tela e modificamos para o sprite frame nomeado “SonicSaltando2.png” quando ele tira o dedo da tela. Relembrando, o sprite frame nomeado “SonicSaltando1.png” corresponde àquele que o Sonic está com a mão mais levantada.

Se você for atencioso, perceberá que nós ainda não mexemos na variável que criamos no arquivo “HelloWorldScene.h”. As últimas edições desse tutorial consiste na manipulação dela. Começaremos com a sua inicialização, adicionando a seguinte linha de código:

HelloWorld::salto = false;

logo ACIMA dessa:

setTouchEnabled(true);

Agora vamos realizar as modificações de valores dela, fazendo com que ela armazene verdadeiro, caso o jogador inicie um salto, e armazene falso, quando o jogador tira o dedo da tela. Para isso, adicione a seguinte linha de código:

HelloWorld::salto = true;

logo abaixo dessas:

HelloWorld::velocidadeYInicial = 13*HelloWorld::sonic->boundingBox().size.height;

HelloWorld::tempoCorrido = 0.0;

e adicione a seguinte linha de código:

HelloWorld::salto = false;

logo abaixo dessas:

HelloWorld::velocidadeYInicial += HelloWorld::gravidade*HelloWorld::tempoCorrido;

HelloWorld::gravidade = -40*HelloWorld::sonic->boundingBox().size.height;

HelloWorld::posicaoYInicial = HelloWorld::sonic->getPositionY();

HelloWorld::tempoCorrido = 0.0;

Para finalizar, vamos adicionar a principal função da variável “salto”: verificar se o Sonic está no meio de um salto quando o jogador tira o dedo da tela. Para isso, modifique a seguinte linha de código:

if(HelloWorld::gravidade==-20.0*HelloWorld::sonic->boundingBox().size.height) {

de forma que ela fique assim:

if(HelloWorld::salto) {

Proooonto … basta compilar e executar o game para ver que o Sonic está animando quando corre sobre uma plataforma e ele muda de sprite frame quando salta. Perceba que, enquanto o jogador está com o dedo encostado na tela, o Sonic fica com um sprite frame e quando o jogador solta o dedo, ele muda para outro. Além disso, as plataformas iniciam em alturas aleatórias. Agora o jogo está com uma cara mais “profissional”. =] Aos curiosos de plantão, a animação a seguir ilustra o jogo em execução.

Vimos nesse tutorial como fazer com que as plataformas sejam criadas em alturas aleatórias. Para isso, precisávamos sortear um número aleatório e fazer com que a altura inicial das plataformas iniciasse com base nesse número.

Também adicionamos as animações do Sonic correndo e pulando.

No próximo tutorial nós adicionaremos os elementos de HUD e a programação do 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.