I was alerted to KitchenSync, a AS3 tweening library by Mims Wright, on the Adobe blog feed a week or so ago. I was a bit skeptical at first of another tweening library for Flash but I have been searching for a true AS3 replacement to FUSE (I never started working with GOASAP but should probably check it out to). Tweener was ok but as a teacher I prefer libraries with good documentation as it makes a students life easier, which really makes my life easier. Anyway, I had to teach an AS animation class yesterday, which I normally do with Tweener, but decided to give KS 30 minutes to blow my mind. Within 5 minutes I knew I was going to be teaching KS. Good documentation, animation sequencing/paralleling, filter tweening, a dev roadmap and fast response to questions by Mims all told me KS was worth investing some time in and worth teaching to students. I hope to contribute some documentation over time and maybe a student project or two as a showcase. You should at least give it 5 minutes yourself.
I finally found the time to check out what my good friends at Rouxbe have been up to with their newly launched cooking school. There is lots of great content already, can’t wait to do the pasta lessons, and lots more to come. Thinking I was a knife smarty pants I took the “Handling a Chefs Knife” quiz and got a 76% (and learned a few things). Overall I wish I had checked this out earlier as I am really impressed by the content. I am going to be making some time to do all the material. You can try a free lesson on wheat and gluten and/or sign up for a free membership to check out all of Rouxbe’s great video recipes. As always I am super impressed by the quality of all the videos. Keep up the great work Rouxbe team.
As a full disclosure I was the original Flash developer responsible for creating all of the flash players for the Rouxbe site. They did not however ask me to write this and I am not currently working for them.
Revolute joints can be used to create rotating joints (aka motors) or joints with friction. Both types can have angular limits placed on them. Take a look at the TestRagdoll, TestCrankGearsPulley and TestTheoJansen for more examples of how to use this joint type.
The motor features of a revolute joint provide a lot of functionality. Just look at the Crank/Gear/Pulley and Theo Jansen Walker test bed examples for a hint of their potential. When creating a motor the maxMotorTorque is the most import property. Measured in newton meters (N•m), when using the normal units (not converted to pixels as in my example), it determines the amount of mass the motor can rotate. If your motors is not rotating or rotating poorly you likely need to increase its maxMotorTorque. Simple Motor Example:
//Create and setup a revolute joint as a simple motor pivot.position.Set(80,250); var pivotBody1:b2Body = m_world.CreateBody(pivot); pivotBody1.CreateShape(pivotPoly) pivotBody1.SetMassFromShapes(); var motorPoly:b2PolygonDef = new b2PolygonDef(); motorPoly.SetAsOrientedBox(30, 10, new b2Vec2(0, 0), 0); motorPoly.friction = .3; motorPoly.density = .01; motorPoly.restitution = .1; var motorDef:b2BodyDef = new b2BodyDef(); motorDef.position.Set(110, 250); var motorBody:b2Body = m_world.CreateBody(motorDef); motorBody.CreateShape(motorPoly); motorBody.SetMassFromShapes(); //Setup the revolute joint definition for later instantiation. rjd is a predefined b2RevoluteJointDef object. rjd.Initialize(pivotBody1, motorBody, new b2Vec2(80,250)); rjd.motorSpeed = 3; rjd.maxMotorTorque = 10000000; rjd.enableMotor = true; rjd.enableLimit = false; //Create the motor joint and cast it as a b2RevoluteJoint var joint1:b2RevoluteJoint = m_world.CreateJoint(rjd) as b2RevoluteJoint;
Revolute joints are not limited to continuous rotation. You can set upper and lower limits to the joint (in radians). When used with the enableMotor property set to false, this joint is ideal for simulating limbs. See the TestRagdoll example for a great demo of this.
Combining joint limits, motors and conditionals allows for creation of some interesting systems. I could see this used as valves, platforms in games, fins on fish, etc. In this example I have setup a motor to oscillate between its limits.
//Setup a limited revolute joint that oscillates between its limits pivot.position.Set(80,100); var pivotBody2:b2Body = m_world.CreateBody(pivot); pivotBody2.CreateShape(pivotPoly) pivotBody2.SetMassFromShapes(); var limitMotorPoly:b2PolygonDef = new b2PolygonDef(); limitMotorPoly.SetAsOrientedBox(30, 10, new b2Vec2(0, 0), 0); limitMotorPoly.friction = .3; limitMotorPoly.density = .01; limitMotorPoly.restitution = .1; var limitedMotorDef:b2BodyDef = new b2BodyDef(); limitedMotorDef.position.Set(110, 100); var limitedMotorBody:b2Body = m_world.CreateBody(limitedMotorDef); limitedMotorBody.CreateShape(limitMotorPoly); limitedMotorBody.SetMassFromShapes(); //Setup the revolute joint definition for later instantiation rjd.Initialize(pivotBody2, limitedMotorBody, new b2Vec2(80,100)); rjd.motorSpeed = 3; rjd.lowerAngle = 0; //Convert the angle in degrees to radians rjd.upperAngle = 270*(Math.PI/180); rjd.enableLimit = true; rjd.maxMotorTorque = 10000000; rjd.referenceAngle = 0; rjd.enableMotor = true; //Create the motor joint and cast it as a b2RevoluteJoint. Store the joint object in a class var for use later in the update method. limitMotorJoint = m_world.CreateJoint(rjd) as b2RevoluteJoint;
Friction joints are revolute joints with the motor enabled, a non-zero maxMotorTorque and the motor speed set to 0. This will cause the joint to resist rotation but give when the maxMotorTorque is exceeded, giving the effect of a joint with friction at the pivot. Once the force to the joint is removed it stops moving. Example:
//Setup a friction joint pivot.position.Set(190,100); var pivotBody3:b2Body = m_world.CreateBody(pivot); pivotBody3.CreateShape(pivotPoly) pivotBody3.SetMassFromShapes(); var armPoly:b2PolygonDef = new b2PolygonDef(); armPoly.SetAsOrientedBox(90, 10, new b2Vec2(0, 0), 0); armPoly.friction = .5; armPoly.density = .01; armPoly.restitution=0; var armBodyDef:b2BodyDef = new b2BodyDef(); armBodyDef.position.Set(280,100); var armBody = m_world.CreateBody(armBodyDef); armBody.CreateShape(armPoly) armBody.SetMassFromShapes(); rjd.Initialize(pivotBody3, armBody, new b2Vec2(190,100)); rjd.motorSpeed = 0; rjd.maxMotorTorque = 10000000; rjd.enableMotor = true; rjd.enableLimit = false; var joint2:b2RevoluteJoint = m_world.CreateJoint(rjd) as b2RevoluteJoint;
With the release of the 2.0.1 update of Box2D a couple of things have changed. Here are a couple of changes I have found. If you know of more post a comment.
Previously when creating bodies you had to specify if the body was static or dynamic, this is no longer the case. The engine itself will determine the body type based on its density setting. If you set the density of the shapes to 0 the body will be static and any non-zero value will make it dynamic. Example:
//Create a static body var staticPoly:b2PolygonDef = new b2PolygonDef(); staticPoly.SetAsOrientedBox(10, 10, new b2Vec2(0, 0), 0); staticPoly.friction = .5; //Setting the density to 0 will make the body that contains this poly static staticPoly.density = 0; staticPoly.restitution=0; var staticBodyDef:b2BodyDef = new b2BodyDef(); staticBodyDef.position.Set(0,0); var staticBody = m_world.CreateBody(staticBodyDef); //New shape instantiation does not need to define static or dynamic staticBody.CreateShape(staticPoly) staticBody.SetMassFromShapes(); //Create a dynamic body var dynamicPoly:b2PolygonDef = new b2PolygonDef(); dynamicPoly.SetAsOrientedBox(10, 10, new b2Vec2(0, 0), 0); dynamicPoly.friction = .5; //Setting the density to any value greater then 0 will make the body that contains this poly dynamic dynamicPoly.density = 1; dynamicPoly.restitution=0; var dynamicBodyDef:b2BodyDef = new b2BodyDef(); dynamicBodyDef.position.Set(0,0); var dynamicBody = m_world.CreateBody(dynamicBodyDef); //New shape instantiation does not need to define static or dynamic dynamicBody.CreateShape(dynamicPoly) dynamicBody.SetMassFromShapes();
A couple of minor changes have been made to the distance joint type. It now includes a dampening factor and a frequency. I can’t really seem to figure out what they do though. I am probably wrong but I don’t think they are working properly in flash yet.
Joints are one of the most interesting parts of Box2D. Over the next several weeks I will attempt to explain all of the Box2D joint types and possibly add a new one.
Before You Start
I have switched over to pixels as my primary unit for working with Box2D. This was done by changing the scale factor and it impacts defining joints because they use N•m as their units. So now the values used in joints will need to be 30x bigger. Nothing major but if you use the same values as the test bed examples your joint won’t work properly. This will be more important with other joint types.
A distance joint is the simplest of the joints to use. As the name implies it links two bodies together with a rigid connection that maintains the distance between the bodies. Each body is free to rotate and the collideConnected property of the inherited b2JointDef controls whether the bodies collide. The joint itself will not collide with other objects. As with most things in Box2D the vectors that specify the connection points are relative to the world and not the bodies. Example:
//Create a new distance joint definition var djd:b2DistanceJointDef = new b2DistanceJointDef(); //Initialize the joint between two bodies. The b2Vec2() objects are used to define the location of the joint ends. Values are sample only. djd.Initialize(body1, body2, new b2Vec2(0,0),new b2Vec2(0,30)); //Define whether the two objects will be allowed to collide with each other. djd.collideConnected = true; var distJoint:b2DistanceJoint = m_world.CreateJoint(djd);