• Nenhum resultado encontrado

Física de games �������������������������������������������������������������

Física é uma macro função muito importante em games de ação, pois serve para aumentar a jogabilidade, aumentando a percepção de realidade e o en- volvimento do jogador. A física de um game deve lidar com problemas como: força, aceleração, movimento e colisão, tentando fazer com que os Game Ob- jects se comportem aproximadamente como os modelos reais.

Os exemplos são incrementais

Eu vou mostrar vários exemplos neste capítulo e todo o código-fonte está disponível para você, logo, n�o necessitará digitar coisa alguma.

Porém, eu quero fazer uma observaç�o sobre os exemplos: o objetivo é

mostrar como aplicar cálculos de física aos games. Neste momento, eu não

estou preocupado com a precisão do Game Loop ou com quaisquer outros detalhes. Logo, antes de usar os exemplos como base para o seu game, tenha em mente que existem mais aspectos a serem analisados, então, eu sugiro que você leia até o final ANTES de sair criando seu jogo definitivo.

Rode todos os exemplos

Este capítulo é muito grande, mas é extremamente importante para que você conheça bem a física de jogos. Todos os exemplos est�o junto com o código-fonte que acompanha o livro. Eu recomendo que você baixe todos e rode em seu computador.

o

S primórdioS

Ilustraç�o 24: O jogo “�orilla.bas”, que vinha com o Microsoft QBasic

Um dos exemplos mais antigos de física que eu me lembro é o do jogo “Gorilla.bas”, que vinha com o Microsoft QBasic. Na verdade, eu já o conhe- cia de um produto mais antigo: o Microsoft QuickBasic, que eu utilizava para desenvolver sistemas na década de 80. A física era bem simples e basicamente lidava com o movimento de um projétil (uma banana), levando em conta a força da gravidade.

Se pararmos para pensar, não é muito diferente do que o “Angry Birds” (Rovio - www.rovio.com/index.php?page=angry-birds) original fazia: atirar um pássaro, que viaja em trajetória influenciada pela gravidade. Quanto mais força, mais larga a parábola. E você tinha que acertar ou derrubar os porcos. A mecânica é parecida com a do “Gorilla.bas”, talvez um pouco mais precisa.

c

onceitoS báSicoS

Nem todo game é tão exigente na física quanto os jogos de ação. Existem games que sequer possuem qualquer tipo de física. É o caso do game que es- tou desenvolvendo para Facebook: o RandoSystem, que é um quebra-cabeças baseado em labirinto.

Ilustraç�o 25: Um jogo que dispensa a física

Porém, se você quer criar um jogo onde os �ame Objects se movam e colidam, deve prestar atenção à física, de modo a aumentar o envolvimento do jogador.

O jogo que eu descrevi no meu livro anterior, “Mobile �ame Jam” (www. mobilegamejam.com) era muito mais dependente de física.

Ilustraç�o 26: O jogo “BueiroBall”, do livro “Mobile �ame Jam”

No “BueiroBall” (eu sei, o nome poderia ser melhor) você tem que “enca- çapar” as bolas em determinada ordem, sen�o perde pontos (neste caso, as pre- tas só podem entrar depois das coloridas) e você joga usando o acelerômetro,

ou seja, inclinando o seu dispositivo. Neste jogo, a física é fundamental, pois temos que acrescentar realismo ao movimento e às colisões. As bolas devem se movimentar de acordo com a inclinação, acelerando ou diminuindo confor- me a posição do dispositivo.

E também tive que tratar a colisão, ou seja, o que acontece quando duas ou mais bolas colidem. Qual é o vetor de movimento resultante etc.

Aceleração e movimento

A parte que estuda isso na física é a cinemática. Eu não vou desperdiçar seu tempo explicando conceitos de física, mas, se quiser saber, recomendo a série “física de video game”, do portal “The Code Bakers” (http://www.theco- debakers.org/search/label/F%C3%ADsica).

O grande problema de jogos de movimento dinâmico é calcular onde você deve desenhar a figura no próximo frame. Se você utiliza uma física simples, como a que vimos no protótipo do “AsteroidNuts” (capítulo anterior), isto não é problema. Basta decrementar ou incrementar o valor da coordenada correspondente à direção do movimento e pronto. No caso do “AsteroidNuts”, estamos no espaço, e consideramos a aceleração constante. Mas poderíamos criar efeitos interessantes, como o puxão da gravidade, por exemplo.

Para calcular a posição de um objeto com relação a um plano de coordena- das cartesianas, podemos usar o método de Verlet (http://pt.wikipedia.org/wiki/ M%C3%A9todo_de_Verlet ou http://www.fisica.ufjf.br/~sjfsato/fiscomp1/node40. html). A fórmula básica é:

x(t + Δt) = (2 – f)x(t) – (1 – f)x(t - Δt) + a(t)( Δt)2

Podemos calcular a posição em cada eixo, informando as forças que foram aplicadas a eles (impulso e gravidade, por exemplo).

É isso o que fiz no game “Ataque das formigas marcianas”, publicado no “The Code Bakers” (http://www.thecodebakers.org/2012/04/fisica-de-vide- ogame-3-finalmente-um.html). O código-fonte do �ame está no �oogle Code (http://code.google.com/p/ataque-formigas-marcianas/), e ele usa a licença Apache 2.0 (Open Source).

Ilustraç�o 27: O jogo “Ataque das formigas marcianas

No jogo das “formigas”, o código que controla o movimento e aceleraç�o é calculado na classe que representa a “Bola”:

/*

* Esta classe representa uma bola * Podemos criar mais de uma... */ class Bola { double altura; double alturaAnterior; double alturaLimite; double limiteSuperior; double aceleracao; double velocidade; double dt; double forcaGrav; double massa;

boolean parada = true; boolean descendo = true;

double e = 0.50; // Coeficiente de restitui ‹o (pode variar) float x; float y;

Bola() { reset(); } void reset() { limiteSuperior = PISO; altura = limiteSuperior; alturaAnterior = altura; alturaLimite = 0; aceleracao = 0.0d; velocidade = 0.0d; dt = 01.d; forcaGrav = -9.8d; massa = 1.0d; descendo = true; } void atualizar() {

altura = altura + velocidade * dt +

(aceleracao * Math.pow(dt, 2)) / 2.0d; double vel2 = velocidade + (aceleracao * dt) /2.0d; double aceleracao = forcaGrav / massa ; velocidade = vel2 + (aceleracao * dt) / 2.0d;

} }

E, quando chegamos ao “chão”, nossa velocidade vai inverter, com uma aceleração proporcional à deformação causada pela colisão.

Colisão

Em física, temos dois tipos básicos de colis�o: elástica e inelástica (http:// www.coladaweb.com/fisica/mecanica/colisao-elastica-e-inelastica). Eu postei um artigo sobre isso no portal “The Code Bakers” (http://www.thecodebakers. org/2011/06/fisica-de-videogame-2-colisoes.html). O tipo de material dos dois ob- jetos pode determinar o tipo de colis�o que teremos:

• Colisão elástica: ambos os corpos se deformam e se expandem após

o choque, resultando na mesma energia cinética;

• Colisão parcialmente elástica: os corpos perdem parte da energia

cinética, que é transferida para trabalho (barulho, calor, deformaç�o permantente - plástica);

• Colisão inelástica: toda a energia cinética é transferida para trabalho;

O que significa isso? Bem, quando dois �ame Objects colidem, dependen- do do tipo de material, parte da energia cinética é transferida e um deles (ou ambos) podem perder velocidade. É o que acontece no jogo “Ataque das for- migas marcianas” quando a bola atinge o solo, “quicando” e subindo até uma altura menor que a inicial. Ela vai “quicar” algumas vezes até parar.

Em outros tipos de game (como o “BueiroBall”) nós n�o precisamos pen- sar nisso, pois é irrelevante. Mas, em games onde o “quique” e a deformação provocados pela colisão são importantes, é necessário calcular o que acontece depois da colisão.

Cada tipo de material tem um CR - “Coeficiente de retribuiç�o” (http:// www.thecodebakers.org/2011/06/fisica-de-videogame-2-colisoes.html), que influencia no cálculo do movimento de “quique” e da deformaç�o causados pela colisão. No caso do “Ataque das Formigas”, eu estou desprezando a de- formação e utilizando o CR apenas para calcular a força que será aplicada à bola para subir novamente.

if (bola.altura <= 0) {

// A bola bateu no ch‹ão bola.altura = 0;

bola.x = MEIO;

bola.y = (float)(PISO - bola.altura);

canvas.drawBitmap(bitmap, bola.x, bola.y, null); if (!bola.parada) {

verificaColisao(canvas); }

double novaAltura = Math.pow(bola.e, 2) * bola.alturaAnterior;

bola.velocidade = Math.sqrt(2 * (-bola.forcaGrav) * novaAltura);

bola.alturaAnterior = novaAltura; ...

O CR que estou usando (0,50) provoca um alto valor de restituiç�o, per- mitindo que a bola “quique” alto. Se usarmos algo como bola murcha caindo em argila, teremos uma baixíssima restituição, já que os dois materiais usarão a maior parte da energia cinética no trabalho de deformação, absorvendo o impacto.

Há outro fator a ser considerado: a direç�o dos objetos após a colis�o. No caso do “BueiroBall”, estou simplesmente inverto a velocidade nos dois eixos, que não é exatamente o que aconteceria na vida real, mas dá um efeito aceitável para o jogador. No caso do “Ataque das formigas marcianas”, estou desprezando isso e fazendo a bola simplesmente subir na mesma direção. Po- rém, em uma colis�o mais realista, a trajetória dos objetos seria afetada por:

• Ângulo da trajetória dos objetos; • Massa dos objetos;

• Velocidade dos objetos; • CR dos objetos;

Ou seja, há muitas variáveis a serem consideradas, e, dependendo do jogo, pode n�o ser interessante considerar isso tudo. Você tem que analisar o valor que a colisão realista vai agregar ao seu game.

No protótipo de game “AsteroidNuts” a colis�o é tratada de forma muito simples. Ao tocar em um asteroide, a nave perde ou ganha energia (no jogo), mas ambos (asteroide e nave) n�o s�o deformados e nem têm sua trajetória alterada. Esta é uma decisão que temos que tomar, caso sigamos em frente com este projeto.

Deteção de colisão

Se temos um jogo onde existem objetos em movimento, então também teremos que detetar colisões entre eles. Note que colis�o nem sempre significa desastre, por exemplo, quando o “herói” pula para uma plataforma, ocorre uma colisão.

Eu criei alguns artigos sobre deteção de colisão no portal “The Code Bakers” (http://www.thecodebakers.org/search/label/�ame), mas é um assunto complexo e difícil de ser resolvido em desenvolvimento de games.

Todo Game Object que está em uma determinada camada pode ser afetado por outros objetos da mesma camada. Por exemplo, a nave e os asteroides no protótipo “AsteroidNuts” est�o na mesma camada e podem se colidir.

Como saber se dois objetos colidiram? Se eles se tocarem ou se tiverem pontos em comum, então podemos deduzir que houve colisão. Todo Game Object tem sua imagem exterior, logo, podemos assumir que esta é a sua “fronteira”? Imagine o �O da figura seguinte. Como detectaríamos colis�o de um objeto como este?

Ilustraç�o 28: Um �ame Object de forma compexa

Realmente, teríamos que delimitar um polígono em volta do Game Object, de modo a testarmos se houve colisão com outro GO.

Podemos simplificar muito o cálculo de colis�o se utilizarmos polígonos simples, como retângulos.

Ilustraç�o 29: Polígono de colis�o retangular

Neste caso, a colisão se resume a determinar se os dois retângulos se inter- cetam. E isto pode ser feito facilmente, tanto no Android, como no iOS.

// Android

private boolean colisao (Rect r1, Rect r2) { if (r1.intersect(r2)) { return true; } return false; } // Objective C – iOS

- (BOOL) colisao: (CGRect) r1 outro: (CGrect) r2 { if (CGRectIntersectsRect(r1,r2)) { return YES; } return NO; }

No Android, temos a classe “android.graphics.Rect”, que possui métodos para lidar com retângulos, e no iOS temos a estrutura CGRect, que representa um retângulo, além da funç�o “C�RectIntersectsRect()”, que verifica se dois retângulos passados se intercetam.

É claro que estamos falando de games 2D, pois para games 3D tudo muda. O problema de usar polígonos retangulares pode ser notado na figura seguinte.

Ilustraç�o 30: Nem sempre retângulos colisores d�o o melhor resultado

Podemos notar que, dependendo da forma e do tamanho dos objetos, um retângulo colisor (o polígono que envolve o �O) pode dar um resulta- do ruim, detetando colisões que poderiam ser evitadas, o que compromete a jogabilidade.

Para resolver este problema, podemos usar outras formas ou “malhas” colisoras.

Ilustraç�o 31: Outros tipos de colisores

Porém, temos outro problema: como vamos detetar colisões? Bem, depen- dendo da forma dos colisores, existem várias maneiras.

Se ambos os objetos usarem colisores circulares, é simples, pois basta comparar a distância entre seus centros e os seus tamanhos somados.

Se forem círculos e polígonos, podemos pegar o segmento de reta do po- lígono que está à frente do círculo, e calcular a distância entre o centro do círculo e a reta, comparando com o raio, ou qualquer variante deste algoritmo. Eu mesmo dei soluç�o para alguns destes problemas em: http://www.the- codebakers.org/2012/10/fisica-de-videogame-4-deteccao-de.html, e inclusive criei uma biblioteca em Java para isto: http://fisica-videogame.googlecode.com/ files/colisoes3.zip.

Se ambos forem polígonos, podemos calcular a interseção de polígonos

convexos.

Um polígono P é considerado convexo se qualquer segmento de reta defi- nido por dois pontos dentro de P se situa dentro de P. Podemos usar o método de projeç�o para sabermos se dois polígonos se intercetam:

1. Selecionamos um dos segmentos do polígono colisor do PLAYER OBJECT PO);

2. Selecionamos os �Os que est�o na mesma faixa Y, ou seja, aqueles que podem estar colidindo com o PO;

3. Selecionamos os �Os que est�o mais próximos (X) dentro da faixa; 4. Para cada �O selecionado, verificamos a interseç�o;

A verificaç�o da interseç�o em si é feita pelo seguinte algoritmo: 1. Pegamos um dos segmentos de reta de um polígono; 2. Calculamos um vetor Ortogonal a ele;

3. Calculamos o produto vetorial do vetor ortogonal por cada vetor de cada outro polígono, usando os pontos iniciais e finais. Isto nos dará valores numéricos reais;

4. Pegamos o máximo e o mínimo de cada produto;

5. Projetamos no segmento. Se houver interseção entre todos os seg- mentos, então os polígonos estão se tocando ou se sobrepondo. Uma boa referência para isto é: http://gamemath.com/2011/09/detecting- whether -two-convex-polygons-overlap/.

Infelizmente, dependendo da complexidade dos polígonos, o cálculo pode demorar demais. Eu propus uma alternativa no post: http://www.thecodebakers. org/2012/11/fisica-de-videogame-5-multirectangle-cd.html, que consiste em divi- dir o problema em simples interseção de retângulos. Para isto, dividimos as imagens em retângulos colisores, conforme a figura seguinte. Neste caso, o segredo é manter o mapeamento entre a posição atual do GO e a de cada re- tângulo colisor.

Ilustraç�o 32: Uma opç�o mais simples de colis�o de objetos complexos

A deteção de colisão é um problema crítico da macrofunção de física de qualquer game. Falhas na

detecção de colisão podem comprometer a jogabilidade, logo, eu recomen- do duas abordagens:

• Se o seu game é muito simples, use retângulos ou círculos e ponto final;

• Se o seu game é mais complexo, use um engine de física.

e

ngineS de fíSica

Para facilitar o desenvolvimento de jogos de ação, foram criadas várias bibliotecas de funções e cálculos de física, chamadas de “Physics engines” (Engines de física, é a forma que eu prefiro). Existem vários engines, sejam gratuitos, pagos, 2D ou 3D. Todos eles servem para calcular: aceleraç�o, mo- vimento, colisão e seus efeitos.

É perfeitamente possível criar um game de ação sem utilizar um engine de física. Na verdade, eu fiz isso em alguns projetos de jogos. O fator a ser analisado na decis�o de uso de um engine é: qual é o valor agregado por uma física mais realista? É certo que uma física mais realista vai demandar maio- res recursos, como: CPU e/ou memória, ent�o, temos que ter certeza de que seu uso vai agregar valor proporcional ao jogador, caso contrário, estaremos introduzindo o risco de “lag” à toa.

Bullet Physics Library

É um engine de física open source desenvolvido por Erwin Coumans. Pode ser baixado do site: http://bulletphysics.org/wordpress/, e sua documen-

taç�o pode ser acessada no link: http://bulletphysics.com/ftp/pub/test/physics/ Bullet_User_Manual.pdf.

O Bullet, além de open source, é multiplataforma. Ele é feito em C++ e pode ser usado em: Sony PLAYSTATION 3, Microsoft XBox 360, Nintendo Wii, PC, Linux, Mac OSX, Android e Apple iOS. Além disto, pode ser inte- grados a softwares de edição 3D, como o Maya, da AutoDesk, e o Blender.

Para ter uma ideia de como o Bullet é profissional, veja só uma pequena lista de games que o utilizam:

• Toy Story 3 (Disney); • �TA IV (Rockstar �ames); • Blood Drive (Activision);

Uma característica importante do Bullet é que a partir da vers�o 2.80 os cálculos de física de corpos sólidos s�o executados pela �PU, utilizando o OpenCL (http://www.khronos.org/opencl/), o que é um grande recurso para evi- tar “lags” devido a cálculos complexos de física.

Chipmunk physics engine

O Chipmunk é um engine completo, também open source, e desenvolvido por Scott Lembcke. Seu site é http://chipmunk-physics.net/. Ele é utilizado em vários games e ferramentas, como o Cocos2D (http://www.cocos2d-iphone.org/).

A versão “pro” é paga, mas tem alguns recursos interessantes, como o “Autogeometry”, que permite criar a malha de colisão diretamente a partir de imagens.

Box2D

O Box2D é uma biblioteca de funções físicas para games totalmente Open Source e gratuita, desenvolvida em C++ por Erin Catto. Seu site é:

http://box2d.org. É uma das mais famosas, talvez por ser uma das mais simples. N�o possui recursos sofisticados, mas permite calcular movimento e colis�o de forma bem realista.

Ela possui versões para várias linguagens, como o JBox2D (http://www. jbox2d.org/), que é bem fiel à biblioteca original. Algo que ajudou a criar a fama do Box2D foi sua utilizaç�o no “blockbuster” Angry Birds (Rovio).

Como eu não posso abordar todos os engines de física em apenas um único livro, escolhi o Box2D, pois, além da preferência pessoal, é muito comentado hoje em dia.

f

íSicacom

b

ox

2d

Antes de continuarmos, é necessário fazer alguns comentários sobre o Bo- x2D. Para começar, ele foi feito em C++ e, para utilizá-lo dentro de aplicações Android, nós teríamos que usar JNI para nos comunicarmos com ele, o que dificultaria um pouco o desenvolvimento. Ent�o, eu optei por ensinar Box2D usando o JBox2D em Java mesmo. Depois, eu explico como isso funciona com o Box2D e o iOS. Assim, muitas vezes eu vou me referir apenas ao Bo- x2D, neste caso, tudo vale também para o JBox2D.

A segunda coisa que precisamos saber é que o Box2D não desenha na tela. Ele apenas calcula posições, sendo sua a responsabilidade de desenhar o que o Box2D calculou.

A terceira coisa é que o Box2D n�o faz referência à origem do plano carte- siano que usa. Na verdade, ele vai trabalhar bem de qualquer forma, pois, para ele n�o existe canto superior esquerdo. Se você vai apresentar alguma imagem baseado nas coordenadas calculadas pelo Box2D, você tem que ajustá-las para a sua “viewport”, ou seja, se está usando um framework gráfico que coloca a origem do eixo das ordenadas no canto superior esquerdo, ent�o você tem que fazer a translação da coordenada “y”.

Finalmente, temos que conversar sobre as unidades e medidas. O Box2D não assume nenhuma unidade, embora esteja ajustado para trabalhar com me- tros. Por exemplo, um retângulo de 50 x 30 o que significa? Pode ser um prédio de 50 metros de largura por 30 de altura, ou pode ser uma caixa de sapato, você é que decide. Em seu manual (http://box2d.org/manual.pdf), ele recomenda que você mantenha seus objetos dinâmicos entre 0,1m e 10m de tamanho (altura e largura), e os objetos estáticos até 50m. É recomendável que você faça a traduç�o entre as medidas do Box2D e as medidas reais na tela, evitando associar diretamente as unidades com pixels. Por exemplo, você criou uma caixa com largura 50 e altura 30 no Box2D e assume que ser�o 50 por 30 pixels. Crie os objetos com um valor de unidade que seja fácil de tra- balhar, calculando a escala para exibição depois.

Isto é muito importante: o Box2D trabalha melhor com objetos dinâmicos

entre 0.1 e 10 metros. Objetos estáticos podem ser maiores. Você tem que criar um fator de escala para traduzir para a tela. NÃO CONVERTA DIRETA- MENTE METROS EM PIXELS!

Preparando o laboratório

Considerando que nem todo mundo tem um Mac ao seu dispor, achei melhor estudarmos os conceitos do Box2D com um laboratório, baseado no JBox2D e em Java. As diferenças são desprezíveis, e podemos trabalhar em qualquer plataforma Desktop. Depois, quando formos estudar a aplicação em dispositivos móveis, nós usaremos o Box2D para iOS e o JBox2D para o Android.

Eu recomendo que você baixe e leia o manual do Box2D (C++): http:// box2d.org/manual.pdf. A definiç�o de todas as funções está nele. Aqui, eu ape- nas listo um resumo. Se quiser o modelo de objetos em Java, leia o JavaDoc do JBox2D, que vem dentro da distribuiç�o. Eu aconselho você a comprarar sempre os dois.

Eu recomendo que você baixe os dois: o Box2D e o JBox2D. Para baixar o Box2D, acesse o link: http://code.google.com/p/box2d/downloads/list e baixe a última vers�o (no meu caso é 2.2.1). E, para baixar o JBox2D, acesse o link:

http://code.google.com/p/jbox2d/downloads/list e baixe a última vers�o (2.1.2.2). Descompacte os dois arquivos em pastas separadas.

O código-fonte deste projeto está junto com os fontes do livro. Veja no capítulo de introduç�o. A pasta é “...\Codigo\JBox2DLab\jbox2lab.zip”. É um projeto “eclipse” compactado, logo, você pode importar para sua “workspace”.

Nota: Configure sua “Workspace” eclipse para trabalhar com caracteres

UTF-8. Abra o menu “Window / Preferences”, expanda o item “�eneral” e clique em “Editors”, clique no link “Content-types”, selecione “Text” e digite “UTF-8” no campo “Default encoding”, pressionando o bot�o “Update”. Isto