Tutorial: Criando um jogo ao estilo Angry Birds – Parte 1:Criando o projeto Cocos2d-x

Finalizamos mais um conjunto de tutoriais e criamos mais um game diferente.

Indo na mesma onda, criaremos outro jogo bastante viciante e que muita gente nem imagina como funciona o motor por trás dele.

Veremos como é simples criar um jogo ao estilo Angry Birds (créditos a Rovio).

No último tutorial, nós terminamos de implementar um jogo ao estilo Arkanoid (créditos a Taito). Incluímos três elementos de HUD e mais algumas funcionalidades que contavam o número de chances utilizadas no jogo e o número de blocos amarelos destruídos durante o jogo. Daremos início a mais um conjunto de tutoriais com o objetivo de programar a mecânica básica de um jogo bastante conhecido: o Angry Birds.

 

O Angry Birds

O Angry Birds é um jogo desenvolvido pela empresa Rovio e é distribuído atualmente nos principais canais de distribuição de jogos mobile, como, por exemplo, a AppStore e o Google Play. Esse é um jogo do tipo Catapult Shooting, ou seja, você arremessa um objeto, nesse caso um pássaro, de encontro a uma estrutura feita de blocos que protege alguns alvos principais. O objetivo do jogo é eliminar todos os alvos, que nesse caso são porcos, e fazer o máximo de pontos possíveis arremessando o mínimo de pássaros. Esse é um game que faz uso de simulação física para realizar as movimentações de todos os objetos interativos no game. Para quem não conhece (creio que seja difícil), o vídeo a seguir mostra um gameplay de Angry Birds.

Conhecendo bem como funciona o game, vamos dar início ao desenvolvimento criando um novo projeto no Cocos2d-x. Partiu.

 

Criando o projeto e testando os Sprites

Primeiramente crie um projeto Cocos2d-x Android com o nome de pacote “com.Santy.Canhao” e nomeie o projeto como “Canhao”. Selecione a API alvo do Android com id número 8. Se você não lembra como criar um projeto Cocos2d-x, veja nesse tutorial. Lá mostra certinho como compilar e executar o jogo. A Figura 1 mostra como eu criei o projeto.

Figura 1 - Criando o projeto Cocos2d-x

Figura 1 – Criando o projeto Cocos2d-x

Com o projeto devidamente criado, acesse a pasta “Resources” e apague o arquivo “HelloWorld.png”. Para quem não sabe, esse é um arquivo de imagem padrão mostrado em toda aplicação Cocos2d-x quando criada. Ele só serve para teste e, como queremos colocar o nosso jogo na tela ao invés dessa imagem, então ela é desprezível e pode ser apagada. Copie para essa mesma pasta o conteúdo existente nesse arquivo compactado.

Eu mesmo criei o sprite sheet do jogo que vamos programar, então não sejam muito críticos com a minha arte. =P. Para esse game, precisaremos de Sprites para o arremessador, para o objeto a ser arremessado, para a estrutura, para o alvo a ser acertado e, obviamente, para o fundo. O arremessador usará dois Sprites diferentes: um será o canhão e outro será o suporte dele. O objeto arremessado será uma bala de canhão. A estrutura poderá ser composta por três tipos de objetos diferentes: um bloco de pedra, um bloco de madeira e uma viga de aço. O alvo será representado por um vaso de flores … sem flores. Para finalizar, terão também um Sprite para o fundo e um Sprite de uma seta para mostrar a força e a angulação com que a bala de canhão será arremessada. Se você não entende como funciona um sprite sheet ou não sabe como criar um, veja sobre tudo isso nesse tutorial.

Está certo, agora vamos ao código. Abra o arquivo “HelloWorldScene.cpp” e apague todas as linhas de código existentes entre essas linhas:

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

// 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 linhas:

// add the sprite as a child to this layer

this->addChild(pSprite, 0);

Nesse mesmo lugar, adicione as seguintes linhas de código:

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

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

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

if(size.width/size.height>470/320)

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

else

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

fundo->setAnchorPoint(ccp(0,0));

addChild(fundo);

CCSprite* suporteCanhao = CCSprite::createWithSpriteFrameName(“SuporteCanhao.png”);

suporteCanhao->setScale(fundo->getScale());

suporteCanhao->setAnchorPoint(ccp(0,0));

suporteCanhao->setPosition(ccp(0.1*size.width,15*fundo->getScale()));

CCSprite* canhao = CCSprite::createWithSpriteFrameName(“Canhao.png”);

canhao->setScale(fundo->getScale());

canhao->setAnchorPoint(ccp(18.0/62.0,20.0/47.0));

canhao->setPosition(ccp(0.1*size.width + (22.0/44.0)*suporteCanhao->boundingBox().size.width,15*fundo->getScale() + (31.0/38.0)*suporteCanhao->boundingBox().size.height));

canhao->setRotation(-35);

addChild(canhao);

addChild(suporteCanhao);

CCSprite* blocoPedra = CCSprite::createWithSpriteFrameName(“BlocoPedra.png”);

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

blocoPedra->setPosition(ccp(0.6*size.width,15*fundo->getScale() + blocoPedra->boundingBox().size.height/2));

addChild(blocoPedra);

CCSprite* blocoMadeira = CCSprite::createWithSpriteFrameName(“BlocoMadeira.png”);

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

blocoMadeira->setPosition(ccp(0.8*size.width,15*fundo->getScale() + blocoMadeira->boundingBox().size.height/2));

addChild(blocoMadeira);

CCSprite* viga = CCSprite::createWithSpriteFrameName(“Viga.png”);

viga->setScale((0.5*size.height)/viga->boundingBox().size.width);

viga->setPosition(ccp(0.7*size.width,15*fundo->getScale() + blocoPedra->boundingBox().size.height + viga->boundingBox().size.height/2));

addChild(viga);

CCSprite* vaso = CCSprite::createWithSpriteFrameName(“Vaso.png”);

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

vaso->setPosition(ccp(0.7*size.width,15*fundo->getScale() + blocoPedra->boundingBox().size.height + viga->boundingBox().size.height + vaso->boundingBox().size.height/2));

addChild(vaso);

CCSprite* bala = CCSprite::createWithSpriteFrameName(“Bala.png”);

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

bala->setPosition(ccp(0.5*size.width,0.45*size.height));

addChild(bala);

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

seta->setAnchorPoint(ccp(-((44.0/62.0)*canhao->boundingBox().size.width)/seta->boundingBox().size.width,0.5));

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

seta->setRotation(-35);

seta->setPosition(ccp(0.1*size.width + (22.0/44.0)*suporteCanhao->boundingBox().size.width,15*fundo->getScale() + (31.0/38.0)*suporteCanhao->boundingBox().size.height));

addChild(seta);

Vou explicar o que fizemos, em partes. Inicialmente tiramos o código que mostrava na tela a imagem padrão do Cocos2d-x e mais algumas etiquetas dispensáveis ao nosso jogo. Logo após, incluímos um conjunto de código que mostrava a tela de teste do nosso game. Nesse código adicionado, primeiramente criamos e incluímos o fundo e os Sprites que representam o arremessador, ou seja, a base do canhão e o canhão em si. Logo após, incluímos mais três Sprites para a estrutura, que era feita de um bloco de pedra, um bloco de madeira e uma viga de aço. Adicionamos o vaso-alvo acima da viga de aço e, para finalizar, incluímos a bala de canhão e a seta que mostra a direção e a força que a bala é arremessada. O resultado visual disso tudo é mostrado na Figura 2.

Figura 2 - Tela de teste do game

Figura 2 – Tela de teste do game

Entendemos nesse tutorial como funciona o jogo Angry Birds, da Rovio, e criamos um projeto no Cocos2d-x. Adicionamos nesse projeto um sprite sheet que o nosso jogo utilizará e testamos todos os Sprites desse sprite sheet. Criamos uma tela inicial de teste para termos uma ideia de como ficará o jogo no final. No próximo tutorial, implementaremos o arremesso da bala de canhão por meio de um clique na tela. Para que a bala siga o caminho corretamente conforme a lei da gravidade, faremos uso da biblioteca física Box2D.

Um grande abraço e nos vemos adiante. []

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