Skip to content

C2D 07 Adding Physics

Robert Silverton edited this page Aug 12, 2013 · 7 revisions

Making objects in a Cadet Scene behave in a physically realistic way is something that can be achieved using a combination of Geometry, Behaviours and a Process.

Adding Physics screenshot

All of the Components required to achieve this already exist in the Cadet Library, so we can get up and running with a physics scene fairly quickly. In later tutorials we will show how you can add your own Behaviours to manipulate these physical objects, but for now we will simply get a working example running.

The Cadet2DBox2D library contains behaviours and processes which are designed to add 2D physics to a 2D scene, hence Cadet2D-Box2D.

For this example, create a new class named CadetHelloPhysics in the default package, set it to be the default application and copy and paste the code below into it.

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	
	import cadet.core.CadetScene;
	import cadet.core.ComponentContainer;
	
	import cadet2D.components.geom.RectangleGeometry;
	import cadet2D.components.renderers.Renderer2D;
	import cadet2D.components.skins.GeometrySkin;
	import cadet2D.components.transforms.Transform2D;
	
	import cadet2DBox2D.components.behaviours.RigidBodyBehaviour;
	import cadet2DBox2D.components.behaviours.RigidBodyMouseDragBehaviour;
	import cadet2DBox2D.components.processes.PhysicsProcess;
	
	[SWF( width="700", height="400", backgroundColor="0x002135", frameRate="60" )]
	public class CadetHelloPhysics extends Sprite
	{
		private var cadetScene	: CadetScene;
		
		public function CadetHelloPhysics()
		{
			cadetScene = new CadetScene();
			
			var renderer:Renderer2D = new Renderer2D();
			renderer.viewportWidth = stage.stageWidth;
			renderer.viewportHeight = stage.stageHeight;
			cadetScene.children.addItem(renderer);
			renderer.enable(this);
			
			cadetScene.children.addItem( new PhysicsProcess() );
			
			for ( var i:int = 0; i < 30; i++ )
			{
				var x:Number = Math.random() * stage.stageWidth;
				var y:Number = Math.random() * 100;
				var width:Number = 20 + Math.random() * 20;
				var height:Number = 20 + Math.random() * 20;
				addRectangleEntity( x, y, width, height );
			}
			
			// Create the floor. We pass 'true' as the 'fixed' property to make the floor static.
			addRectangleEntity( 0, stage.stageHeight-50, stage.stageWidth, 50, true );
			
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);			
		}
		
		private function addRectangleEntity( x:Number, y:Number, width:Number, height:Number, fixed:Boolean = false ):ComponentContainer
		{
			var entity:ComponentContainer = new ComponentContainer();
			entity.children.addItem( new Transform2D(x, y) );
			entity.children.addItem( new GeometrySkin() );
			entity.children.addItem( new RectangleGeometry(width, height) );
			entity.children.addItem( new RigidBodyBehaviour(fixed) );
			entity.children.addItem( new RigidBodyMouseDragBehaviour() );
			
			cadetScene.children.addItem(entity);
			
			return entity;
		}
		
		private function enterFrameHandler( event:Event ):void
		{
			cadetScene.step();
		}
	}
}

In the constructor we are still creating a CadetScene and a Renderer2D as usual. What’s new is the PhysicsProcess Component we’re adding in initScene(). This Process is responsible for wrapping up a physics engine and stepping the simulation, in this case, the engine is Box2D. If you take a look at addRectangleEntity() you'll see that besides the usual Transform2D, RectangleGeometry and GeometrySkin, we're also adding two new behaviours: RigidBodyBehaviour and RigidBodyMouseDragBehaviour.

The RigidBodyBehaviour wraps up a Box2D body and associates it with the behaviour's siblings: Transform2D and RectangleGeometry via the addSiblingReference() function, seen earlier. The PhysicsProcess is responsible for stepping the Box2D simulation, but when each RigidBodyBehaviour is stepped, the matrix (scale, rotation, translation) of the Box2D body is passed to the Transform2D. The GeometrySkin listens in to changes in the Transform2D, so is updated after the RigidBodyBehaviour is stepped.

The RigidBodyMouseDragBehaviour listens in to TouchEvents from the Renderer2D viewport, which it grabs a reference to via addSceneReference(). If the behaviour has a Skin as a sibling, it checks to see whether that Skin has been interacted with; if so, a Box2D mouse joint is created between the mouse position and the Box2D body on the RigidBodyBehaviour, hence RigidBodyMouseDragBehaviour.

< Previous | Next >