Skip to content

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 Constrainer component 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 Constrainer instances tick from the central UpdateManager LateUpdate pass — no per-component MonoBehaviour overhead.
  • Composites are O(n) in their inner-constraint count. Keep frequently-evaluated composites short.
  • Constrainer and 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.