Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ryanhcode/sable/llms.txt
Use this file to discover all available pages before exploring further.
Sable’s constraint system lets you connect two sub-levels (or a sub-level to the world) with a joint. Constraints are created via PhysicsPipeline.addConstraint() using a typed configuration record and return a handle for later management or removal. Both bodies in a constraint can be independently null, which pins the non-null body to the static world.
PhysicsPipeline pipeline = physicsSystem.getPipeline();
FixedConstraintConfiguration config = new FixedConstraintConfiguration(pos1, pos2, orientation);
FixedConstraintHandle handle = pipeline.addConstraint(sublevelA, sublevelB, config);
PhysicsConstraintConfiguration
public interface PhysicsConstraintConfiguration<T extends PhysicsConstraintHandle> {}
A marker interface for constraint configurations. Each configuration record implements this interface and declares the handle type T it produces. Pass a configuration to PhysicsPipeline.addConstraint() to create the corresponding joint.
PhysicsConstraintHandle
public interface PhysicsConstraintHandle
The base interface returned by addConstraint(). All constraint handle types extend this interface.
getJointImpulses
void getJointImpulses(Vector3d linearImpulseDest, Vector3d angularImpulseDest)
Reads the latest global linear and angular impulses resolved by the constraint solver in the last physics step. Useful for monitoring joint load.
Destination for the linear impulse vector.
Destination for the angular impulse vector.
void setContactsEnabled(boolean enabled)
Enables or disables collision detection between the two constrained bodies. Disabling contacts lets two sub-levels overlap, which is often desirable for tightly coupled joints.
setMotor
void setMotor(
ConstraintJointAxis axis,
double target,
double stiffness,
double damping,
boolean hasMaxForce,
double maxForce
)
Adds or replaces a PD-controller motor on a specific degree of freedom. The motor drives the joint toward target along axis.
axis
ConstraintJointAxis
required
Target position along the axis. Units are [m] for linear axes and [rad] for angular axes.
Proportional gain (P) of the PD controller.
Derivative gain (D) of the PD controller.
If true, the motor force is clamped to maxForce.
Maximum force the motor can apply. Ignored when hasMaxForce is false.
remove
Removes this constraint from the active physics engine. The handle is invalid after this call — check isValid() before further use.
isValid
Returns true if the constraint is still registered with the physics engine and has not been removed.
FixedConstraint
A fixed joint locks all six degrees of freedom, rigidly connecting two bodies. Use this to weld sub-levels together.
FixedConstraintConfiguration
public record FixedConstraintConfiguration(
Vector3dc pos1,
Vector3dc pos2,
Quaterniondc orientation
) implements PhysicsConstraintConfiguration<FixedConstraintHandle>
A world-space position inside the first sub-level’s plot (e.g. a block center). Used to anchor the joint frame on body A.
A world-space position inside the second sub-level’s plot. Used to anchor the joint frame on body B.
The local orientation of body B’s joint frame relative to body A. Motor axes are expressed in this frame.
FixedConstraintHandle
public interface FixedConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with no additional methods. All interaction is through the base handle interface.
Example — weld two sub-levels:
FixedConstraintConfiguration config = new FixedConstraintConfiguration(
new Vector3d(10.5, 64.5, 10.5), // block center in sublevel A
new Vector3d(10.5, 66.5, 10.5), // block center in sublevel B
new Quaterniond() // identity — no relative rotation
);
FixedConstraintHandle weld = pipeline.addConstraint(sublevelA, sublevelB, config);
weld.setContactsEnabled(false); // let the bodies overlap
RotaryConstraint
A rotary joint allows a single angular degree of freedom (rotation around one axis), locking all other motion. Use this for axles, hinges, and motors.
RotaryConstraintConfiguration
public record RotaryConstraintConfiguration(
Vector3dc pos1,
Vector3dc pos2,
Vector3dc normal1,
Vector3dc normal2
) implements PhysicsConstraintConfiguration<RotaryConstraintHandle>
World-space anchor position on the first sub-level.
World-space anchor position on the second sub-level.
Local rotation axis on the first sub-level.
Local rotation axis on the second sub-level.
RotaryConstraintHandle
public interface RotaryConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with a convenience for servo control.
ConstraintJointAxis DEFAULT_AXIS = ConstraintJointAxis.ANGULAR_X;
The default motor axis for this constraint type.
setServoCoefficients(double angle, double stiffness, double damping) is deprecated and will be removed. Use setMotor(RotaryConstraintHandle.DEFAULT_AXIS, angle, stiffness, damping, false, 0.0) instead.
Example — spinning axle with a motor:
RotaryConstraintConfiguration config = new RotaryConstraintConfiguration(
new Vector3d(5.5, 64.5, 5.5),
new Vector3d(5.5, 64.5, 6.5),
new Vector3d(0, 0, 1), // Z axis on body A
new Vector3d(0, 0, 1) // Z axis on body B
);
RotaryConstraintHandle axle = pipeline.addConstraint(sublevelA, sublevelB, config);
// Spin at a target angle with a stiff spring
axle.setMotor(RotaryConstraintHandle.DEFAULT_AXIS, Math.PI, 200.0, 10.0, true, 500.0);
FreeConstraint
A free joint imposes no hard locks on any degree of freedom. It tracks the relationship between two bodies and lets you attach motors on individual axes without any hard constraints.
FreeConstraintConfiguration
public record FreeConstraintConfiguration(
Vector3dc pos1,
Vector3dc pos2,
Quaterniondc orientation
) implements PhysicsConstraintConfiguration<FreeConstraintHandle>
World-space anchor position on the first body.
World-space anchor position on the second body.
Local orientation of the second body’s joint frame relative to the first. Motor axes are expressed in this frame.
FreeConstraintHandle
public interface FreeConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with no additional methods. Useful for attaching motors to otherwise unconstrained body pairs.
GenericConstraint
Available since Sable 1.1.0.
A generic joint with per-axis hard locks and re-anchorable local frames. It is the most flexible constraint type and can emulate fixed, rotary, prismatic, or free joints by choosing which axes to lock.
GenericConstraintConfiguration
public record GenericConstraintConfiguration(
Vector3dc pos1,
Vector3dc pos2,
Quaterniondc orientation1,
Quaterniondc orientation2,
Set<ConstraintJointAxis> lockedAxes
) implements PhysicsConstraintConfiguration<GenericConstraintHandle>
A secondary constructor is also provided for convenience when no axes should be locked (equivalent to a free constraint):
public GenericConstraintConfiguration(
Vector3dc pos1,
Vector3dc pos2,
Quaterniondc orientation1,
Quaterniondc orientation2
)
World-space anchor position on the first body.
World-space anchor position on the second body.
Local orientation of the joint frame on the first body.
Local orientation of the joint frame on the second body.
The set of degrees of freedom hard-locked by the solver. An empty set is equivalent to a FreeConstraint. Use EnumSet.of(...) for efficient construction.
GenericConstraintHandle
public interface GenericConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with methods to re-anchor the joint frames at runtime.
setFrame1
void setFrame1(Vector3dc localPosition, Quaterniondc localRotation)
Updates the joint’s local anchor frame on the first body.
New local anchor position on body 1.
New local frame orientation on body 1.
setFrame2
void setFrame2(Vector3dc localPosition, Quaterniondc localRotation)
Updates the joint’s local anchor frame on the second body.
New local anchor position on body 2.
New local frame orientation on body 2.
Example — planar constraint (lock Y translation and all rotations):
Set<ConstraintJointAxis> locked = EnumSet.of(
ConstraintJointAxis.LINEAR_Y,
ConstraintJointAxis.ANGULAR_X,
ConstraintJointAxis.ANGULAR_Y,
ConstraintJointAxis.ANGULAR_Z
);
GenericConstraintConfiguration config = new GenericConstraintConfiguration(
pos1, pos2, new Quaterniond(), new Quaterniond(), locked
);
GenericConstraintHandle handle = pipeline.addConstraint(sublevelA, sublevelB, config);
ConstraintJointAxis
public enum ConstraintJointAxis {
LINEAR_X, LINEAR_Y, LINEAR_Z,
ANGULAR_X, ANGULAR_Y, ANGULAR_Z;
public static final ConstraintJointAxis[] ALL = values();
public static final ConstraintJointAxis[] LINEAR = { LINEAR_X, LINEAR_Y, LINEAR_Z };
public static final ConstraintJointAxis[] ANGULAR = { ANGULAR_X, ANGULAR_Y, ANGULAR_Z };
}
Represents one of the six degrees of freedom available for hard locks and motors.
| Value | Description |
|---|
LINEAR_X | Translation along the X axis |
LINEAR_Y | Translation along the Y axis |
LINEAR_Z | Translation along the Z axis |
ANGULAR_X | Rotation around the X axis (default axis for RotaryConstraint) |
ANGULAR_Y | Rotation around the Y axis |
ANGULAR_Z | Rotation around the Z axis |
The convenience arrays ALL, LINEAR, and ANGULAR let you lock entire groups at once:
// Lock all translational DOFs (prismatic-like)
for (ConstraintJointAxis axis : ConstraintJointAxis.LINEAR) {
handle.setMotor(axis, 0.0, 1000.0, 50.0, false, 0.0);
}