Skip to content

Constrainer

Continuously enforces position and rotation constraints on a target transform while active.

Namespace: Octoputs.Constraints Inherits: ControllableComponent → MonoBehaviour Implements: ILastLateUpdatable, ILastFixedUpdatable

Overview

Constrainer keeps a target Transform inside spatial limits — bounds, spheres, planes, lines, angle ranges. Each frame the target's position runs through every position constraint in order, then its rotation through every rotation constraint.

When the target has a Rigidbody, Constrainer corrects twice per physics step: in the last FixedUpdate channel, after every other system has applied forces but before the step, and again in the post-physics channel right after the step, so the drawn pose never leaves the constraint. On dynamic bodies it also projects linearVelocity and angularVelocity onto the constraint tangent, so collisions, joints, and forces can push the body along the constraint surface but never through it.

With Rigid Contacts on, collisions also see the body as immovable in the directions its constraints block: a heavy box dropped on a drawer rests on it instead of shoving it off its rail and falling through. A push along the rail at an angle moves the body a little less than it should.

Without a Rigidbody, Constrainer runs in the last LateUpdate channel so it has the final say after every other transform write.

Inherits its lifecycle from ControllableComponent: the constraining window can be tied to OnEnable/OnDisable, an attachment cycle, an external event, or manual Begin/End.

Properties

Property Type Description
target Transform Transform to constrain. Falls back to this GameObject when empty.
space Space Whether constraints operate on world or local position/rotation.
projectVelocityOnCorrection bool On dynamic Rigidbody targets, project velocity onto the constraint tangent on correction (preserve motion along the surface). Disable for legacy "zero velocity on correction" behaviour.
correctAfterPhysics bool On Rigidbody targets, corrects again right after each physics step. On by default.
rigidContacts bool On dynamic Rigidbody targets, collisions treat the body as immovable in the directions its constraints block. On by default.
positionConstraints List<IPositionConstraint> Position constraints applied in order. Empty = position not constrained.
rotationConstraints List<IRotationConstraint> Rotation constraints applied in order. Empty = rotation not constrained.

Constraint Lifecycle

On OnBegin (the lifecycle entry point), Constrainer calls Initialize() on each position constraint and then each rotation constraint before registering for the update loop. This is the hook custom constraints implementing IPositionConstraint / IRotationConstraint use to resolve their Smart* fields (CopiedOnInit mode in particular needs this — without it the field would never run its resolver). Both interfaces provide a default no-op Initialize(), so most constraints don't need to override it; override only if your constraint holds smart fields or other init-once state.

See Also