Skip to content

C2D 08 Applying Forces

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

In our AnimateRotationBehaviour we directly alter the ‘rotation’ property of the Transform2D instance via the step() method. When we are using RigidBodyBehaviours, we can no longer do this. This is because the Transform2D of the ComponentContainer is now derived from the position/rotation of the rigid body being simulated by Box2D. One of the tasks the RigidBodyBehaviour performs is to update the Transform2D of the ComponentContainer each step() so it matches the internal position/rotation of the Box2D rigid body – so any other Behaviours directly affecting the Transform2D will have their changes wiped out each step() by the RigidBodyBehaviour.

Apply Torque screenshot

Directly setting the position or rotation of non-fixed rigid body will tend to cause some unnatural-looking behaviour in your scene. In order to affect the position / rotation of a Component being controlled by a RigidBodyBehaviour in a more natural way, we need to use forces.

We will be using some classes and methods from the Box2D library for this example. Full documentation for the library can be found at: http://box2dflash.sourceforge.net/

Let’s begin by creating a new Behaviour Component, called ApplyTorqueBehaviour.

Before we continue, let’s have a quick GSCE Physics recap.

  • Force is measured in Newtons. In Box2D we can apply a force to a rigid body.
  • Force is converted into acceleration by dividing it by the object’s mass. A = F/M.
  • Applying the same force to 2 objects, one twice as heavy as the other, results in an acceleration half the size on the heavier object.
  • Acceleration is the change in velocity over time. It is integrated into the object’s velocity.
  • Velocity is the change in position over time. It is integrated into the object’s position.

These same principles apply to an object’s rotational properties. They just have different names.

  • Angular force is still measured in Newtons.
  • Angular force is converted into torque by dividing is by the object’s mass. T = F/M.
  • Torque is the change in angular velocity over time. It is integrated into the object’s angular velocity.
  • Angular velocity is the change in rotation over time. It is integrated into the object’s rotation.

To summarise:

Generally speaking, rather than setting Acceleration, Velocity or Position in a physics system it is better for these values to be derived by applying forces.

Linear Force:

Acceleration = Force / Mass New Velocity = Velocity + Acceleration New Position = Position + New Velocity

Angular Force:

Torque = Force / Mass New Angular Velocity = Angular Velocity + Torque New Rotation = Rotation + New Angular Velocity


Create the following class:

package cadetHelloWorld.components.behaviours
{
	import cadet.core.Component;
	import cadet.core.ISteppableComponent;
	import cadet2DBox2D.components.behaviours.RigidBodyBehaviour;
	
	public class ApplyTorqueBehaviour extends Component implements ISteppableComponent
	{
		public var rigidBodyBehaviour			:RigidBodyBehaviour;
		public var torque				:Number;
		public var targetVelocity			:Number;
		
		public function ApplyTorqueBehaviour( torque:Number = 50, targetVelocity:Number = 2 )
		{
			this.torque = torque;
			this.targetVelocity = targetVelocity;
		}
		
		override protected function addedToParent():void
		{
			addSiblingReference( RigidBodyBehaviour, "rigidBodyBehaviour" );
		}
		
		public function step(dt:Number):void
		{
			// If we're not attached to an Entity with a RigidBodyBehaviour, then skip.
			if ( !rigidBodyBehaviour ) return;
			
			// Calculate a ratio where 0.5 means we're spinning at half the target speed, and 1 means full speed.
			var ratio:Number = rigidBodyBehaviour.getAngularVelocity() / targetVelocity;
			
			// Scale the torque value by the opposite of the ratio, so as we near the target
			// velocity, we reduce the amount of torque applied.
			rigidBodyBehaviour.applyTorque((1-ratio)*torque);
		}
	}
}

Hopefully most of this is pretty familiar by now. This class is very similar to the AnimationRotationBehaviour we created earlier, but instead of directly affecting an objects rotation, we are doing it indirectly via the applyTorque() method found on the RigidBodyBehaviour class. The logic of how we are calculating the amount of torque to apply works much like a thermostat, applying more torque the further away from the target we are.

To see this working in your scene, add the following code to your application's constructor:

var rotatingRectangle:ComponentContainer = addRectangleEntity( 0, 0, 100, 100 );
rotatingRectangle.children.addItem( new ApplyTorqueBehaviour(50,2) );

...like so...

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 );
}
			
var rotatingRectangle:ComponentContainer = addRectangleEntity( 0, 0, 100, 100 );
rotatingRectangle.children.addItem( new ApplyTorqueBehaviour(50,2) );

// 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);

You may need to run the scene a few times before the box makes it all the way across – remember, you can give it a nudge by dragging it with your mouse.

< Previous | Next >

Clone this wiki locally