Expand description
Joints are a way to connect rigid bodies in a way that restricts their movement relative to each other. They act as constraints that restrict different Degrees of Freedom depending on the joint type.
§Degrees of Freedom (DOF)
In 2D, rigid bodies can normally translate along the x and y axes and rotate about the z axis. Therefore, they have 2 translational DOF and 1 rotational DOF, a total of 3 DOF.
Joints limit the degrees of freedom that bodies can have. For example, a RevoluteJoint
or hinge
prevents any relative movement between two bodies, except for rotation about a single axis
at an anchor point.
Below is a table containing all joints that are currently implemented.
Joint | Allowed 2D DOF | Allowed 3D DOF |
---|---|---|
FixedJoint | None | None |
DistanceJoint | 1 Translation, 1 Rotation | 2 Translations, 3 Rotations |
PrismaticJoint | 1 Translation | 1 Translation |
RevoluteJoint | 1 Rotation | 1 Rotation |
§Using Joints
In Avian, joints are modeled as components. Each joint is spawned as its own entity,
providing the Entity
identifiers of the bodies it should constrain.
use avian2d::prelude::*;
use bevy::prelude::*;
fn setup(mut commands: Commands) {
let body1 = commands.spawn(RigidBody::Dynamic).id();
let body2 = commands.spawn(RigidBody::Dynamic).id();
// Connect the bodies with a fixed joint.
commands.spawn(FixedJoint::new(body1, body2));
}
By default, the attached bodies can still collide with each other.
This behavior can be disabled with the JointCollisionDisabled
component.
§Joint Frames
By default, joints use body transforms as their reference for how to constrain the connected bodies.
For example, a RevoluteJoint
aims to make the positions of the two bodies coincide in world space,
while allowing the bodies to rotate freely around a common axis.
However, it can often be useful to define the attachment point or orientation separately from the body transform.
For example, you may want the RevoluteJoint
to be attached to the corner of a body instead of its center,
and that the other body is rotated by 90 degrees relative to the first body.
This can be done by configuring the JointFrame
associated with each body. Each joint frame is expressed
by a local JointAnchor
and JointBasis
relative to the transforms of the bodies. The anchor determines
the attachment point, while the basis determines the orientation of the joint frame relative to the body transform.
Storing the frames in local space allows the initial configuration to be preserved even when the bodies are moved.
The frames can also be specified in global coordinates using JointFrame::global
, but they are automatically converted
to local frames during the next simulation step.
Below is an example of configuring JointFrame
s for a RevoluteJoint
.
// Connect two bodies with a revolute joint.
// Set the global anchor point and rotate the first frame by 45 degrees about the local z axis.
commands.spawn((
RevoluteJoint::new(body1, body2)
.with_anchor(Vec2::new(5.0, 2.0))
.with_local_basis1(PI / 4.0),
));
§Damping
By default, no work is done to dampen the movement of bodies connected by a joint. A pendulum will swing indefinitely, unless explicitly stopped or it loses energy due to simulation inaccuracies.
It can often be desirable to dampen the relative velocities of bodies connected by a joint to slow them down over time.
This can be done using the JointDamping
component.
// Connect two bodies with a distance joint.
// Apply linear and angular damping to the joint.
commands.spawn((
DistanceJoint::new(body1, body2),
JointDamping {
linear: 0.1, // Linear damping
angular: 0.1, // Angular damping
},
));
§Reading Joint Forces
Joints apply forces and torques to constrain the bodies they are attached to.
These forces can be read by adding the JointForces
component to the joint entity:
// Connect two bodies with a revolute joint.
// Read the forces applied by the joint.
commands.spawn((
RevoluteJoint::new(body1, body2),
JointForces::new(),
));
and querying for it in a system:
fn read_joint_forces(query: Query<&JointForces>) {
for joint_forces in &query {
println!("Joint force: {}", joint_forces.force());
}
}
This can often be useful for determining when to “break” a joint with the JointDisabled
component
when its forces exceed a certain threshold. An example of this can be found in the next section on disabling joints.
§Disabling Joints
It can sometimes be useful to temporarily disable a joint without removing it from the world.
This can be done by adding the JointDisabled
component to the joint entity.
A common use case is to “break” a joint when its JointForces
exceed a certain threshold.
This could be done with a system like the following:
const BREAK_THRESHOLD: f32 = 500.0; // Example threshold
fn break_joints(
mut commands: Commands,
query: Query<(Entity, &JointForces), Without<JointDisabled>>,
) {
for (entity, joint_forces) in &query {
if joint_forces.force().length() > BREAK_THRESHOLD {
// Break the joint by adding the `JointDisabled` component.
// Alternatively, you could simply remove the joint component or despawn the entity.
commands.entity(entity).insert(JointDisabled);
}
}
}
Disabled joints can be re-enabled by removing the JointDisabled
component.
§Other Configuration
Different joints may have different configuration options. They may allow you to change the axis of allowed translation or rotation, and can have distance or angle limits for those axes.
Take a look at the documentation and methods of each joint to see all the different configuration options.
Structs§
- Angle
Limit - A limit that indicates that angles should be between
alpha
andbeta
. - Distance
Joint - A distance joint maintains an upper and/or lower bound on the distance between anchor points on two bodies.
- Distance
Limit - A limit that indicates that the distance between two points should be between
min
andmax
. - Fixed
Joint - A fixed joint prevents any relative movement between two bodies, effectively locking them together.
- Joint
Collision Disabled - A marker component that disables collision between rigid bodies connected by a joint. Must be on the same entity as the joint.
- Joint
Damping - A component for applying damping to the relative linear and angular velocities of bodies connected by a joint.
- Joint
Disabled - A marker component that indicates that a joint is disabled and should not constrain the bodies it is attached to. Must be on the same entity as the joint.
- Joint
Forces - A component for reading the force and torque exerted by a joint.
- Joint
Frame - The reference frame of a body that is being constrained by a joint.
- Joint
Plugin - A plugin for managing and initializing joints.
- Prismatic
Joint - A prismatic joint prevents any relative movement between two bodies,
except for translation along the
slider_axis
. - Revolute
Joint - A revolute joint or hinge prevents any relative movement between two bodies, except for rotation about a pivot point defined by the joint anchor.
Enums§
- Joint
Anchor - The translation of a
JointFrame
, defining the anchor point where the bodies are attached to each other. - Joint
Basis - The rotation of a
JointFrame
, defining the basis of the joint frame relative to the body transform. - Joint
Systems - System sets for joints.
Traits§
- Entity
Constraint - A trait for constraints between entities.