Tutorial: Criando um jogo ao estilo Flappy Bird – Parte 1: Criando o projeto do Cocos2d-x

Daremos início à implementação de mais um game famoso e viciante.

Você acha simples manter um pássaro em voo e o desviar dos obstáculos?

Isso pode ser difícil, mas você verá que a implementação desse game acaba não sendo tão complicada.

No último tutorial, nós finalizamos a implementação de mais um game, sendo esse um jogo de estacionar um carro em uma vaga. Adicionamos as últimas funcionalidades no jogo, fazendo com que o carro ande para frente ou para trás e implementamos a física do atrito, para que o carro não derrape. Iniciaremos hoje mais um conjunto de tutoriais com o objetivo de implementar um game. O próximo jogo da nossa lista será ao estilo do jogo Flappy Bird. Partiu.

 

O Flappy Bird

O Flappy Bird é um jogo para dispositivos móveis desenvolvido pelo estúdio .GEARS, que ficou muito popular em meados de 2014. O jogador controla o voo de um pássaro e tem como objetivo passar pelo meio de tubos que fazem parte do cenário. A cada toque na tela do aparelho, o pássaro bate as suas asas e é impulsionado para cima, de forma que o jogador possa controlar o voo com consecutivos toques. O desafio está em fazer o pássaro passar pelas frestas existentes entre os tubos, tocando na tela nos momentos certos, de forma que o pássaro não encoste no chão e em nenhum tubo. O vídeo a seguir mostra o gameplay do Flappy Bird e ilustra a explicação dada.

Conhecendo bem o jogo que estamos prestes a implementar, vamos à criação do projeto que gerará o nosso game.

 

Criando o projeto no Cocos2d-x

Daremos início a parte prática com a criação de um projeto de aplicativo Android, que possui suporte à programação gráfica com o motor Cocos2d-x. Caso você não faça ideia do que se trata esse motor, dê uma olhada nesse tutorial. Ele mostra também como criar um projeto Android que usa o Cocos2d-x, caso você não saiba ou não se lembra como. Continuando, crie um projeto com nome de pacote “com.Santy.Desvio” e com nome de projeto “Desvio”. Escolha a API alvo com o número ID igual a 8. Essa API dá suporte ao desenvolvimento de aplicativos para aparelhos com sistema operacional Android com versão superior à 2.2. A Figura 1 mostra como eu criei o projeto.

Figura 1 - Criando o projeto

Figura 1 – Criando o projeto

Lembre-se que é necessário realizar mais alguns passos padrões para a criação de um projeto Cocos2d-x. Caso você não os conheça, veja quais são os passos no tutorial citado anteriormente. Vamos criar e testar os Sprites.

 

Testando os Sprites

Primeiramente, acesse a pasta “Resources” do projeto criado e apague a imagem nomeada “HelloWorld.png”. Essa imagem vem por padrão ao se criar um projeto Cocos2d-x. Como não a utilizaremos em nosso game, ela é desnecessária e pode ser apagada para otimizar espaço ao compilar o jogo.

Eu mesmo criei um sprite sheet para esse jogo que implementaremos. Caso você não saiba de que se trata um sprite sheet ou não faz ideia do que é Sprite, acesse esse tutorial, por favor. Nesse sprite sheet, tem uma imagem de fundo, três imagens que geram postes de luz e duas imagens responsáveis pela animação do pato que será manipulado pelo jogador. As imagens do pato eu peguei desse lugar, enquanto que as outras eu peguei diretamente de pesquisas no Google. Baixe esse arquivo e o descompacte dentro da pasta “Resources”. Eles serão importantes para podermos criar os Sprites do nosso game.

Agora abra o arquivo “HelloWorldScene.cpp”, localizado na pasta “Classes” do projeto criado, e apague todas as linhas de código entre essas (inclusive):

/////////////////////////////

// 3. add your codes below…

// add a label shows “Hello World”

// create and initialize a label

CCLabelTTF* pLabel = CCLabelTTF::create(“Hello World”, “Thonburi”, 34);

e essas (inclusive):

// add the sprite as a child to this layer

this->addChild(pSprite, 0);

Ao apagar essas linhas, nós removemos código desnecessário para o nosso game. Basicamente, esses códigos adicionavam na tela a imagem que apagamos anteriormente e uma etiqueta que escreve “Hello World” na parte superior da tela do jogo, todos elementos desnecessários. Agora, no mesmo lugar onde você apagou essas últimas linhas de código, adicione as seguintes linhas:

CCSize size = CCDirector::sharedDirector()->getWinSize();

CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(“spriteSheet.plist”);

CCSprite* fundo = CCSprite::createWithSpriteFrameName(“Fundo.png”);

fundo->setScaleX(size.width/fundo->boundingBox().size.width);

fundo->setScaleY(size.height/fundo->boundingBox().size.height);

fundo->setPosition(ccp(size.width/2,size.height/2));

addChild(fundo);

CCSprite* pato = CCSprite::createWithSpriteFrameName(“Passaro1.png”);

pato->setScale((0.15*size.height)/pato->boundingBox().size.height);

pato->setPosition(ccp(0.25*size.width,size.height/2));

addChild(pato);

CCSprite* pe1 = CCSprite::createWithSpriteFrameName(“PostePe.png”);

pe1->setScale((0.04*size.height)/pe1->boundingBox().size.height);

pe1->setPosition(ccp(0.5*size.width,pe1->boundingBox().size.height/2));

addChild(pe1);

CCSprite* corpo1 = CCSprite::createWithSpriteFrameName(“PosteCorpo.png”);

corpo1->setScaleX((0.08*size.height)/corpo1->boundingBox().size.height);

corpo1->setScaleY((0.2*size.height)/corpo1->boundingBox().size.height);

corpo1->setPosition(ccp(0.5*size.width,pe1->boundingBox().size.height+corpo1->boundingBox().size.height/2));

addChild(corpo1);

CCSprite* cabeca1 = CCSprite::createWithSpriteFrameName(“PosteCabeca.png”);

cabeca1->setScale((0.08*size.height)/cabeca1->boundingBox().size.height);

cabeca1->setPosition(ccp(0.5*size.width,corpo1->getPositionY()+(corpo1->boundingBox().size.height+cabeca1->boundingBox().size.height)/2));

addChild(cabeca1);

CCSprite* corpo2 = CCSprite::createWithSpriteFrameName(“PosteCorpo.png”);

corpo2->setScaleX((0.08*size.height)/corpo2->boundingBox().size.height);

corpo2->setScaleY((0.4*size.height)/corpo2->boundingBox().size.height);

corpo2->setPosition(ccp(0.5*size.width,size.height-corpo2->boundingBox().size.height/2));

corpo2->setRotation(180);

addChild(corpo2);

CCSprite* cabeca2 = CCSprite::createWithSpriteFrameName(“PosteCabeca.png”);

cabeca2->setScale((0.08*size.height)/cabeca2->boundingBox().size.height);

cabeca2->setPosition(ccp(0.5*size.width,corpo2->getPositionY()-(corpo2->boundingBox().size.height+cabeca2->boundingBox().size.height)/2));

cabeca2->setRotation(180);

addChild(cabeca2);

CCSprite* pe3 = CCSprite::createWithSpriteFrameName(“PostePe.png”);

pe3->setScale((0.04*size.height)/pe3->boundingBox().size.height);

pe3->setPosition(ccp(0.75*size.width,pe3->boundingBox().size.height/2));

addChild(pe3);

CCSprite* corpo3 = CCSprite::createWithSpriteFrameName(“PosteCorpo.png”);

corpo3->setScaleX((0.08*size.height)/corpo3->boundingBox().size.height);

corpo3->setScaleY((0.4*size.height)/corpo3->boundingBox().size.height);

corpo3->setPosition(ccp(0.75*size.width,pe3->boundingBox().size.height+corpo3->boundingBox().size.height/2));

addChild(corpo3);

CCSprite* cabeca3 = CCSprite::createWithSpriteFrameName(“PosteCabeca.png”);

cabeca3->setScale((0.08*size.height)/cabeca3->boundingBox().size.height);

cabeca3->setPosition(ccp(0.75*size.width,corpo3->getPositionY()+(corpo3->boundingBox().size.height+cabeca3->boundingBox().size.height)/2));

addChild(cabeca3);

CCSprite* corpo4 = CCSprite::createWithSpriteFrameName(“PosteCorpo.png”);

corpo4->setScaleX((0.08*size.height)/corpo4->boundingBox().size.height);

corpo4->setScaleY((0.2*size.height)/corpo4->boundingBox().size.height);

corpo4->setPosition(ccp(0.75*size.width,size.height-corpo4->boundingBox().size.height/2));

corpo4->setRotation(180);

addChild(corpo4);

CCSprite* cabeca4 = CCSprite::createWithSpriteFrameName(“PosteCabeca.png”);

cabeca4->setScale((0.08*size.height)/cabeca4->boundingBox().size.height);

cabeca4->setPosition(ccp(0.75*size.width,corpo4->getPositionY()-(corpo4->boundingBox().size.height+cabeca4->boundingBox().size.height)/2));

cabeca4->setRotation(180);

addChild(cabeca4);

Nas linhas de código adicionadas, nós, inicialmente, abrimos o sprite sheet que contém os Sprites do nosso game. Isso é necessário para que possamos testar os Sprites que eu criei para fazermos o jogo. Logo após, nós adicionamos um Sprite com o fundo do game, o redimensionamos e o posicionamos de forma que ele ocupe toda a tela do aparelho. Inserimos o pato na tela e quatro postes pertencentes ao cenário do jogo. Se você notar, todos os Sprites foram redimensionados para que o cenário fique parecido em qualquer dispositivo, seja ele um celular ou um tablet. Cada poste de iluminação pregado no chão é formado por um conjunto de três Sprites, um que representa a base do poste, outro que representa o corpo do poste e outro que representa a lâmpada do poste. Note que os postes que são pregados na parte superior da tela são desprovidos de base. Se você compilar o código e executar o aplicativo, será mostrado algo parecido com a Figura 2.

Figura 2 - Primeira execução do jogo

Figura 2 – Primeira execução do jogo

Nesse tutorial nós conhecemos tudo, ou quase tudo, sobre o jogo Flappy Bird. Vimos que esse foi um jogo muito popular e tinha como objetivo guiar o voo de um pássaro, evitando os obstáculos que vão aparecendo. Também criamos o nosso projeto do jogo e testamos os Sprites para termos ideia de como ficará o jogo posteriormente. No próximo tutorial nós adicionaremos o mundo físico no jogo e implementaremos o bater de asas do pato. Obviamente, ainda não o faremos andar para frente, mas faremos que seja possível o deixar voando por meio de sucessivos toques na tela.

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