Arquivo

Textos com Etiquetas ‘Flash’

Box2D, Modo DebugDraw

Olá Pessoal,

Dando continuação ao último tutorial, será mostrado como utilizar o modo de debug do Box2D chamado de DebugDraw. Com esse modo você poderá analisar visualmente como estão ocorrendo as colisões, contatos, onde estão os centros de massa, que objetos estão “dormindo”, entre outras análises.

Para exemplificar esse modo será utilizado o mesmo código do artigo anterior que pode ser visualizado em http://marciosilva.net/2009/04/box2d-primeira-simulacao/. Um preview do que será feito está logo abaixo:

Algumas adaptações serão necessárias para colocar o DebugDraw no exemplo anteriormente visto. Primeiramente será necessário importar a classe MovieClip e demais modificações que podem ser vistas no código abaixo:

?View Code ACTIONSCRIPT
package
{
	import flash.display.Sprite;
        /*novo import*/
	import flash.display.MovieClip;
 
	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();
 
			debugDraw();
		}
 
                /*Método que realiza o DebugDraw*/
		private function debugDraw():void
		{
			var m_sprite:Sprite;
			m_sprite = new Sprite();
 
			addChild(m_sprite);
 
			debug = new b2DebugDraw();
 
			debug.m_sprite=m_sprite;
			/*escala padrão do Box2D 30px = 1m*/
			debug.m_drawScale=30;
 
			debug.m_alpha = 1;
 
			debug.m_fillAlpha=0.5;
 
			debug.m_lineThickness=1;
 
			debug.m_drawFlags = b2DebugDraw.e_shapeBit
				|b2DebugDraw.e_jointBit
				|b2DebugDraw.e_coreShapeBit
				|b2DebugDraw.e_aabbBit
				|b2DebugDraw.e_obbBit
				|b2DebugDraw.e_pairBit
				|b2DebugDraw.e_centerOfMassBit;
 
			/*aplica ao mundo o modo debug*/
			world.SetDebugDraw(debug);
		}
		/* Define os listeners da simulação/game*/
		private function createListeners():void
		{
			timer = new Timer(2000);
			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.4;
 
			/* 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 MovieClip();
				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 MovieClip();
				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;
                /*novo atributo para aplicar o DebugDraw*/
		private var debug:b2DebugDraw;
 
	}
}

As modificações começaram com a adição da classe MovieClip que será usada como dado do usuário:

?View Code ACTIONSCRIPT
package
{
	import flash.display.Sprite;
        /*novo import*/
	import flash.display.MovieClip;

Aos atributos foi adicionado um novo que serve para realizar o DebugDraw da classe b2DebugDraw:

?View Code ACTIONSCRIPT
		private var physScale = 30.0;
		private var timer:Timer;
                /*novo atributo para aplicar o DebugDraw*/
		private var debug:b2DebugDraw;
 
	}
}

Tanto para criar o círculo quanto para criar os poligonos a classe de dado de usuários é a classe MovieClip, com ela fica mais fácil visualizar o comportamento dos corpos quanto ao seu estado de atividade que veremos mais à frente no texto:

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

A mudança mais importante foi a criação de um novo método chamado debugDraw():

?View Code ACTIONSCRIPT
private function debugDraw():void
{
	var m_sprite:Sprite;
	m_sprite = new Sprite();
	addChild(m_sprite);
	debug = new b2DebugDraw();
 
	debug.m_sprite=m_sprite;
	/*escala padrão do Box2D 30px = 1m*/
	debug.m_drawScale=30;
	debug.m_alpha = 1;
 
	debug.m_fillAlpha=0.5;
 
	debug.m_lineThickness=1;
 
	debug.m_drawFlags = b2DebugDraw.e_shapeBit
		|b2DebugDraw.e_jointBit /*mostra todos os Joints da Cena*/
		|b2DebugDraw.e_coreShapeBit /*utilizaado para observar colisões contínuas*/
		|b2DebugDraw.e_aabbBit /*mostra o eixo de coordenados dos corpos*/
		|b2DebugDraw.e_obbBit /*mostra os bouding boxes*/
		|b2DebugDraw.e_pairBit /*mostra um vetor que parte do centro dos corpos para os outros que estão em contado*/
		|b2DebugDraw.e_centerOfMassBit ;/*mostra o centro de massa dos Corpos*/
	/*aplica ao mundo o modo debug*/
	world.SetDebugDraw(debug);
}

debug.m_drawFlags é um inteiro sem sinal com 7 bits que podem estar ligados ou não dependendo do OR (OU) resultante da combinação de uma mais flags unidos pelo OR bit a bit representado pelo ‘|’, comumente chamado de Pipe.

No debugdraw você também observa que alguns corpos possuem cores diferentes de outros. A cor vermelha indica que o corpo está dormindo, ou seja, o existem cálculos matemáticos/físicos sendo realizados para ele, esse fato é muito é muito importante para que haja uma maior performance reduzindo o consumo de processamento desnecessarimante. Os corpos cinzas estão em movimento, e os verdes são corpos estáticos, como por exemplo paredes e obstáculos.

Estados

Estados

Os arquivos deste tutorial podem ser baixados aqui:
Box2D DebugDraw download

Faça diversas combinações dessas flags para você verificar visualmente como os corpos se comportam. Até a próxima.

Box2D, a Engine de física para Games em Flash

12, abril, 2009 Márcio Silva 2 comentários
Box2D Home Page

Box2D Home Page

Olá Pessoal,

De hoje em diante começarei um conjunto de tutoriais que explicam o funcionamento básico de uma grande ferramenta para os desenvolvedores de Games em flash. Trata-se de uma poderosa API para simulação Física de Corpos Rígidos, é de extrema importância que você tenha familiaridade com conceitos físicos como: massa, força, atrito, colisão, inércia, movimento, dentre outros conceitos que estão intimamente ligados a Dinâmica de Corpos Rígidos.

 

Exemplos do que pode ser feito com o Box2D. Use as setas do teclado para fazer o objeto andar.


Fonte: Emanuele Feronato.

De forma alguma darei uma aula de física aqui, dessa forma, procure conteúdos pela internet que falem sobre os itens que citei acima. No entanto, basta pedir que indicarei links para que vocês possam estudar. De imediato posso indicar um dos melhores sites para que você possa procurar sobre esses conteúdos: 

Wikipédia aqui você irá encontrar com certeza os tópicos que mencionei acima.

Também assumirei que você conhece muito bem Action Script 3.0 ou AS3, pois também não é o intuito aqui ensinar como criar uma classe no AS3 ou manipular o Macromédia Flash. O principlal objetivo é o mostrar o funcionamento de Engine da Física no flash, mostrar os principais conceitos de física empregados em cada linha de código.

Nesse primeiro artigo, apresentarei os conceitos mais básicos que você necessita saber antes de prosseguir.

ATENÇÃO: Se não entender a definição dos termos apresentados abaixo, não adianta prosseguir nos próximos artigos, pois não entenderá nada do que estará acontecendo. Sei que provavelmente você pode fazer um CTRL + C e CTRL + V do código para testar o funcionamento. Mas e aí? Você vai aprender alguma coisa fazendo assim? E se funcionar claro, pois muita gente copia e dá um monte de erro, pois as belas Aspas “” do HTML causam esses erros.

Bom, avisos dados agora vamos ao que interessa, alguns termos eu deixarei em inglês mesmo, por que é da forma que aparecerá na API. Os conceitos iniciais são os seguintes:

Rigid Body / Corpo Rigido: Este é um dos mais importantes conceitos, a idéia básica é que em um corpo rígido se marcarmos dois pontos neste corpo, a distância entre esses dois pontos será sempre constante. Exemplo: um diamente. Na API esse corpo rígido se chamará body

Shape/ Forma: É qualquer parte da Geometria 2D fixada ao corpo rígido. Ela pode possuir propriedades físicas como atrito e restituição.

Constraint / Restrição: Uma restrição remove graus de liberdade de um corpo. Em 2d existem 3 graus de liberdade e em 3D existem 6. No caso de 2D um corpo pode transladar (deslocar) sobre qualquer um dos eixos (x, y) e realizar um movimento de rotação em torno do eixo perpendicular ao plano formado por x e y. Se pendurarmos um corpo numa parede como se fosse um pêndulo, estaremos retirando 2 Graus de liberdade desse corpo, pois ele conseguirá apenas realizar rotações em torno do eixo de fixação.

Contact Constraint / Restrição de contato: Nada mais é do que não permitir que dois corpos possam penetrar um no outro, aí vem a famosa lei de Newton: “Dois corpos não podem ocupar o mesmo lugar ao mesmo tempo”. Esta restrição é implementada pelo próprio Box2D.

Joint / Junção: É uma restrição para manter 2 ou mais corpos rígidos ligados. A Junção pode ser Limite e Motora.

Joint Limit / Junção Limite: Uma junção limite restringe a amplitude de movimento de uma articulação. Pode representar um braço humano por exemplo.

Joint Motor / Junção Motora: Junção motora coordena o movimenta de corpos conectados conforme os graus de liberdade.

World / Mundo: É um conjunto de corpos, formas, e restrições que interagem entre si.

Espero que tenham assimilado os conceitos básicos apresentados na API, eles são importantes para que você entenda os códigos que serão estudados.

Até a próxima.

Fonte: http://www.box2d.org e http://www.emanueleferonato.com