Arquivo

Textos com Etiquetas ‘jogos’

Box2D, Primeira Simulação

Olá Pessoal, 

Vamos agora aprender como programar com a Engine de Física para Games em Flash Box2D. Neste primeiro exemplo prático iremos mostrar como criar um Mundo e corpos que sofrerão ações e restrições desse mundo.

Quem está lendo este tutorial e ainda não leu o primeiro recomendo que o leia neste link [http://marciosilva.net/2009/04/box2d-a-engine-de-fisica-para-games-em-flash/]. 

Pré-requisitos e Softwares utilizados:

Macromedia Flash CS4

Conhecimento em Física Básica (Cinemática pelo menos).

Conhecimento Intermediário em AS3.

API do Box2D que você pode baixar aqui [http://sourceforge.net/project/showfiles.php?group_id=210232&package_id=252417&release_id=642873]

Faremos algo como o exemplo abaixo:

 

Agora com os pré-requisitos estabelecidos, vamos criar nossa primeira aplicação. Baixe o arquivo ZIP contendo o código do Box2D e descompacte-o. Se por exemplo, você descompactou o box2D dentro de uma pasta chamada C:\game\, então o Box2D ficou com o seguinte caminho C:\game\Box2D\. Para que tudo funcione corretamente, todos os arquivos citados neste tutorial e nos próximos devem estar em C:\game\.  Veja o exemplo:

Exemplo de organização básica

Exemplo de organização básica

Crie um novo arquivo chamado Box2DMX.as. Nele coloque o seguinte código:

?View Code ACTIONSCRIPT
package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	/*importação da API Box2D*/
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
 
	public class Box2DMX extends Sprite
	{
		/* Construtor da classe	*/
		public function Box2DMX()
		{
			init();
		}
 
		/* Incializa a aplicação*/
		private function init():void
		{
			createWorld();
 
			createListeners();
 
			createGround();
		}
 
		/* Define os listeners da simulação/game*/
		private function createListeners():void
		{
			timer = new Timer(1000);
			timer.addEventListener(TimerEvent.TIMER, createBodies);
			timer.start();
			addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
		}
 
		/* Instancia o mundo onde a simulação ocorrerá*/
		private function createWorld():void
		{
			/* Definição dos limite do mundo*/
			var worldAABB:b2AABB = new b2AABB();
			worldAABB.lowerBound.Set(-100.0, -100.0);
			worldAABB.upperBound.Set(100.0, 100.0);
 
			/* Difinição da gravidade atuante em todos os corpos desse mundo*/
			var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
			/* Indica que os corpos devem permanecerem inativos	*/
			var doSleep:Boolean=true;
 
			/* Construção do mundo*/
			world = new b2World(worldAABB, gravity, doSleep);
 
		}
 
		/* Cria o chão onde os corpos ficarão*/
		private function createGround():void
		{
			var body:b2Body;
			var bodyDef:b2BodyDef;
			var boxDef:b2PolygonDef;
 
			bodyDef = new b2BodyDef();
			bodyDef.position.Set(10, 12);
			bodyDef.angle=0.0;
 
			boxDef = new b2PolygonDef();
			boxDef.SetAsBox(90, 3);
			boxDef.friction = 0.1;
 
			/* para corpos que nunca se moverão o
			* valor da densidade deve ser zero
			*/
			boxDef.density = 0;
			bodyDef.userData = new PhysGround();
			bodyDef.userData.width = physScale * 2 * 30;
			bodyDef.userData.height = physScale * 2 * 3;
 
			addChild(bodyDef.userData);
 
			body=world.CreateBody(bodyDef);
			body.CreateShape(boxDef);
			body.SetMassFromShapes();
		}
		/*cria os atores da simulação*/
		private function createBodies(e:Event):void
		{
			/* representa o corpo rígido*/
			var body:b2Body;
 
			/* será utilizado para representar
			* as características físicas do corpo rígido
			*/
			var bodyDef:b2BodyDef;
 
			/*define um polígono e suas características físicas*/
			var boxDef:b2PolygonDef;
 
			/*define um círculo e suas características físicas*/
			var circleDef:b2CircleDef;
 
			bodyDef = new b2BodyDef();
			bodyDef.position.Set(Math.random() * 15+5, 0);
 
			var rX:Number = Math.random() + 0.1;
			var rY:Number = Math.random() + 0.1;
			//Caixa
			if (Math.random() < 0.5)
			{
				boxDef = new b2PolygonDef();
				boxDef.SetAsBox(rX, rY);
				boxDef.density = 1.0;
				boxDef.friction = 0.5;
				boxDef.restitution = 0.2;
 
				bodyDef.userData = new PhysBox();
				bodyDef.userData.width = rX * 2 * physScale;
				bodyDef.userData.height = rY * 2 * physScale; 
 
				body = world.CreateBody(bodyDef);
				body.CreateShape(boxDef);
			}
			else //Círculo
			{
				circleDef = new b2CircleDef();
				circleDef.radius = rX;
				circleDef.density = 1.0;
				circleDef.friction = 0.5;
				circleDef.restitution = 0.2;
 
				bodyDef.userData = new PhysCircle();
				bodyDef.userData.width = rX * 2 * physScale;
				bodyDef.userData.height = rX * 2 * physScale; 
 
				body = world.CreateBody(bodyDef);
				body.CreateShape(circleDef);
			}
 
			bodyDef.userData.x = body.GetPosition().x *physScale ;
			body.SetMassFromShapes();
			addChild(bodyDef.userData);
		}
 
		/*atualiza o posicionamento dos atores*/
		private function Update(e:Event):void
		{
			world.Step(timeStep, iterations);
 
			// Pare cada corpo no mundo atualiza a sua posição e rotação
			for (var body:b2Body = world.GetBodyList (); body; body = body.GetNext())
			{
				if (body.GetUserData() is Sprite)
				{
					body.GetUserData().x = body.GetPosition().x * physScale;//metros para pixels
					body.GetUserData().y = body.GetPosition().y * physScale;//metros para pixels
					body.GetUserData ().rotation = body.GetAngle() * (180/Math.PI);
				}
			}
		}
 
		private var world:b2World;
		private var iterations:int = 10;
		private var timeStep:Number = 1.0/30.0;
		private var physScale = 30.0;
		private var timer:Timer;
 
	}
}

Neste primeiro código podemos destacar a criação do mundo que é realizado determinando seus limites pela classe b2AABB, além de delimitar o mundo você utilizar esta classe para determinar locais em seu game onde os personagens sofrem alguma alteração. Por exemplo, delimitar locais onde existem bombas que explodem se eles passarem por cima,  checkpoints, etc.

Outro ponto que deve ser destacado é a criação de corpos (bodies), a criação de um body segue uma sequência de passos bem definida e lógica:

  1. Define um body com posição;
  2. Usa o obejto world para criar um body;
  3. Define os shapes com geometria, atrito, densidade, etc;
  4. Coloca os shapes no body;
  5. E opcionalmente ajusta a massa do body;

 

Podemos destacar também neste primeiro exemplo o atributo userData, usado por exemplo neste trecho de código:

?View Code ACTIONSCRIPT
bodyDef.userData = new PhysCircle();

O Box2D permite que você crie suas próprias classes de atores e vincule a um body do mundo criado. Por exemplo, você está desenvolvendo um jogo de guerra e uma das suas classes se chama Tanque e dentro da classe tanque existem variáveis que você controla como life, munição, quantidade de inimigos que matou, etc. Portanto, está classe são dados controlados por você. Se você percebeu quem define as propriedades físicas é a classe b2BodyDef, é com ela que você informa ao Box2D como ele deverá tratar o ator aplicando as restrições físicas do mundo criado.

E por fim, temos a linha abaixo:

?View Code ACTIONSCRIPT
world.Step(timeStep, iterations);

Esta linha deve aparecer no Main loop de seu Game, nesse momento o Box2D faz o trabalho duro de calcular colisões, prever contatos, tudo através de cálculos matemáticos. Você não precisa saber como ele faz isso, precisa apenas informar o quão preciso você quer esses cálculos através da variável iterations. Quanto maior o valor dessa variável mais perfeito são os cálculos físicos e matemáticos. No entanto, isso gera um overhead, ou seja, deixa seu jogo mais lento perdendo performance.

Games com Engines, ao contrário de games simples que não possuem engines de cálculos físicos e matemáticos, necessitam de um tempo adicional para que possam aplicar equações complexas para que a simulação possua um pouco de realidade. Esse tempo no Box2D é o timeStep, o game loop ou main loop é necessário apenas para aplicar as novas posições calculadas pelo Box2D.

Um fato importante que deve ser observado é o physScale que indica as escala utilizada pelo Box2D, em Box2D 1(um) metro é igual a 30px. Esse fato deve-se ao fato dos cálculos físicos serem feitos com unidades  internacionais e convencionadas pelos físicos como o metro e não com coordenadas de tela. Dessa forma, no main loop (método update)  é feita uma conversão de metros para pixel, pois após a chamada do método Step() as novas coordenadas calculdas pela Engine foram determinadas, no entanto elas foram calculadas em metros. 

Como a tela do seu munitor tem como unidade de medida e posicionamento o pixel, devemos converter o valor em metros calculado pelo Box2D para pixel como vemos abaixo. E o mesmo vale para outras medidas como altura e largura de objetos na cena.

?View Code ACTIONSCRIPT
body.GetUserData().x = body.GetPosition().x * physScale;//metros para pixels
body.GetUserData().y = body.GetPosition().y * physScale;//metros para pixels

Agora crie um arquivo chamado Box2DMX.fla e na aba properties coloque o nome da classe que deseja linkar.

Aba properties

Aba properties

Agora vamos criar os atores da simulação.  Pressione CTRL + F8 para adicionar um novo símbolo, crie um quadrado de 100px x100px com o nome de PhysBox. Veja figura abaixo:

 

Box

Box

Agora crie da mesma forma um círculo chamado PhysCircle com as dimensões e posicionamento mostrados abaixo:

 

Circle

Circle

 

E por fim crie um movieclip que será o chão de sua simulação, este se chamará PhysGround.

 

Ground

Ground

Para que os movie clips criados acima funcionem com o código, para cada um você irá até a library clicar com o botão direito em cima do PhysBox por exemplo, e depois escolher a opção properties. Uma janela de diálogo se abrirá como a que está ilustrada abaixo para você exportar para o Action Script é só confirmar clicando em OK. Lembre-se de fazer o mesmo para o PhysCircle e o PhysGround.

Exportanto para o Action Script 3.0

Exportanto para o Action Script 3.0

Agora é só salvar os dois arquivos e dar CTRL + ENTER. 

Espero que tenham gostado, até a próxima.

Acesse o link abaixo e baixe os arquivos do tutorial.

Exemplo Box2D download

Categories: Jogos em Flash Tags: , ,

Mortal Kombat VS Street Fighter

Olá Pessoal,

Dois dos maiores sucessos do vídeo game estão juntos nesta edição de vídeo em combos inimagináveis. Não é um Game Play, pois existem combos e golpes nunca antes vistos. Existe uma 3 vídeos que conheço dessa série. O primeiro que encontrei vem logo abaixo, é uma luta entre Ryu e Scorpion. Quem será que ganha?


Este é do Akuma VS Camaleon, esse é meu favorito.

 E por fim Ken VS Raiden:

Esses dois games fizeram e ainda fazem parte da diversão de muita gente.

Categories: Jogos em geral Tags: ,