Constraints¶
Limit where transforms can move and how they can rotate: on a shape (plane, line, circle, curve), inside or outside a volume (box, ball, cylinder, capsule), on a grid or on snap points, with optional soft-edge behaviours near the boundary.
Overview¶
Constraints clamp a transform's position and rotation against the shapes you list. Pick a shape, attach it to one of the entry points below, and the system clamps every frame the entry point is active. Near the edges, you choose what happens: a hard stop, a gradual slowdown, an elastic bounce, or smooth damping. Composite constraints layer multiple rules in sequence.
Namespace: Octoputs.Constraints. Assembly: Octoputs.
- Position constraints — limit where a transform can be.
- Rotation constraints — limit how a transform can be oriented.
- Limit behaviours — choose what happens approaching a boundary.
- Two entry points — a standalone
Constrainercomponent or drag-pipeline modifiers.
Entry points¶
The same constraint instances plug into three different surfaces. Pick the one that matches what's driving the transform.
Constrainer component¶
A MonoBehaviour you drop on a GameObject. Hosts a list of position and rotation constraints and applies them every LateUpdate while it is active. Active/inactive is decided by an IExecutionFrame (the standard Jungle lifecycle picker), so the constraining window can be tied to OnEnable/OnDisable, an attachment cycle, an event, or external Begin()/End() calls.
| Field | Default | Description |
|---|---|---|
target |
null (self) |
Transform to constrain. Leave empty to constrain this GameObject. |
space |
World |
Apply position/rotation in world or local space. |
positionConstraints |
empty | Applied in order each LateUpdate. Empty = position passthrough. |
rotationConstraints |
empty | Applied in order each LateUpdate. Empty = rotation passthrough. |
Use this whenever you want a transform constrained outside of a drag flow — patrol zones, UI bounds, persistent enclosures, gameplay boundaries triggered by lifecycle or events.
Drag pipeline modifiers¶
Inside an Octoputs drag transform pipeline, three modifiers expose the constraint system:
PositionConstraintModifier— clamps the dragged target's position.RotationConstraintModifier— clamps the dragged target's rotation.OrbitConstraintModifier— keeps the target on a sphere surface (or a circle) with optional face-the-center rotation.
These run only while a drag is active and only on the dragged object.
Limit behaviours¶
Every constraint that derives from PositionConstraintBase / RotationConstraintBase exposes the same three knobs that shape what happens near the boundary.
| Field | Effect |
|---|---|
LimitBehaviour.HardStop |
Snap to the boundary, no easing. |
LimitBehaviour.SlowDown |
Linear lerp from limitStrength to 1 inside the transition band. |
LimitBehaviour.Elastic |
Quadratic falloff inside the transition band. |
LimitBehaviour.Damped |
Cubic falloff inside the transition band. |
limitTransitionDistance / limitTransitionAngle |
How far from the boundary the soft behaviour begins. |
limitStrength |
Multiplier applied right at the boundary (0 = stalled, 1 = no effect). |
The computed factor is consumed by ApplyLimitToLerpSpeed, which the modifiers call to scale their interpolation speed as the value approaches a limit.
Core interfaces¶
public interface IPositionConstraint
{
Vector3 ConstrainPosition(Vector3 position);
float GetDistanceToLimit(Vector3 position);
}
public interface IRotationConstraint
{
Quaternion ConstrainRotation(Quaternion rotation);
float GetDistanceToLimit(Quaternion rotation);
}
PositionConstraintBase and RotationConstraintBase implement the limit-behaviour machinery; custom constraints should usually inherit from them rather than implement the bare interface.
Position constraints¶
| Type | What it does |
|---|---|
KeepOnShapeConstraint |
Keeps the position on a shape (plane, line, circle, arc, curve, mesh surface). maxDistance above 0 leaves a band around the shape instead: a tube around a curve, a slab above a floor. |
KeepInVolumeConstraint |
Keeps the position Inside, Outside or OnSurface of a volume (box, sphere, cylinder, capsule). A leash is a sphere that follows its anchor; an orbit is OnSurface of a sphere. |
SnapToGridConstraint |
Snaps to the centre of the nearest grid cell. The grid is laid out in a volume: cells splits it on each axis (0 leaves an axis free), and a box's grid repeats past its edges. |
SnapPointConstraint |
Snap to the nearest of a list of discrete points. |
NoPositionConstraint |
Holds the position at a reference value. |
CompositePositionConstraint |
Apply a sequence of IPositionConstraints in order. |
Shapes and volumes¶
Keep On Shape takes a SmartShape; Keep In Volume and Snap To Grid take a SmartSpatialVolume. Both offer the same three ways to give the geometry:
- Inline (the default): the shape or volume is stored in the constraint, in world space.
- From Component: it comes from a Shape or Volume component in the scene, so several constraints can share one, and its Local Space option makes it follow that object.
- In Transform Space: an inline shape or volume laid out relative to a pose. Point the frame at a transform and it moves, turns and scales with it.
Press the Inspect button on the shape or volume field to see it in the Scene view and drag its handles: centre, size, radius, line ends, plane axes. Turning debug on for the whole modifier draws the outline only.
Composites¶
CompositePositionConstraint:
Constraints:
[0] KeepOnShapeConstraint # on the floor plane
[1] KeepInVolumeConstraint # inside a 2 m box
The output of each constraint feeds the next. Order matters: place broad constraints (a volume) before fine ones (a grid). A distance band between two radii is two Keep In Volume entries: inside the outer sphere, then outside the inner one.
Rotation constraints¶
| Type | Shape |
|---|---|
RotationConstraint |
Per-axis Euler clamping relative to a reference rotation. |
AngleSnapRotationConstraint |
Snap to angle increments per axis. |
AxisLockRotationConstraint |
Lock selected Euler axes to a reference rotation. |
NoRotationConstraint |
Passthrough — returns the input rotation unchanged. Useful as a placeholder in composites or conditionals. |
CompositeRotationConstraint |
Apply a sequence of IRotationConstraints in order. |
Examples¶
Constrain a Transform to a plane (no drag)¶
Drop Constrainer on the GameObject:
Constrainer:
Target: <leave empty — uses this GameObject>
Space: World
Position Constraints:
[0] KeepOnShapeConstraint
Shape: Plane (origin (0, 0, 0), right (1, 0, 0), up (0, 0, 1))
Limit Behaviour: SlowDown
Limit Transition Distance: 0.5
Limit Strength: 0.5
Switch the execution frame to drive the constraining window from anything you like — an attachment cycle, an event, or external Begin()/End() calls.
Constrain a dragged object to a sphere¶
In the drag transform pipeline, add a PositionConstraintModifier with a KeepInVolumeConstraint:
PositionConstraintModifier:
Position Constraint:
Type: KeepInVolumeConstraint
Volume: Sphere (center (0, 1, 0), radius 2)
Region: Inside
Limit Behaviour: Damped
Limit Transition Distance: 0.3
Rotate within angular limits¶
RotationConstraintModifier:
Rotation Constraint:
Type: RotationConstraint
Reference Rotation: identity
Max Angle X: 45
Max Angle Y: 90
Max Angle Z: 0
Constrain X / Y / Z: true / true / false
Limit Behaviour: Damped
Limit Transition Angle: 15
Performance notes¶
- All
Constrainerinstances tick from the centralUpdateManagerLateUpdate pass — no per-component MonoBehaviour overhead. - Composites are O(n) in their inner-constraint count. Keep frequently-evaluated composites short.
Constrainerand the operation surfaces only run while their lifecycle is active; idle objects cost nothing.- Position and rotation passes are skipped entirely when the corresponding list is empty.