Liquidfun links
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
# Joints
|
||||
|
||||
[About](#about)<br/>
|
||||
[Joint Definition](#jd)<br/>
|
||||
[Joint Factory](#jf)<br/>
|
||||
[Using Joints](#uj)<br/>
|
||||
|
||||
<a name="about">
|
||||
|
||||
## About
|
||||
|
||||
Joints are used to constrain bodies to the world or to each other. Typical
|
||||
examples in games include ragdolls, teeters, and pulleys. Joints can be
|
||||
combined in many different ways to create interesting motions.
|
||||
|
||||
Some joints provide limits so you can control the range of motion. Some joint
|
||||
provide motors which can be used to drive the joint at a prescribed speed
|
||||
until a prescribed force/torque is exceeded.
|
||||
|
||||
Joint motors can be used in many ways. You can use motors to control position
|
||||
by specifying a joint velocity that is proportional to the difference between
|
||||
the actual and desired position. You can also use motors to simulate joint
|
||||
friction: set the joint velocity to zero and provide a small, but significant
|
||||
maximum motor force/torque. Then the motor will attempt to keep the joint from
|
||||
moving until the load becomes too strong.
|
||||
|
||||
<a name="jd">
|
||||
## Joint Definition
|
||||
|
||||
Each joint type has a definition that derives from b2JointDef. All joints are
|
||||
connected between two different bodies. One body may static. Joints between
|
||||
static and/or kinematic bodies are allowed, but have no effect and use some
|
||||
processing time.
|
||||
|
||||
You can specify user data for any joint type and you can provide a flag to
|
||||
prevent the attached bodies from colliding with each other. This is actually
|
||||
the default behavior and you must set the collideConnected Boolean to allow
|
||||
collision between to connected bodies.
|
||||
|
||||
Many joint definitions require that you provide some geometric data. Often a
|
||||
joint will be defined by anchor points. These are points fixed in the attached
|
||||
bodies. LiquidFun requires these points to be specified in local coordinates.
|
||||
This way the joint can be specified even when the current body transforms
|
||||
violate the joint constraint --- a common occurrence when a game is saved and
|
||||
reloaded. Additionally, some joint definitions need to know the default
|
||||
relative angle between the bodies. This is necessary to constrain rotation
|
||||
correctly.
|
||||
|
||||
Initializing the geometric data can be tedious, so many joints have
|
||||
initialization functions that use the current body transforms to remove much
|
||||
of the work. However, these initialization functions should usually only be
|
||||
used for prototyping. Production code should define the geometry directly.
|
||||
This will make joint behavior more robust.
|
||||
|
||||
The rest of the joint definition data depends on the joint type. We cover
|
||||
these now.
|
||||
|
||||
<a name="jf">
|
||||
## Joint Factory
|
||||
|
||||
Joints are created and destroyed using the world factory methods. This brings
|
||||
up an old issue:
|
||||
|
||||
Caution
|
||||
|
||||
Don't try to create a joint on the stack or on the heap using new or malloc. You must create and destroy bodies and joints using the create and destroy methods of the b2World class.
|
||||
|
||||
Here's an example of the lifetime of a revolute joint:
|
||||
|
||||
`b2RevoluteJointDef jointDef;`<br/>
|
||||
`jointDef.bodyA = myBodyA;`<br/>
|
||||
`jointDef.bodyB = myBodyB;`<br/>
|
||||
`jointDef.anchorPoint = myBodyA->GetCenterPosition();`<br/>
|
||||
`b2RevoluteJoint* joint =
|
||||
(b2RevoluteJoint*)myWorld->CreateJoint(&jointDef);`<br/>
|
||||
`… do stuff …`<br/>
|
||||
`myWorld->DestroyJoint(joint);`<br/>
|
||||
`joint = NULL;`<br/>
|
||||
|
||||
It is always good to nullify your pointer after they are destroyed. This will
|
||||
make the program crash in a controlled manner if you try to reuse the pointer.
|
||||
|
||||
The lifetime of a joint is not simple. Heed this warning well:
|
||||
|
||||
Caution
|
||||
|
||||
Joints are destroyed when an attached body is destroyed.
|
||||
|
||||
This precaution is not always necessary. You may organize your game engine so
|
||||
that joints are always destroyed before the attached bodies. In this case you
|
||||
don't need to implement the listener class. See the section on Implicit
|
||||
Destruction for details.
|
||||
|
||||
<a name="uj">
|
||||
## Using Joints
|
||||
|
||||
Many simulations create the joints and don't access them again until they are
|
||||
destroyed. However, there is a lot of useful data contained in joints that you
|
||||
can use to create a rich simulation.
|
||||
|
||||
First of all, you can get the bodies, anchor points, and user data from a
|
||||
joint.
|
||||
|
||||
`b2Body* GetBodyA();`
|
||||
|
||||
`b2Body* GetBodyB();`
|
||||
|
||||
`b2Vec2 GetAnchorA();`
|
||||
|
||||
`b2Vec2 GetAnchorB();`
|
||||
|
||||
`void* GetUserData();`
|
||||
|
||||
All joints have a reaction force and torque. This the reaction force applied
|
||||
to body 2 at the anchor point. You can use reaction forces to break joints or
|
||||
trigger other game events. These functions may do some computations, so don't
|
||||
call them if you don't need the result.
|
||||
|
||||
`b2Vec2 GetReactionForce();`<br/>
|
||||
|
||||
`float32 GetReactionTorque();`<br/>
|
||||
|
||||
### Distance Joint
|
||||
|
||||
One of the simplest joint is a distance joint which says that the distance
|
||||
between two points on two bodies must be constant. When you specify a distance
|
||||
joint the two bodies should already be in place. Then you specify the two
|
||||
anchor points in world coordinates. The first anchor point is connected to
|
||||
body 1, and the second anchor point is connected to body 2. These points imply
|
||||
the length of the distance constraint.
|
||||
|
||||
<img align="center" src="image_18.gif" alt="Distance joint" height="118"
|
||||
width="155"><br/>
|
||||
|
||||
Here is an example of a distance joint definition. In this case we decide to
|
||||
allow the bodies to collide.
|
||||
|
||||
`b2DistanceJointDef jointDef;`<br/>
|
||||
`jointDef.Initialize(myBodyA, myBodyB, worldAnchorOnBodyA,
|
||||
worldAnchorOnBodyB);`<br/>
|
||||
`jointDef.collideConnected = true;`<br/>
|
||||
|
||||
The distance joint can also be made soft, like a spring-damper connection. See
|
||||
the Web example in the testbed to see how this behaves.
|
||||
|
||||
Softness is achieved by tuning two constants in the definition: frequency and
|
||||
damping ratio. Think of the frequency as the frequency of a harmonic
|
||||
oscillator (like a guitar string). The frequency is specified in Hertz.
|
||||
Typically the frequency should be less than a half the frequency of the time
|
||||
step. So if you are using a 60Hz time step, the frequency of the distance
|
||||
joint should be less than 30Hz. The reason is related to the Nyquist frequency.
|
||||
|
||||
The damping ratio is non-dimensional and is typically between 0 and 1, but can
|
||||
be larger. At 1, the damping is critical (all oscillations should vanish).
|
||||
|
||||
`jointDef.frequencyHz = 4.0f;`<br/>
|
||||
`jointDef.dampingRatio = 0.5f;`<br/>
|
||||
|
||||
### Revolute Joint
|
||||
|
||||
A revolute joint forces two bodies to share a common anchor point, often
|
||||
called a hinge point. The revolute joint has a single degree of freedom: the
|
||||
relative rotation of the two bodies. This is called the joint angle.
|
||||
|
||||
<img align="center" src="image_19.gif" alt="Revolute joint" height="97"
|
||||
width="139"><br/>
|
||||
|
||||
To specify a revolute you need to provide two bodies and a single anchor point
|
||||
in world space. The initialization function assumes that the bodies are
|
||||
already in the correct position.
|
||||
|
||||
In this example, two bodies are connected by a revolute joint at the first
|
||||
body's center of mass.
|
||||
|
||||
`b2RevoluteJointDef jointDef;`<br/>
|
||||
`jointDef.Initialize(myBodyA, myBodyB,
|
||||
myBodyA->GetWorldCenter());`<br/>
|
||||
|
||||
The revolute joint angle is positive when bodyB rotates CCW about the angle
|
||||
point. Like all angles in LiquidFun, the revolute angle is measured in
|
||||
radians. By convention the revolute joint angle is zero when the joint is
|
||||
created using Initialize(), regardless of the current rotation of the two
|
||||
bodies.
|
||||
|
||||
In some cases you might wish to control the joint angle. For this, the
|
||||
revolute joint can optionally simulate a joint limit and/or a motor.
|
||||
|
||||
A joint limit forces the joint angle to remain between a lower and upper
|
||||
bound. The limit will apply as much torque as needed to make this happen. The
|
||||
limit range should include zero, otherwise the joint will lurch when the
|
||||
simulation begins.
|
||||
|
||||
A joint motor allows you to specify the joint speed (the time derivative of
|
||||
the angle). The speed can be negative or positive. A motor can have infinite
|
||||
force, but this is usually not desirable. Recall the eternal question:
|
||||
|
||||
*"What happens when an irresistible force meets an immovable object?"*
|
||||
|
||||
I can tell you it's not pretty. So you can provide a maximum torque for the
|
||||
joint motor. The joint motor will maintain the specified speed unless the
|
||||
required torque exceeds the specified maximum. When the maximum torque is
|
||||
exceeded, the joint will slow down and can even reverse.
|
||||
|
||||
You can use a joint motor to simulate joint friction. Just set the joint speed
|
||||
to zero, and set the maximum torque to some small, but significant value. The
|
||||
motor will try to prevent the joint from rotating, but will yield to a
|
||||
significant load.
|
||||
|
||||
Here's a revision of the revolute joint definition above; this time the joint
|
||||
has a limit and a motor enabled. The motor is setup to simulate joint friction.
|
||||
|
||||
b2RevoluteJointDef jointDef;
|
||||
jointDef.Initialize(bodyA, bodyB, myBodyA->GetWorldCenter());
|
||||
jointDef.lowerAngle = -0.5f * b2_pi; // -90 degrees
|
||||
jointDef.upperAngle = 0.25f * b2_pi; // 45 degrees
|
||||
jointDef.enableLimit = true;
|
||||
jointDef.maxMotorTorque = 10.0f;
|
||||
jointDef.motorSpeed = 0.0f;
|
||||
jointDef.enableMotor = true;
|
||||
|
||||
You can access a revolute joint's angle, speed, and motor torque.
|
||||
|
||||
`float32 GetJointAngle() const;`<br/>
|
||||
`float32 GetJointSpeed() const;`<br/>
|
||||
`float32 GetMotorTorque() const;`<br/>
|
||||
|
||||
You also update the motor parameters each step.
|
||||
|
||||
`void SetMotorSpeed(float32 speed);`<br/>
|
||||
`void SetMaxMotorTorque(float32 torque);`<br/>
|
||||
|
||||
Joint motors have some interesting abilities. You can update the joint speed
|
||||
every time step so you can make the joint move back-and-forth like a sine-wave
|
||||
or according to whatever function you want.
|
||||
|
||||
`... Game Loop Begin ...`<br/>
|
||||
`myJoint->SetMotorSpeed(cosf(0.5f * time));`<br/>
|
||||
`... Game Loop End ...`<br/>
|
||||
|
||||
You can also use joint motors to track a desired joint angle. For example:
|
||||
|
||||
`... Game Loop Begin ...`<br/>
|
||||
`float32 angleError = myJoint->GetJointAngle() -
|
||||
angleTarget;`<br/>
|
||||
`float32 gain = 0.1f;`<br/>
|
||||
`myJoint->SetMotorSpeed(-gain * angleError);`<br/>
|
||||
`... Game Loop End ...`<br/>
|
||||
|
||||
Generally your gain parameter should not be too large. Otherwise your joint
|
||||
may become unstable.
|
||||
|
||||
### Prismatic Joint
|
||||
|
||||
A prismatic joint allows for relative translation of two bodies along a
|
||||
specified axis. A prismatic joint prevents relative rotation. Therefore, a
|
||||
prismatic joint has a single degree of freedom.
|
||||
|
||||
<img align="center" src="image_20.gif" alt="Prismatic joint" height="134"
|
||||
width="165"><br/>
|
||||
|
||||
The prismatic joint definition is similar to the revolute joint description;
|
||||
just substitute translation for angle and force for torque. Using this analogy
|
||||
provides an example prismatic joint definition with a joint limit and a
|
||||
friction motor:
|
||||
|
||||
`b2PrismaticJointDef jointDef;`<br/>
|
||||
`b2Vec2 worldAxis(1.0f, 0.0f);`<br/>
|
||||
`jointDef.Initialize(myBodyA, myBodyB,
|
||||
myBodyA->GetWorldCenter(), worldAxis);`<br/>
|
||||
`jointDef.lowerTranslation = -5.0f;`<br/>
|
||||
`jointDef.upperTranslation = 2.5f;`<br/>
|
||||
`jointDef.enableLimit = true;`<br/>
|
||||
`jointDef.maxMotorForce = 1.0f;`<br/>
|
||||
`jointDef.motorSpeed = 0.0f;`<br/>
|
||||
`jointDef.enableMotor = true;`<br/>
|
||||
|
||||
The revolute joint has an implicit axis coming out of the screen. The
|
||||
prismatic joint needs an explicit axis parallel to the screen. This axis is
|
||||
fixed in the two bodies and follows their motion.
|
||||
|
||||
Like the revolute joint, the prismatic joint translation is zero when the
|
||||
joint is created using Initialize(). So be sure zero is between your lower and
|
||||
upper translation limits.
|
||||
|
||||
Using a prismatic joint is similar to using a revolute joint. Here are the
|
||||
relevant member functions:
|
||||
|
||||
`float32 GetJointTranslation() const;`
|
||||
|
||||
`float32 GetJointSpeed() const;`
|
||||
|
||||
`float32 GetMotorForce() const;`
|
||||
|
||||
`void SetMotorSpeed(float32 speed);`
|
||||
|
||||
`void SetMotorForce(float32 force);`
|
||||
|
||||
### Pulley Joint
|
||||
|
||||
A pulley is used to create an idealized pulley. The pulley connects two bodies
|
||||
to ground and to each other. As one body goes up, the other goes down. The
|
||||
total length of the pulley rope is conserved according to the initial
|
||||
configuration.
|
||||
|
||||
length1 + length2 == constant
|
||||
|
||||
You can supply a ratio that simulates a block and tackle. This causes one side
|
||||
of the pulley to extend faster than the other. At the same time the constraint
|
||||
force is smaller on one side than the other. You can use this to create
|
||||
mechanical leverage.
|
||||
|
||||
length1 + ratio * length2 == constant
|
||||
|
||||
For example, if the ratio is 2, then length1 will vary at twice the rate of
|
||||
length2. Also the force in the rope attached to body1 will have half the
|
||||
constraint force as the rope attached to body2.
|
||||
|
||||
<img align="center" src="image_21.gif" alt="Pulley joint" height="213"
|
||||
width="237"><br/>
|
||||
|
||||
Pulleys can be troublesome when one side is fully extended. The rope on the
|
||||
other side will have zero length. At this point the constraint equations
|
||||
become singular (bad). You should configure collision shapes to prevent this.
|
||||
|
||||
Here is an example pulley definition:
|
||||
|
||||
`b2Vec2 anchor1 = myBody1->GetWorldCenter();`<br/>
|
||||
`b2Vec2 anchor2 = myBody2->GetWorldCenter();`<br/>
|
||||
`b2Vec2 groundAnchor1(p1.x, p1.y + 10.0f);`<br/>
|
||||
`b2Vec2 groundAnchor2(p2.x, p2.y + 12.0f);`<br/>
|
||||
`float32 ratio = 1.0f;`<br/>
|
||||
`b2PulleyJointDef jointDef;`<br/>
|
||||
`jointDef.Initialize(myBody1, myBody2, groundAnchor1,
|
||||
groundAnchor2, anchor1, anchor2, ratio);`<br/>
|
||||
|
||||
Pulley joints provide the current lengths.
|
||||
|
||||
`float32 GetLengthA() const;`<br/>
|
||||
`float32 GetLengthB() const;`<br/>
|
||||
|
||||
### Gear Joint
|
||||
|
||||
If you want to create a sophisticated mechanical contraption you might want to
|
||||
use gears. In principle you can create gears in LiquidFun by using compound
|
||||
shapes to model gear teeth. This is not very efficient and might be tedious to
|
||||
author. You also have to be careful to line up the gears so the teeth mesh
|
||||
smoothly. LiquidFun has a simpler method of creating gears: the gear joint.
|
||||
|
||||
<img align="center" src="image_22.gif" alt="Gear joint" height="188"
|
||||
width="179"><br/>
|
||||
|
||||
The gear joint can only connect revolute and/or prismatic joints.
|
||||
|
||||
Like the pulley ratio, you can specify a gear ratio. However, in this case the
|
||||
gear ratio can be negative. Also keep in mind that when one joint is a
|
||||
revolute joint (angular) and the other joint is prismatic (translation), and
|
||||
then the gear ratio will have units of length or one over length.
|
||||
|
||||
coordinate1 + ratio * coordinate2 == constant
|
||||
|
||||
Here is an example gear joint. The bodies myBodyA and myBodyB are any bodies
|
||||
from the two joints, as long as they are not the same bodies.
|
||||
|
||||
`b2GearJointDef jointDef;`<br/>
|
||||
`jointDef.bodyA = myBodyA;`<br/>
|
||||
`jointDef.bodyB = myBodyB;`<br/>
|
||||
`jointDef.joint1 = myRevoluteJoint;`<br/>
|
||||
`jointDef.joint2 = myPrismaticJoint;`<br/>
|
||||
`jointDef.ratio = 2.0f * b2_pi / myLength;`<br/>
|
||||
|
||||
Note that the gear joint depends on two other joints. This creates a fragile
|
||||
situation. What happens if those joints are deleted?
|
||||
|
||||
Caution
|
||||
|
||||
Always delete gear joints before the revolute/prismatic joints on the gears. Otherwise your code will crash in a bad way due to the orphaned joint pointers in the gear joint. You should also delete the gear joint before you delete any of the bodies involved.
|
||||
|
||||
|
||||
### Mouse Joint
|
||||
|
||||
The mouse joint is used in the testbed to manipulate bodies with the mouse. It
|
||||
attempts to drive a point on a body towards the current position of the
|
||||
cursor. There is no restriction on rotation.
|
||||
|
||||
The mouse joint definition has a target point, maximum force, frequency, and
|
||||
damping ratio. The target point initially coincides with the body’s anchor
|
||||
point. The maximum force is used to prevent violent reactions when multiple
|
||||
dynamic bodies interact. You can make this as large as you like. The frequency
|
||||
and damping ratio are used to create a spring/damper effect similar to the
|
||||
distance joint.
|
||||
|
||||
Many users have tried to adapt the mouse joint for game play. Users often
|
||||
want to achieve precise positioning and instantaneous response. The mouse
|
||||
joint doesn’t work very well in that context. You may wish to consider using
|
||||
kinematic bodies instead.
|
||||
|
||||
### Wheel Joint
|
||||
|
||||
The wheel joint restricts a point on bodyB to a line on bodyA. The wheel joint
|
||||
also provides a suspension spring. See b2WheelJoint.h and Car.h for details.
|
||||
|
||||
<img align="center" src="image_23.png" alt="Wheel joint" height="286"
|
||||
width="157"><br/>
|
||||
|
||||
### Weld Joint
|
||||
|
||||
The weld joint attempts to constrain all relative motion between two bodies.
|
||||
See the Cantilever.h in the testbed to see how the weld joint behaves.
|
||||
|
||||
It is tempting to use the weld joint to define breakable structures. However,
|
||||
the LiquidFun solver is iterative so the joints are a bit soft. So chains of
|
||||
bodies connected by weld joints will flex.
|
||||
|
||||
Instead it is better to create breakable bodies starting with a single body
|
||||
with multiple fixtures. When the body breaks, you can destroy a fixture and
|
||||
recreate it on a new body. See the Breakable example in the testbed.
|
||||
|
||||
### Rope Joint
|
||||
|
||||
The rope joint restricts the maximum distance between two points. This can be
|
||||
useful to prevent chains of bodies from stretching, even under high load. See
|
||||
b2RopeJoint.h and RopeJoint.h for details.
|
||||
|
||||
### Friction Joint
|
||||
|
||||
The friction joint is used for top-down friction. The joint provides 2D
|
||||
translational friction and angular friction. See b2FrictionJoint.h and
|
||||
ApplyForce.h for details.
|
||||
|
||||
|
||||
*This content is licensed under
|
||||
[Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/legalcode).
|
||||
For details and restrictions, please see the
|
||||
[Content License](md__content_license.html).*
|
||||
Reference in New Issue
Block a user