CharacterMotor

Physics-driven movement and rotation component for characters. Manages velocity, acceleration, grounding detection, collision response, and jump mechanics. Internally creates and drives a Unity CharacterController for physics-based movement.

Definition

Namespace: Paragon.Townskeep.CharacterSystem Assembly: Townskeep.dll

[Serializable]
public class CharacterMotor : CharacterComponent

Inheritance: CharacterComponent → CharacterMotor

Remarks

CharacterMotor is the lowest-level movement primitive in the Character system. It operates on a target pose model: callers set a desired position and rotation via MoveBy(), MoveTo(), RotateBy(), etc., and the motor interpolates towards that target each frame during Tick().

Unity CharacterController Integration

On OnInitialize(), the motor creates a UnityEngine.CharacterController component on the character's GameObject, configured with the motor's body parameters (Radius, Height, SkinWidth, Center, StepOffset). The Unity controller's Move() method is cached as a delegate for efficient per-frame calls.

The Unity CharacterController component is hidden in the Inspector (HideFlags.HideInInspector) since all configuration is driven by the motor's serialized fields.

Tick Loop

Each frame, Tick(float dt) runs the following pipeline:

  1. CheckIsGrounded — SphereCast downward to detect ground

  2. UpdateAcceleration — Apply gravity (5x) when airborne; zero when grounded

  3. UpdateVelocity — Compute horizontal velocity towards target, add vertical acceleration

  4. UpdatePosition — Move via CharacterController.Move() or snap for small distances

  5. UpdateRotation — Slerp towards target rotation

  6. CheckIsGrounded — Re-check after movement

  7. ApplyCollision — CapsuleCast to deflect velocity off obstacles when airborne

Speed Modes

The motor supports three speed tiers, switched via SetSprint() and SetWalk():

Mode
Speed Field
Activated By

Walk

WalkSpeed

SetWalk(true)

Normal

MoveSpeed

SetWalk(false) or SetSprint(false)

Sprint

SprintSpeed

SetSprint(true)

Minimum Step Distance

When the target is very close (< MinimumStepDistance) and the velocity for this frame is also below the threshold, the motor snaps directly to the target position instead of using CharacterController.Move(). This prevents micro-oscillation around the target.

Quick Lookup

Goal
How

Move by local-space delta

motor.MoveBy(new Vector3(1, 0, 0))

Move by world-space delta

motor.MoveBy(delta, worldSpace: true)

Move to world position

motor.MoveTo(position)

Rotate by angle (input-driven)

motor.RotateBy(angle)

Face a direction

motor.RotateTowards(direction)

Face a position

motor.RotateTo(position)

Jump

motor.Jump()

Sprint mode

motor.SetSprint(true)

Walk mode

motor.SetWalk(true)

Check if grounded

motor.IsGrounded

Read current velocity

motor.Velocity

Read current speed tier

motor.CurrentSpeed

Read facing direction

motor.Direction

Properties

Property
Type
Description

Acceleration

Vector3

Current acceleration vector (gravity when airborne, zero when grounded)

Velocity

Vector3

Current velocity vector

IsGrounded

bool

Whether the character is touching the ground

CurrentSpeed

float

Active speed tier (walk, normal, or sprint)

Direction

Vector3

Character's forward direction (transform.forward)

TargetPose

Pose

The target position and rotation the motor is interpolating towards

Fields

Movement

Field
Type
Description

WalkSpeed

float

Speed when walking

MoveSpeed

float

Default movement speed

SprintSpeed

float

Speed when sprinting

RotationSpeed

float

Rotation speed multiplier

JumpSpeed

float

Initial vertical velocity when jumping

Body

Field
Type
Description

Radius

float

Capsule collider radius

Height

float

Capsule collider height

Center

Vector3

Capsule collider center offset

SkinWidth

float

CharacterController skin width

StepOffset

float

Max step height the character can climb

MinimumStepDistance

float

Below this distance, snap to target instead of Move()

Methods

MoveBy

Sets the target position as a delta from the current position. The delta is clamped to magnitude 1.0.

Parameter
Type
Default
Description

delta

Vector3

Movement direction and magnitude (clamped to 1.0)

worldSpace

bool

false

If false, delta is transformed from local to world space

MoveTo

Sets the target position to a specific world-space coordinate. Internally calls MoveBy() with worldSpace: true.

Parameter
Type
Description

position

Vector3

World-space target position

RotateBy

Rotates the target rotation by an angle around the Y axis. Multiplied by RotationSpeed * Time.deltaTime.

Parameter
Type
Description

angle

float

Rotation angle (typically raw input axis value)

RotateTowards

Sets the target rotation to face a world-space direction. The Y component is zeroed out (horizontal rotation only).

Parameter
Type
Description

direction

Vector3

World-space direction to face (Y component ignored)

RotateTo

Sets the target rotation to face a world-space position. Computes the direction from the character to the target, then calls RotateTowards().

Parameter
Type
Description

target

Vector3

World-space position to face

Jump

Applies an upward velocity impulse if the character is grounded.

circle-info

Grounded checkJump() only applies velocity when IsGrounded is true. Calling it while airborne has no effect.

SetSprint

Sets the active speed to SprintSpeed (enabled) or MoveSpeed (disabled).

Parameter
Type
Description

enableSprint

bool

true for sprint speed, false for normal speed

SetWalk

Sets the active speed to WalkSpeed (enabled) or MoveSpeed (disabled).

Parameter
Type
Description

enableWalk

bool

true for walk speed, false for normal speed

OnDebug (override)

Draws debug visualization: current pose, target pose, line between them, and velocity ray. Only draws when the character is spawned.

Common Pitfalls

circle-exclamation
circle-exclamation
circle-exclamation
circle-exclamation
circle-exclamation

Examples

Direct Motor Control

Reading Motor State

Speed Mode Switching

See Also

Last updated