Física em jogos com Chipmunk2D

Física em jogos com Chipmunk2D
vitor.mattos
vitor.mattos

Compartilhe

Uma dúvida de muitos que iniciam no desenvolvimento de jogos é: "Como farei para simular a física?" Lidar com física nunca é uma tarefa simples. Temos que considerar gravidade, como ela afeta os corpos presentes no espaço, colisão entre os corpos, força de impulso, formas geométricas etc.

chipmunk

Para que o desenvolvedor não precise se preocupar com todos esses aspectos, diversas engines de física para jogos foram criados. Veremos o quão fácil é trabalhar com a engine Chipmunk2D, usando o framework Cocos2d-JS para criar nosso jogo! Você pode conferir o resultado final do que faremos nesse link.

jogo

Diversos tutoriais básicos sobre Cocos2d podem ser encontrados na página da documentação e o download está disponível aqui.

Para começarmos a usar a engine de física do Chipmunk2D, temos que declarar nas configurações do Cocos2d-JS que usaremos o chipmunk. Para isso, alteramos o arquivo cocos2d.js na pasta cocos2d e adicionamos a seguinte instrução:

 chipmunk:true, 

Agora toda vez que carregarmos o Cocos2d, o jsloader carregará também a biblioteca do Chipmunk2D.

Para de fato usarmos a física em uma cena, precisamos de um objeto chamado Space. Nesse objeto definiremos todas as regras de física do nosso "espaço", como a gravidade, por exemplo. É comum criarmos um método (initPhysics) na cena (Scene) que iniciará todas as configurações de física:

 var PhysicScene = cc.Scene.extend({ space: null,

initPhysics:function() { //criação do objeto Space this.space = new cp.Space(); },

onEnter:function () { this.\_super(); this.initPhysics(); var layer = new GameLayer(this.space); this.addChild(layer);

this.scheduleUpdate(); }, update: function(dt) { this.space.step(dt); } }); 

Pronto! Agora já temos um objeto representando o espaço. Um vez criado podemos definir a força da gravidade nele. Para tal, o objeto space possui uma propriedade gravity que recebe um vetor no plano cartesiano:

 //dentro da função initPhysics, logo após ter criado o space this.space.gravity = cp.v(0, -650); 

O próximo passo é criar um GameLayer. Nesse Layer (ou camada da cena) acontecerão todas as animações. É a camada principal que junta todos os elementos do jogo.

O GameLayer recebe o objeto space criado anteriormente como parâmetro no construtor. O código seguinte initializa o GameLayer:

 var GameLayer = cc.Layer.extend({

ctor : function(space){ this.\_super(); this.space = space; this.init(); },

init:function(){ this.\_super(); //aqui vamos fazer mais coisas ainda }, }); 

Vamos simular um corpo sendo afetado pela gravidade em nosso espaço. Representaremos esse corpo com o sprite de uma bola que fica salvo dentro de um diretório especial chamado res/Normal/:

ball

Para a simulação, no GameLayer dentro da função init criaremos o sprite da bola e o associaremos a um corpo físico:

 init:function(){ this.\_super();

// cc.PhysicsSprite cria um sprite que representará um corpo var bola = cc.PhysicsSprite.create("ball.png"); this.addChild(bola);

var raio = 32;

// Criando o corpo físico que obedecerá as leis do espaço var corpo = this.space.addBody(new cp.Body(10, cp.momentForCircle(10, 0, raio, cp.v(0,0))));

// Podemos escolher a forma do corpo, a elasticidade e a fricção dele! forma = this.space.addShape(new cp.CircleShape(corpo, raio, cp.v(0,0))); forma.setElasticity(0.6); forma.setFriction(1);

var s = cc.Director.getInstance().getWinSize(); corpo.setPos(cp.v(s.width/2, s.height/2));

bola.setBody(corpo) }, 

Rode a aplicação e verifique o resultado. A bola está passando desaparecendo tela! Precisamos criar um chão para que ela permaneça na área visível.

Vamos criar 4 paredes, uma em cada lado da tela, transformando a área jogável em uma espécie de "caixa". No método initPhysics, que está no PhysicScene:

 var winSize = cc.Director.getInstance().getWinSize();

var staticBody = this.space.staticBody;

var paredes = \[ new cp.SegmentShape(staticBody, cp.v(0,0), cp.v(winSize.width,0), 0 ), // bottom

new cp.SegmentShape(staticBody, cp.v(0,winSize.height), cp.v(winSize.width,winSize.height), 0), // top

new cp.SegmentShape(staticBody, cp.v(0,0), cp.v(0,winSize.height), 0), // left

new cp.SegmentShape(staticBody, cp.v(winSize.width,0), cp.v(winSize.width,winSize.height), 0) // right \];

for( var i=0; i < paredes.length; i++ ) { var forma = paredes\[i\]; forma.setElasticity(1); forma.setFriction(1); this.space.addStaticShape( forma ); } 

Agora nossa bola bate no chão e quica! Podemos facilmente aplicar um impulso ao corpo. Na função init do GameLayer:

 var forcaX = -4000; var forcaY = 3000;

corpo.applyImpulse(cp.v(forcaX, forcaY), cp.v(0, 0)); 

Agora a bola começa já com um impulso. O primeiro parâmetro da função applyImpulse é um vetor com a direção do impulso. O segundo parâmetro é um offset indicando (a partir do centro do corpo) onde o impulso será aplicado. Poderíamos usar valores diferentes de 0 se quiséssemos causar uma rotação na bola.

Vimos que é muito simples simularmos física em nossos jogos do Cocos2d-html5 usando a engine Chipmunk2D. Só precisamos de um objeto space, onde podemos configurar, por exemplo, a gravidade. E nele teremos os corpos que serão afetados pela física.

Falta mencionar que Cocos2d já vem com o Cocos2d-html5 e o Cocos2d-x Javascript Binding, para podermos compilar nosso código para rodar nativamente em dispositivos mobile. Além disso, a biblioteca do Cocos2d também possui suporte para outras engines de física, como por exemplo o Box2D.

O código completo desse projeto pode ser encontrado no Github e se quiser saber mais sobre Cocos2d-html5, não deixe de visitar a MobileConf RJ 2014!

Veja outros artigos sobre Front-end