# Characters

Spark includes three built-in character controllers. This page covers their architecture and how to customize or replace them.

## Controller Architecture

All Spark controllers are MonoBehaviours that handle player input, movement, and camera control. They interact with Unity's character controller or rigidbody systems and integrate with Spark's entity and event systems.

Controllers are independent of the Spark plugin system. You can use any Unity controller alongside Spark entities.

## Third-Person Controller

**SparkThirdPersonController** provides a standard third-person setup.

Key features:

* WASD/stick movement relative to camera direction
* Camera follow with adjustable distance, angle, and smoothing
* Jump support
* Ground detection
* Animation parameter updates for movement blend trees

Customize by modifying the public fields in the inspector: movement speed, rotation speed, jump height, camera distance, camera sensitivity, etc.

## MMO Controller

**SparkMMOController** provides an MMO-style controller with:

* Click-to-move navigation
* Keyboard movement (WASD)
* Autorun toggle
* Camera orbit with right-click drag
* Target locking

**MMOCamera** handles the orbit camera behavior separately. It supports zoom (scroll wheel), orbit (right-click drag), and smooth following.

**AnimatorLayerWeightController** blends animator layers based on movement state. For example, the upper body layer might play an attack animation while the lower body runs.

## Creating a Custom Controller

If the built-in controllers don't fit your game, create your own:

```csharp
using UnityEngine;

[RequireComponent(typeof(SparkEntity))]
public class TopDownController : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 5f;
    [SerializeField] private float rotationSpeed = 720f;

    private SparkEntity _entity;
    private CharacterController _characterController;
    private Animator _animator;

    private void Awake()
    {
        _entity = GetComponent<SparkEntity>();
        _characterController = GetComponent<CharacterController>();
        _animator = GetComponent<Animator>();
    }

    private void Update()
    {
        // Skip if animation locked
        // (subscribe to AnimationLockStartedEvent/AnimationLockEndedEvent)

        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");
        Vector3 input = new Vector3(h, 0, v).normalized;

        if (input.magnitude > 0.1f)
        {
            // Move
            Vector3 move = input * moveSpeed * Time.deltaTime;
            _characterController.Move(move);

            // Rotate toward movement direction
            Quaternion targetRotation = Quaternion.LookRotation(input);
            transform.rotation = Quaternion.RotateTowards(
                transform.rotation,
                targetRotation,
                rotationSpeed * Time.deltaTime);
        }

        // Update animator
        if (_animator != null)
        {
            _animator.SetFloat("Speed", input.magnitude);
        }
    }
}
```

The controller is just a regular MonoBehaviour. It doesn't need to inherit from any Spark base class. As long as it's on the same GameObject as a `SparkEntity`, it integrates with the rest of the framework automatically.

## Animation Lock Integration

Combat abilities and playables can lock the character, preventing movement. To respect this in your controller:

```csharp
private bool _isLocked = false;

private void OnEnable()
{
    SparkEventBus.Subscribe<AnimationLockStartedEvent>(_lockHandler);
    SparkEventBus.Subscribe<AnimationLockEndedEvent>(_unlockHandler);
}

private void OnDisable()
{
    SparkEventBus.Unsubscribe<AnimationLockStartedEvent>(_lockHandler);
    SparkEventBus.Unsubscribe<AnimationLockEndedEvent>(_unlockHandler);
}

private void Update()
{
    if (_isLocked) return;
    // Normal movement logic
}
```

## Best Practices

* Keep controllers focused on movement and input. Don't put combat or UI logic in the controller.
* Use `SparkEntity` for identification, not the controller itself.
* Respect animation locks from the playable/combat systems.
* Use Unity's Input System for input handling (not the legacy Input class) to support rebinding.
* Make camera and movement parameters serialized fields so designers can tune them without code changes.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sparkframework.dev/documentation/developer-guide/core-systems/characters.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
