Tutorial: Criando um jogo de car parking – Parte 4: Virando os pneus

Especificamos logicamente todo o ambiente físico do nosso game de estacionar o carro.

Fizemos os objetos rígidos que representam o carro e seus pneus e prendemos uns aos outros por meio de juntas rotativas e prismáticas.

Vamos incluir a funcionalidade de virar o volante.

Implementamos no último tutorial a adição dos corpos rígidos referentes aos quatro pneus do carro do jogador e incluímos quatro Sprites que mostram os pneus na tela. Ligamos esses corpos rígidos ao corpo rígido principal do carro com juntas rotativas nos pneus dianteiros e com juntas prismáticas nos pneus traseiros. A lógica de construção do carro no Box2D já está pronta e agora daremos início à implementação das funcionalidades do game. Nesse tutorial, faremos com que as rodas dianteiras virem caso o jogador aperte um dos dois botões: para a esquerda ou para a direita. Hoje nos limitaremos à implementação de somente essa funcionalidade, para evitar que o tutorial fique muito extenso.

Iniciando, vamos adicionar as variáveis e os métodos que precisaremos para programarmos a funcionalidade de virar o volante. Para que você possa fazer esse tutorial, é necessário que você já tenha concluído o anterior. Abra o arquivo “HelloWorldScene.h” e adicione as seguintes linhas de código:

int cliqueVirarID;

float anguloRoda;

cocos2d::CCSprite* dir;

cocos2d::CCSprite* esq;

cocos2d::CCSprite* baixo;

cocos2d::CCSprite* cima;

void atualizaMundo(float dt);

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

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

logo abaixo dessa:

b2PrismaticJoint* juntaRodaTraseiraDireita;

Nesse código, incluímos uma variável nomeada “cliqueVirarID”, que tem a função de armazenar o número identificador do toque na tela. Ela é necessária para indicar quando o botão de virar o volante é soltado. Caso ela não exista, não há possibilidade de sabermos quando o jogador para de virar o volante. Foi adicionada também outra variável, nomeada “anguloRoda”, que possui a função de especificar a angulação que as rodas dianteiras devem ficar. Quando o jogador aperta para virar para a esquerda, por exemplo, a angulação das rodas deve ficar em 60 graus e, quando o jogador solta o dedo do botão, a angulação das rodas deve ficar em zero grau.

Foram adicionadas as referências dos quatro Sprites dos botões de interação na tela. Anteriormente, esses botões não estavam acionados, de forma que não houvesse a necessidade de uma referência deles na classe “HelloWorld”. Como daremos início a inclusão da funcionalidade de virar o volante, precisamos de uma referência para sabermos quando o jogador aperta um dos botões. Por último, incluímos os protótipos dos métodos que programaremos no tutorial de hoje. O método “atualizaMundo” realiza a cada quadro o processamento do mundo do Box2D e atualiza a posição e angulação dos Sprites conforme as posições dos objetos rígidos no mundo físico. Os métodos “ccTouchesBegan” e “ccTouchesEnded” são chamados no momento que o jogador encosta o dedo na tela e retira o dedo da tela, respectivamente. Eles são necessários para identificarmos o momento em que ele clica em um dos botões de interação do jogo.

Salve e feche o arquivo “HelloWorldScene.h”, já fizemos a modificação necessária nele. Abra o arquivo “HelloWorldScene.cpp” para editar algumas linhas de código que escrevemos no último tutorial. Edite as seguintes linhas:

CCSprite* dir = CCSprite::createWithSpriteFrameName(“Seta.png”);

.

.

.

CCSprite* baixo = CCSprite::createWithSpriteFrameName(“Seta.png”);

.

.

.

CCSprite* esq = CCSprite::createWithSpriteFrameName(“Seta.png”);

.

.

.

CCSprite* cima = CCSprite::createWithSpriteFrameName(“Seta.png”);

conforme está escrito a seguir:

dir = CCSprite::createWithSpriteFrameName(“Seta.png”);

.

.

.

baixo = CCSprite::createWithSpriteFrameName(“Seta.png”);

.

.

.

esq = CCSprite::createWithSpriteFrameName(“Seta.png”);

.

.

.

cima = CCSprite::createWithSpriteFrameName(“Seta.png”);

Essa modificação faz com que tenhamos uma referência a cada botão de interação do jogo. Agora, quando houver um toque na tela, podemos verificar se o toque foi realizado sobre qualquer um dos Sprites dos botões de interação. Ainda no mesmo arquivo, adicione as seguintes linhas de código:

HelloWorld::cliqueVirarID = -1;

HelloWorld::anguloRoda = 0.0;

schedule(schedule_selector(HelloWorld::atualizaMundo));

setTouchEnabled(true);

logo abaixo dessa:

HelloWorld::juntaRodaTraseiraDireita = static_cast<b2PrismaticJoint*>(HelloWorld::mundoFisico->CreateJoint(&definicaoJuntaRodaTraseiraDireita));

Nessas linhas nós inicializamos as variáveis responsáveis por gerenciar o sistema do volante do carro do jogador, especificamos qual é o método que realiza a atualização dos ambientes físico e do jogo e acionamos a tela de toque. Nada muito complexo, mas de grande importância. Para finalizar, adicione as seguintes linhas de código no final do arquivo:

void HelloWorld::atualizaMundo(float dt) {

    float velocidadeRotacaoVolante;

    velocidadeRotacaoVolante = HelloWorld::anguloRoda – HelloWorld::juntaRodaDianteiraEsquerda->GetJointAngle();

    HelloWorld::juntaRodaDianteiraEsquerda->SetMotorSpeed(velocidadeRotacaoVolante*1.5);

velocidadeRotacaoVolante = HelloWorld::anguloRoda – HelloWorld::juntaRodaDianteiraDireita->GetJointAngle();

    HelloWorld::juntaRodaDianteiraDireita->SetMotorSpeed(velocidadeRotacaoVolante*1.5);

    HelloWorld::mundoFisico->Step(dt,3,2);

    HelloWorld::carroJogador->setPosition(ccp(HelloWorld::corpoCarroJogador->GetWorldCenter().x*PTM_RATIO,HelloWorld::corpoCarroJogador->GetWorldCenter().y*PTM_RATIO));

    HelloWorld::carroJogador->setRotation(-(180*HelloWorld::corpoCarroJogador->GetAngle())/M_PI);

    HelloWorld::rodaDianteiraEsquerda->setPosition(ccp(HelloWorld::corpoRodaDianteiraEsquerda->GetWorldCenter().x*PTM_RATIO,HelloWorld::corpoRodaDianteiraEsquerda->GetWorldCenter().y*PTM_RATIO));

    HelloWorld::rodaDianteiraEsquerda->setRotation(-(180*HelloWorld::corpoRodaDianteiraEsquerda->GetAngle())/M_PI);

    HelloWorld::rodaDianteiraDireita->setPosition(ccp(HelloWorld::corpoRodaDianteiraDireita->GetWorldCenter().x*PTM_RATIO,HelloWorld::corpoRodaDianteiraDireita->GetWorldCenter().y*PTM_RATIO));

    HelloWorld::rodaDianteiraDireita->setRotation(-(180*HelloWorld::corpoRodaDianteiraDireita->GetAngle())/M_PI);

    HelloWorld::rodaTraseiraEsquerda->setPosition(ccp(HelloWorld::corpoRodaTraseiraEsquerda->GetWorldCenter().x*PTM_RATIO,HelloWorld::corpoRodaTraseiraEsquerda->GetWorldCenter().y*PTM_RATIO));

    HelloWorld::rodaTraseiraEsquerda->setRotation(-(180*HelloWorld::corpoRodaTraseiraEsquerda->GetAngle())/M_PI);

    HelloWorld::rodaTraseiraDireita->setPosition(ccp(HelloWorld::corpoRodaTraseiraDireita->GetWorldCenter().x*PTM_RATIO,HelloWorld::corpoRodaTraseiraDireita->GetWorldCenter().y*PTM_RATIO));

    HelloWorld::rodaTraseiraDireita->setRotation(-(180*HelloWorld::corpoRodaTraseiraDireita->GetAngle())/M_PI);

}

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

    CCTouch* toque = static_cast<CCTouch*>(pTouches->anyObject());

    CCPoint ponto = toque->getLocationInView();

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

    if(HelloWorld::esq->boundingBox().containsPoint(ponto)) {

        HelloWorld::anguloRoda = M_PI/3.0;

        HelloWorld::cliqueVirarID = toque->getID();

    }

    else if(HelloWorld::dir->boundingBox().containsPoint(ponto)) {

        HelloWorld::anguloRoda = -M_PI/3.0;

        HelloWorld::cliqueVirarID = toque->getID();

    }

}

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

    CCTouch* toque = static_cast<CCTouch*>(pTouches->anyObject());

    if(toque->getID()==HelloWorld::cliqueVirarID) {

        HelloWorld::anguloRoda = 0.0;

        HelloWorld::cliqueVirarID = -1;

    }

}

Nesse trecho, nós implementamos três métodos. O primeiro, nomeado “atualizaMundo”, realiza o processamento do mundo físico do Box2D. Mas, primeiramente, as rodas dianteiras do carro do jogador são rotacionadas por meio das juntas rotativas que implementamos no último tutorial. Notem que, a todo instante, as rodas são rotacionadas conforme a angulação que elas precisam estar. O sistema de rotação funciona da seguinte forma: quanto maior a diferença entre a angulação atual da roda e a angulação em que ela precisa estar, maior será a velocidade de rotação dela. Por exemplo, caso o jogador esteja com as rodas apontando para a esquerda e, subitamente, ele passa a virar para a direita, as rodas dianteiras rotacionam em uma velocidade maior no início e finalizam com uma rotação mais lenta. Normalmente, os sistemas de rotação do volante de jogos eletrônicos de corrida se baseiam nesse tipo de lógica. O método “atualizaMundo” é finalizado com a atualização da posição e angulação de todos os Sprites que compõem o carro do jogador, conforme os seus respectivos objetos rígidos no Box2D.

No método “ccTouchesBegan”, nós identificamos onde exatamente o jogador encosta o dedo na tela. Caso seja no botão de virar para a esquerda, a angulação que as rodas dianteiras precisam estar é atualizada para 60 graus. Caso o botão de virar para a direita seja apertado, então a angulação é atualizada para -60 graus. Como a rotação das rotas dianteiras é atualizada a cada quadro, então as rodas dianteiras são rotacionadas logo quando o jogador clica em um dos botões do volante. Também armazenamos o número identificador do toque caso o jogador clique nos botões. Como dito anteriormente, isso é necessário para que possamos identificar o momento em que o jogador solta o dedo do botão. Já no método “ccTouchesEnded”, nós apenas igualamos a angulação que a roda precisa estar ao valor de zero grau. Obviamente, caso o jogador não clique nos botões de volante, as rodas precisam estar apontadas para frente.

Pronto … implementamos o sistema do volante do nosso game. Caso você compile o código atual e execute o game, verá algo parecido com o que é mostrado na Figura 1. Note que eu estou virando o volante do carro para a direita.

Figura 1 - Execução do jogo

Figura 1 – Execução do jogo

Implementamos nesse tutorial o sistema de virar o volante do nosso jogo de car parking. Vimos que precisávamos das referências dos Sprites dos botões de interação para identificar se o jogador está virando o volante ou não. Também vimos que é necessário atualizar o mundo do Box2D a cada novo quadro mostrado na tela, para que aconteça a simulação física. Detectamos quando o jogador clica em um dos botões de virar o volante e atualizamos a angulação que as rodas precisam estar. Como a rotação delas acontece a cada quadro, então basta atualizarmos a rotação que elas precisam estar no momento (60 graus, zero grau e -60 graus).

No próximo tutorial, nós implementaremos o sistema de aceleração (para frente e para trás) e frenagem do carro. Também implementaremos os efeitos físicos de atrito das rodas com o chão, para evitar a derrapagem do carro.

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