Restrict Rotation snaps the character’s desired facing to evenly spaced headings. Use it for four-way or eight-way movement, a 2.5D character that should face only along the play plane, or a camera-relative grid. It does not clamp rotation between a minimum and maximum angle.

Before you begin

  • Restriction must be greater than 0. The runtime divides by this value when choosing the nearest heading.
  • With the standard world-up direction, headings are based on world yaw rather than the character’s parent or starting rotation.
  • The supported starting case is an upright character turning around world up. The current rotation-delta multiplication order does not reliably apply the calculated heading to tilted/custom-gravity characters; correct that source calculation before relying on an up-aligned result.
  • Relative Look Source Rotation requires an attached look source. The character normally receives one when a Camera Controller or AI look source is connected.
  • The ability changes facing only. It does not constrain movement input or position; pair it with Restrict Position when the character also needs to stay on a lane or plane.

Add a heading restriction

  1. Select the character and open Ultimate Character Locomotion.
  2. Expand Abilities, select +, and add Restrict Rotation.
  3. Choose a positive Restriction. The source default is 45, which creates eight headings around a full turn.
  4. Set Offset to rotate the heading grid. The source default is 0.
  5. Enable Relative Look Source Rotation only when the grid should rotate with the camera or another look source. Its source default is disabled.
  6. When the grid is look-relative, use Look Source Offset for an additional correction. Its source default is 0.
  7. Enable Rotation Smoothing for a gradual turn toward the selected heading. It is disabled by default, producing an immediate snap.
  8. For a permanent restriction, keep Start Type set to Automatic, Stop Type set to Manual, and Enabled selected.
  9. Place Restrict Rotation below other regular abilities whose final rotation should be quantized. It is concurrent and does not block them, but active abilities call ApplyRotation in list order.

Restrict Rotation does not use an Ability Index or require an Animator state.

Configure useful heading grids

World-aligned movement

With the standard up direction and Offset 0, the allowed headings are world yaw values separated by Restriction:

Restriction Result
45 Eight headings: forward, backward, left, right, and the four diagonals
90 Four headings: 0, 90, 180, and 270 degrees
180 Two headings: 0 and 180 degrees
360 One heading at the configured offset

The target switches to whichever allowed heading is nearest. For a 90-degree grid, it changes heading after the desired rotation crosses the midpoint between two choices.

Offset grid

Offset shifts every allowed heading without changing their spacing. For example, Restriction 90 with Offset 45 allows 45, 135, 225, and 315 degrees. Use this for a level whose paths are diagonal relative to world forward.

Camera-relative grid

Enable Relative Look Source Rotation to add the current look-source yaw to Offset before the nearest heading is selected. A 90-degree grid then stays aligned with the camera as it rotates. Look Source Offset rotates the grid again; for example, 180 reverses its forward reference.

If the camera can orbit continuously, consider Rotation Smoothing so small look-source changes do not produce visibly abrupt character snaps.

2.5D facing

For a character that travels along a world-aligned side-scrolling plane, Restriction 180 produces two opposite headings. Choose Offset so those headings face along the playable axis. The supplied character enables Restrict Rotation from its 2.5D State rather than leaving it active for every movement type.

Temporary mode

Set Start Type to Manual when gameplay code should start and stop the restriction. Alternatively, leave automatic start configured, disable the ability in the default State, and use a State preset to enable it only for the relevant camera or movement mode.

Stopping an enabled automatic ability is temporary: it will try to start again on the next character update. Use manual start or toggle Enabled when the restriction must remain off.

How it runs

Restrict Rotation is concurrent, so locomotion and other abilities can remain active. During the rotation-application phase it reads Target Rotation, expresses that rotation in a frame aligned to the character’s current Up, and rounds the yaw to the nearest multiple of Restriction after subtracting the effective offset. It adds the offset again to calculate a target. The current delta is written as target * inverse(current), while locomotion applies current * DesiredRotation. These orders give the intended result for commuting rotations, such as upright yaw, but generally differ for a tilted character. The required local delta is inverse(current) * target; custom-gravity use needs that source correction.

The effective offset is Offset by itself, or Offset + look-source yaw + Look Source Offset when Relative Look Source Rotation is enabled. Pitch and roll are retained in the calculated target, but the multiplication-order issue can prevent that target from becoming the actual final orientation when the character is tilted.

For upright yaw, Rotation Smoothing disabled applies the selected heading immediately. When enabled, the ability uses a spherical interpolation from the current rotation with Motor Rotation Speed and the current time-step delta. Root motion and rotation-producing abilities establish the target first, after which Restrict Rotation quantizes it. A later ability that also changes rotation during ApplyRotation can replace that result, so test and adjust list order when combining custom rotation modifiers.

The ability listens for OnCharacterAttachLookSource and updates its cached reference when the camera or AI look source changes. It does not send an event when the selected heading changes.

Verify in Play Mode

  1. Display the Transform rotation, Ultimate Character Locomotion, Restrict Rotation, and active ability list.
  2. With Restriction 90, Offset 0, and smoothing disabled, rotate or steer through a full circle. Confirm the character selects only four world-aligned headings.
  3. Change Offset to 45 and confirm all four choices rotate by 45 degrees.
  4. Enable Rotation Smoothing and confirm the character turns gradually toward each selected heading. Change Motor Rotation Speed to verify it controls the response.
  5. Attach the Camera Controller, enable Relative Look Source Rotation, and orbit the camera. Confirm the heading grid rotates with the look-source yaw.
  6. Set Look Source Offset to 180 and confirm the camera-relative reference reverses.
  7. Activate root-motion, Rotate Towards, or another rotation-producing ability used by the game. Confirm Restrict Rotation remains active concurrently and the final facing follows the intended ordering.
  8. If the project needs tilted/custom-gravity characters, correct the source delta order first, then test several Up directions and heading changes. The uncorrected implementation does not guarantee that result.
  9. For a State-controlled setup, enter and leave the relevant mode and confirm Restrict Rotation activates and restores its default state correctly.

Troubleshooting

Symptom Check Fix
The character rotation becomes invalid or unstable Restriction is 0 or negative. Set a positive spacing such as 45, 90, or 180.
The character faces unexpected world directions The grid uses an up-aligned world reference, not the parent or initial rotation. Set Offset to the level’s desired forward heading, or use a custom reference-transform implementation.
The grid is consistently rotated by the wrong amount Offset and Look Source Offset are both part of the effective offset. Set the base world correction in Offset and reserve Look Source Offset for the look-relative correction.
Enabling look-relative rotation causes an error No look source is attached to the character. Attach the Camera Controller or intended AI look source before enabling Relative Look Source Rotation.
The character snaps too abruptly Rotation Smoothing is disabled. Enable smoothing and tune Motor Rotation Speed on Ultimate Character Locomotion.
The character turns too slowly or never seems to settle Smoothing is enabled and Motor Rotation Speed is too low, or the look-relative grid keeps moving. Increase the motor rotation speed or disable smoothing for a fixed snap.
Another ability ignores the heading grid A later regular ability changes Desired Rotation during ApplyRotation, or another system writes the transform afterward. Move Restrict Rotation lower in the regular ability list and identify any post-locomotion rotation writer.
Movement does not follow the snapped facing Restrict Rotation changes rotation but not Input Vector or Desired Movement. Configure the intended Movement Type, or pair the rotation with the matching position/input restriction.
A 2.5D character faces the wrong two directions Restriction or Offset does not match the playable world axis. Use 180 and adjust Offset until both allowed headings align with the plane.
The restriction restarts after being stopped Start Type remains Automatic and the ability is enabled. Use Manual start or toggle Enabled through a State preset.
Custom-gravity facing is inconsistent The ability writes the rotation delta in an order incompatible with locomotion for noncommuting rotations. Correct the source to use inverse(current) * target before relying on tilted-character quantization; changing the reference offset alone does not fix this.

Developer reference

The public runtime properties are Restriction, Offset, RelativeLookSourceRotation, LookSourceOffset, and RotationSmoothing. Restrict Rotation defaults to Automatic start, Manual stop, and IsConcurrent == true. Its source defaults are 45, 0, false, 0, and false, respectively.

The ability consumes OnCharacterAttachLookSource and reports activation through the standard OnCharacterAbilityActive event. It has no heading-change event or public helper that quantizes an arbitrary Quaternion.

The following component assumes Start Type has been changed to Manual in the Inspector:

using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Character.Abilities;
using UnityEngine;

public class HeadingRestriction : MonoBehaviour
{
    [SerializeField] private UltimateCharacterLocomotion m_CharacterLocomotion;

    public void EnableFourWayFacing(float offset)
    {
        var restriction = m_CharacterLocomotion.GetAbility<RestrictRotation>();
        restriction.Restriction = 90;
        restriction.Offset = offset;
        restriction.RelativeLookSourceRotation = false;
        restriction.RotationSmoothing = true;
        m_CharacterLocomotion.TryStartAbility(restriction);
    }

    public void DisableFacingRestriction()
    {
        var restriction = m_CharacterLocomotion.GetAbility<RestrictRotation>();
        m_CharacterLocomotion.TryStopAbility(restriction);
    }
}