Tutorial: Criando um jogo ao estilo Robot Unicorn Attack – Parte 2: Saltos e colisão com o chão

Iniciamos a criação de um jogo ao estilo Robot Unicorn Attack.

Vimos como o jogo ficará no final, porém ainda não implementamos qualquer funcionalidade.

Começaremos a programação para termos alguma jogabilidade inicial.

Criamos no último tutorial o projeto do nosso próximo game. Adicionamos os arquivos de sprite sheet e tile set e vimos como o jogo ficará quando estiver executando. Nesse tutorial, nós incluiremos a funcionalidade que faz com que o Sonic (créditos a SEGA) salte quando o jogador clicar na tela. Além disso, adicionaremos a gravidade de forma que ele também caia. Para que ele não vá em direção ao infinito, adicionaremos também o tratamento de colisão específico entre o personagem jogável e o chão.

Primeiramente, vamos adicionar na classe HelloWorld todas as variáveis necessárias para a nossa simulação. Para isso, abra o arquivo “HelloWorldScene.h” e, logo abaixo dessa linha de código,

static cocos2d::CCScene* scene();

adicione essas linhas:

float gravidade;

float posicaoYInicial;

float velocidadeYInicial;

float tempoCorrido;

cocos2d::CCSprite* sonic;

cocos2d::CCTMXTiledMap* plataforma;

Note que declaramos quatro variáveis que armazenam valores reais e duas variáveis que fazem referência a dois objetos gráficos do nosso jogo. As quatro variáveis reais existem porque faremos uma simulação física de gravidade utilizando alguns conceitos de movimento uniformemente variado. Optei por reimplementar a física e não utilizar o motor físico Box2D para eu mostrar uma boa aplicação daquela Física que você viu no Ensino Médio.

Relembrando, as variáveis existentes no movimento uniformemente variado são: posição inicial (S0), posição final (S), velocidade inicial (V0), velocidade final (V), aceleração (a) e tempo (t). Para o nosso problema, são suficientes declarar apenas as variáveis: aceleração (gravidade, no nosso exemplo), posição inicial, velocidade inicial e tempo. Também adicionamos uma referência ao sprite do Sonic e uma ao tiled map da plataforma. Isso porque, a cada novo quadro mostrado, faremos modificações na posição do Sonic e utilizaremos informações da plataforma para isso.

Ainda no mesmo arquivo, adicione as seguintes linhas de código logo abaixo das declarações de variáveis realizadas anteriormente.

void atualiza(float dt);

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

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

Acabamos de declarar os protótipos dos métodos necessários para realizar a simulação física desejada. O método “atualiza” será chamado para modificar a cena a cada novo quadro processado, o método “ccTouchesBegan” será chamado quando o jogador iniciar um toque na tela e o método “ccTouchesEnded” será chamado quando o jogador terminar o toque na tela. Precisamos desses dois métodos de tratamento de toques porque faremos com que o Sonic pule mais alto quando o jogador segurar o dedo na tela do que quando o jogador apenas encostar rapidamente. Salve o arquivo “HelloWorldScene.h”.

Agora modificaremos algumas linhas de código no arquivo “HelloWorldScene.cpp”, para que tenhamos a referência do sprite do Sonic e do tiled map da plataforma quando precisarmos. Abra esse arquivo e modifique a seguinte linha de código:

CCSprite* sonic = CCSprite::createWithSpriteFrameName(“SonicCorrendo1.png”);

para isso:

sonic = CCSprite::createWithSpriteFrameName(“SonicCorrendo1.png”);

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

CCTMXTiledMap* plataforma = CCTMXTiledMap::create(“plataforma.tmx”);

para isso:

plataforma = CCTMXTiledMap::create(“plataforma.tmx”);

Agora iniciaremos a inclusão de código que implementa a física que desejamos. Primeiramente, vamos inicializar as variáveis físicas que declaramos no arquivo “HelloWorldScene.h”. Insira as seguintes linhas de código:

HelloWorld::gravidade = 0.0;

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

HelloWorld::velocidadeYInicial = 0.0;

HelloWorld::tempoCorrido = 0.0;

setTouchEnabled(true);

schedule(schedule_selector(HelloWorld::atualiza));

logo abaixo dessa:

addChild(plataforma);

Todas as variáveis foram criadas com o objetivo de realizar a simulação física apenas na vertical. Como o nosso Sonic não anda para frente nem para trás, não há necessidade de incluir outras variáveis físicas para isso. Dessa forma, como o personagem jogável está, inicialmente, sobre uma plataforma, então inicializamos as variáveis gravidade, velocidade inicial vertical e tempo corrido como iguais a zero. Isso fará com que o Sonic permaneça sempre no mesmo lugar, pelo fato da velocidade inicial e gravidade serem zeradas. Note que também acionamos a tela de toque e especificamos a necessidade de executar o método “atualiza” a cada novo quadro gerado.

Para finalizar, adicione as seguintes linhas de código no final do arquivo:

void HelloWorld::atualiza(float dt) {

    CCRect s = HelloWorld::sonic->boundingBox();

    s.origin.y++;

    if(s.intersectsRect(HelloWorld::plataforma->boundingBox())) {

        HelloWorld::gravidade = 0.0;

        HelloWorld::posicaoYInicial = HelloWorld::plataforma->getPositionY()+

        HelloWorld::plataforma->boundingBox().size.height+HelloWorld::sonic->boundingBox().size.height/2;

        HelloWorld::velocidadeYInicial = 0.0;

        HelloWorld::tempoCorrido = 0.0;

    }

    HelloWorld::tempoCorrido += dt;

    HelloWorld::sonic->setPosition(ccp(HelloWorld::sonic->getPositionX(),HelloWorld::posicaoYInicial+

      HelloWorld::velocidadeYInicial*HelloWorld::tempoCorrido+

      (HelloWorld::gravidade*HelloWorld::tempoCorrido*HelloWorld::tempoCorrido)/2));

}

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

    if(HelloWorld::gravidade==0.0) {

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

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

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

        HelloWorld::tempoCorrido = 0.0;

    }

}

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

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

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

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

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

        HelloWorld::tempoCorrido = 0.0;

    }

}

Iniciarei a explicação do código adicionado pelo método “atualiza”. Nele, nós primeiramente capturamos o quadrado que limita as beiradas do Sonic e verificamos se ele está encostando na plataforma. Caso isso aconteça, então precisamos deixá-lo exatamente sobre ela. Isso porque, quando o Sonic está caindo, ele poderá entrar na frente dos blocos marrons que formam plataforma. Note que igualamos as variáveis físicas “gravidade”, “posicaoYInicial” e “tempoCorrido” a zero. Como o Sonic estaria sobre o chão, então não há movimentação vertical. No mesmo método, nós incrementamos a variável “tempoCorrido” com o tempo entre quadros e atualizamos a posição do Sonic. Dessa forma, quando o Sonic estiver no ar, ele cairá e, quando ele encostar na plataforma, não sofrerá movimentação vertical.

Nos métodos “ccTouchesBegan” e “ccTouchesEnded” nós modificamos as variáveis físicas para que seja inclusa a funcionalidade de saltos. Note que, caso o jogador inicie um toque na tela, nós inicializamos a velocidade inicial do Sonic com um valor positivo (para ele subir) e a gravidade com um valor negativo (para ele ir descendo com o tempo). Note também, que, para fazer com que o Sonic dê um salto maior caso o jogador segure o dedo na tela, a gravidade é modificada para um valor modular menor quando o jogador inicia o toque e ela é ela modificada para um valor modular maior caso ele solte o dedo da tela. Salve e compile o código e execute o jogo. O resultado é algo como o que é mostrado na animação a seguir. Veja como o Sonic salta mais alto quando o dedo é segurado na tela.

Vimos nesse tutorial como adicionar a funcionalidade de saltar com o Sonic e incluímos a simulação física de gravidade e de detecção e resposta de colisão com o chão. Como nós mesmos implementamos o motor físico, precisamos criar quatro variáveis físicas referentes ao movimento uniformemente variado. Fizemos também com que o Sonic pule mais alto caso o jogador segure o dedo na tela. No próximo tutorial, incluiremos a criação de plataformas com blocos marrons para que possamos fazer com que o Sonic corra no ambiente.

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.