Animator vs Animancer vs ручная state machine: что выбрать для Unity
На каждом проекте я через два месяца упирался в потолок Animator'а, на котором завязал персонажа. Потом смотрел на Animancer и думал «надо бы». На третьем проекте написал свою state machine и понял, что есть выбор не «одно из двух», а «инструмент под задачу». Расскажу, какой инструмент выбирать, что у каждого болит, и как живёт гибрид.
Опираюсь на Unity 6 (6000.x), Animancer 8.x.
Что у тебя есть из коробки: Mecanim Animator
Animator с Animator Controller — это та штука, в которую тебя приводит туториал. Графический state-machine: круги-состояния, стрелки-переходы, параметры (bool, int, float, trigger). Bленды через Blend Tree. Layers с Override и Additive.
Что хорошо:
- Визуальный редактор — дизайнер может сам править переходы.
- Blend Tree удобен для движения (idle/walk/run по скорости).
- Avatar Mask и Layers позволяют миксовать анимации (бег + прицеливание сверху).
- Root Motion из коробки.
Что болит:
- State explosion. На 30 анимациях граф уже невозможно читать.
- Любое изменение — клик-клик-клик в редакторе. В коде состояний нет, рефакторить — мучение.
- Триггеры — глобальное состояние с непонятным временем жизни. Поставил Attack, забыл сбросить, через два кадра он сработал второй раз. Классика.
- Sub-State Machines помогают, но всё равно не масштабируются.
- Нельзя нормально из коды задать «играй вот этот клип сейчас» — нужно создавать состояние и переход в редакторе.
- Производительность нелинейная. Чем больше параметров и переходов, тем медленнее CrossFade'ы.
Вывод: Animator подходит, когда у тебя меньше 15–20 состояний и стабильная анимация-логика. Платформер с 6 состояниями (idle/walk/run/jump/fall/attack) — на нём. Боевая система с 50 ударами и комбо — нет.
Animancer: код-фёрст альтернатива
Animancer (в Asset Store) — библиотека от Кибермэна, переписывает Animator под идею «играй конкретный клип, забудь про граф».
[SerializeField] private AnimancerComponent _animancer;
[SerializeField] private AnimationClip _idle;
[SerializeField] private AnimationClip _attack;
private void Update()
{
if (Input.GetButtonDown("Fire1"))
_animancer.Play(_attack);
else if (!_animancer.IsPlaying(_attack))
_animancer.Play(_idle);
}
Никаких триггеров и параметров. Хочешь воспроизвести клип — вызвал Play. Хочешь дождаться окончания — у тебя возвращается AnimancerState с событиями OnEnd.
private void Attack()
{
var state = _animancer.Play(_attack);
state.Events.OnEnd = () => _animancer.Play(_idle);
}
Что хорошо:
- Логика анимации в коде. Версионируется в git, читается в IDE, рефакторится Find & Replace.
- Можно создавать состояния и переходы динамически. Замена клипа на ходу — норма.
- Хорошо работает с ScriptableObject'ами для движений (ClipTransition, LinearMixerTransition).
- Нет state explosion.
- Хорошее API для вложенных автоматов и слоёв.
Что болит:
- Asset Store-зависимость. Лицензия pro-only, обновления — отдельная история.
- Дизайнер не может тыкать мышкой. Кто-то всегда пишет код.
- Нет встроенного визуального дебагера состояний (Inspector показывает текущее состояние, но граф — нет).
- Кривая обучения у новичков выше, чем у Animator'а.
- Root Motion работает, но настройка отличается, иногда через костыли.
Вывод: Animancer — оптимален для боевых систем, сложных боссов, кастомных AI с большим набором анимаций. Если у тебя в проекте 30+ состояний и команда программистов — стоит.
Своя ручная state machine
Третий путь — собственная state-machine плюс AnimationClipPlayable. Низкоуровневый Playables API в Unity позволяет проигрывать клипы без Animator Controller'а.
public class SimpleAnimator : MonoBehaviour
{
[SerializeField] private Animator _animator;
private PlayableGraph _graph;
private AnimationMixerPlayable _mixer;
private Dictionary<string, AnimationClipPlayable> _clips = new();
private void Awake()
{
_graph = PlayableGraph.Create("SimpleAnimator");
_graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
var output = AnimationPlayableOutput.Create(_graph, "Animation", _animator);
_mixer = AnimationMixerPlayable.Create(_graph, 4);
output.SetSourcePlayable(_mixer);
}
public void AddClip(string id, AnimationClip clip)
{
var playable = AnimationClipPlayable.Create(_graph, clip);
_clips[id] = playable;
_mixer.AddInput(playable, 0, 0f);
}
public void Play(string id, float fadeTime = 0.2f)
{
for (var i = 0; i < _mixer.GetInputCount(); i++)
_mixer.SetInputWeight(i, 0f);
// ... fade-in выбранного индекса
}
private void OnEnable() => _graph.Play();
private void OnDisable() => _graph.Stop();
private void OnDestroy() => _graph.Destroy();
}
Это упрощённый каркас. Реальная реализация — несколько сотен строк, с обработкой fade'ов, событий, лоопов, очередей.
Что хорошо:
- Полный контроль. Знаешь, что и как происходит на каждом кадре.
- Минимум зависимостей — только Unity API.
- Производительность — самая высокая из трёх вариантов, потому что нет лишних слоёв.
- Подходит для крайних случаев: процедурная анимация, генерируемые клипы, тысячи объектов.
Что болит:
- Писать с нуля — недели работы.
- Поддерживать — отдельная задача. Любая мелочь (event'ы анимации, root motion, layer'ы) — пишешь сам.
- Документации нет, потому что это твой код.
- Через год кто-то новый в команде смотрит на этот код и говорит «может, перепишем на Animator».
Вывод: своя машина — для очень специфичных случаев. Прокидной авто-боулинг с тысячей шаров — да. Обычный платформер — нет.
Что выбираю я в реальности
Зависит от проекта.
- Прототип, gamejam — Animator. Быстрый старт, не надо думать.
- Мобильный F2P с одним героем — Animator. Дизайнер сам соберёт граф, фичи добавлять не нужно часто.
- ПК-инди с боевой системой и 50+ анимациями — Animancer. Окупится в первый же месяц.
- Мобильная стратегия с тысячами юнитов — собственный решение поверх Playables (или GPU skinning через ECS, если совсем массово).
Часто гибрид: главные персонажи на Animancer'е, NPC-фон на Animator'е с простым графом, юниты массово — на собственном решении.
Технические штуки, которые работают везде
Animation Events vs события через код
Animation Events (callback'и в момент кадра анимации) — встроенная штука Unity. Удобна для попадания удара по тайму атаки, эффекта на шаге. Минус — теряются при ретаргетинге, требуют наличия скрипта на том же GameObject'е.
Альтернатива — события на аниматоре/Animancer'е по нормализованному времени. Программный, контролируемый.
Root Motion: на или off
Root Motion — когда анимация двигает корневой transform. Удобно для пере-сервированных анимаций (атаки с разворотом, прыжки с расстоянием). Болит, когда персонажа двигает контроллер по физике, а Root Motion накатывает сверху и они спорят.
Я обычно так: на персонаже Root Motion off, использую анимацию для визуала, движение через Rigidbody/CharacterController. Для специальных action'ов (контекстные взаимодействия, добивания) включаю Apply Root Motion на конкретный участок и снимаю обратно после события.
Animation Compression
Анимации FBX часто весят больше нужного. В Import Settings → Animation Type → Animation Compression поставь Optimal или Keyframe Reduction. Без видимой потери качества жмёт в 2–3 раза.
Avatar Mask
Когда нужно играть две анимации одновременно на разных частях тела (бег ногами + стрельба руками), Avatar Mask — твой друг. В Animator это второй слой с маской рук. В Animancer — отдельный AvatarMask на стейте.
Тесты и дебаг
Что я добавляю в каждый проект, независимо от выбора:
- Дебаг-overlay. На экране кружок с именем текущей анимации, нормализованным временем, fade-in/out фазой. Спасает от часов поиска «почему персонаж застревает».
- Хоткей «показать все клипы». В девелопменте — на F1 список всех клипов в проекте, можно тыкнуть и проиграть. Художники любят.
- Логирование переходов. В девбилде — лог в консоль каждого
Play/CrossFadeс источником.
Что не делать
- Не вкладывай 100 анимаций в один Animator Controller. Если граф не помещается на экран — пора рефакторить.
- Не используй
Animator.SetTriggerдля логики, чувствительной к таймингу. Триггеры — для одноразовых событий, не для синхронизации. - Не пиши свою state machine, если у проекта дедлайн через два месяца. Не успеешь.
- Не миксуй Animator и Animancer на одном персонаже одновременно. Мне попадались такие — это сложно и хрупко.
Чек-лист выбора
- Сколько анимаций у главного персонажа? <15 — Animator, 15–50 — Animancer, >50 или массово — своя.
- Кто будет править логику? Дизайнер — Animator. Программист — Animancer или своя.
- Нужен ли Root Motion из коробки? Animator проще всего.
- Нужны ли динамические клипы (не известные на этапе сборки)? Animancer или своя.
- Это пет-проект на пару месяцев или продакшн на год+? Соразмерно вкладывайся.
Если ещё не пробовал Animancer и проект не маленький — попробуй на отдельной ветке за выходные. Перенеси одного героя, сравни с Animator'ом. Часто решение принимается за пятнадцать минут после первой переписанной системы.