Character Controllers

The ControllerManager instance manages simulated motion control for its assigned RootPart. Along with ControllerPartSensors, it can be used to build a physics‑based character controller.

Core Setup

ControllerManager requires a BasePart to use as its root. Movement forces and part sensing will be on this part.

  1. Choose a Part or MeshPart and name it RootPart.

  2. Group the part as a Model instance for organization along with the other components.

  3. Add a ControllerManager instance to the model. If ControllerManager doesn't initially appear in the object insertion menu, uncheck "Show only recommended objects" in the menu's insertion settings.

    ControllerManager and RootPart inside a model.

Sensor Setup

A ControllerPartSensor detects parts with the same code the Humanoid uses for detecting floors and ladders.

  1. Insert a ControllerPartSensor as a child of RootPart and rename it GroundSensor for easier identification of its purpose. Then, in the Properties window, set its SearchDistance property to 2 but leave its SensorMode as Floor.

    GroundSensor as child of RootPart
  2. Insert another ControllerPartSensor as a child of RootPart and rename it ClimbSensor. Then, in the Properties window, set its SearchDistance property to 1 and its SensorMode to Ladder.

    ClimbSensor as child of RootPart

Controller Setup

Controller instances like GroundController and ClimbController tell the managed part how to interact with the world, working alongside the sensors you configured in Sensor Setup.

  1. Insert both a GroundController and ClimbController as children of the ControllerManager.

    GroundController and ClimbController as children of ControllerManager.
  2. Select the new GroundController instance and then, in the Properties window, set its GroundOffset property to a value at which the managed part should "levitate" above the ground. It's important that this value is less than the value of SearchDistance for the GroundSensor, since that sensor will deactivate if it loses sense of the ground and effectively stop its forces on the part.

Linking References

To complete the core setup, you'll need to link various properties of the ControllerManager instance to objects within the main Model.

  1. Select the ControllerManager instance.

    ControllerManager selected in Explorer window.
  2. In the Properties window, click each of the following properties and then, back in the Explorer window, click the respective instance to complete the link.

    1. Link the ActiveController property to the GroundController instance.
    2. Link the RootPart property to the part you named RootPart.
    3. Link the ClimbSensor property to the ClimbSensor instance.
    4. Link the GroundSensor property to the GroundSensor instance.
    ControllerManager properties linked to instances within overall model

Testing

With sensors and controllers in place, and with references linked, you can test the controller in Studio.

  1. Start a playtest using the Run mode (F8) since you don't need to insert your avatar character in this scenario.

    Rapid playtest options in Test tab of Studio
  2. RootPart should levitate above the ground at the GroundController.GroundOffset value you set in Adding Controllers. It should also rotate to align with the ControllerManager.FacingDirection vector.

    Character levitating above ground at GroundOffset, facing in direction of FacingDirection vector.
  3. Experiment with different movement and facing directions by changing the MovingDirection and FacingDirection vectors of the ControllerManager during runtime. Also experiment with different properties of the GroundController instance such as AccelerationTime, DecelerationTime, and GroundOffset.

    ControllerManager properties for moving and facing direction are highlighted.
    ControllerManager
    GroundController properties for acceleration, deceleration, and ground offset are highlighted.
    GroundController

Custom Sensors

The ControllerPartSensor.SensorMode options of Floor and Ladder run the exact Humanoid sensor code, letting you use them for backwards compatibility. However, you can also customize how and when walkable and climbable parts are detected, ultimately changing when the managed part walks/climbs.

  1. Switch the ControllerPartSensor.UpdateType from OnRead to Manual.

    • OnRead triggers the output properties to update corresponding to your SensorMode every time you read them. It essentially puts the sensor in a "read‑only" mode where anything you write to these properties becomes overwritten by its internal sensing behavior.
    • Manual turns off the internal sensing behavior. The output properties are free for you to write however you like and the SensorMode does nothing.
  2. Create a script that performs your own sensing logic and writes the outputs to your sensor output properties. Typically you'll use a spatial query such as WorldRoot:Raycast() or WorldRoot:Blockcast() which returns a RaycastResult. Your script can then take the result properties and set them on the sensor equivalents:

    Note that you'll need to manage how often your queries run and update their sensor instance.

  3. The ControllerManager will continue to use the sensors it has been assigned, taking the data you pass to it.