Получить все состояния аниматора и установить их вручную в коде

Я наткнулся на то, что никогда не представлял себе проблемы, но... это так. Я пишу инструментарий для визуализации / моделирования с использованием Unity 5.5.

Используемая модель уже импортирована, а анимационные клипы устанавливаются через редактор. Вот как выглядит мой контроллер состояния анимации:

Контроллер состояния анимации Я хочу отобразить AnimationStates в DropdownMenu. Всякий раз, когда пользователь выбирает запись, текущее состояние анимации должно быть установлено на выбранное.

eG Пользователь выбрал Autoplay: State установлен, чтобы обрезать Autoplay, после чего - SimpleRotate, затем ComplexRotate и снова Autoplay (простой цикл).

Но если пользователь выбирает Idle, ComplexRotate 0 или SimpleRotate 0, анимация должна проигрываться один раз, а затем оставаться в конце клипа. (Так же, как я сделал это в контроллере анимации.

Вот довольно псевдо-версия того, что я хочу:

//Retrieve all states to populate the dropdown:
List<AnimationState> states = myAnimationController.GetAllStates();

foreach(AnimationState state in states)
  Dropdown.add(state.name)


//callback
OnDropdownIndexChanged(int item)
{
  string stateName = ..... //removed for simplicity
  myAnimationController.setState(stateName)
}

Кроме того, было бы хорошо, если бы я мог проверить переходы ОТ и В состояния. (Автозапуск - это единственное состояние, которое должно отображаться в выпадающем списке для цикла)

Можно ли это реализовать с помощью пользовательского контроллера анимации? Или я что-то пропустил?

1 ответ

Решение

Я вижу два варианта здесь. Довольно простой и немного более сложный, но надежный.

Вариант первый

Вы используете RuntimeAnimatorController, Это даст вам все анимационные клипы в данном Animator во время выполнения. Вы можете воспроизводить состояние в AnimatorController в любое время, используя Animator.Play(StateNameOrHash), К сожалению, для этой опции, это будет воспроизводить состояние только по его имени или NameHash (как состояние в документах). Потому что у нас есть только AnimationClips а не "Состояния из контроллера", эта опция будет включать переименование состояний в контроллере на точное имя анимационного клипа. Тогда вы можете сыграть в таком состоянии:

myAnimator.Play(myAnimationClip.name);

Это быстрый вариант, чтобы начать работу, но в долгосрочной перспективе это не очень хороший вариант, поскольку он имеет два существенных недостатка:

  • Вы можете использовать только плоскую иерархию в вашем AnimatorController. Нет SubStateMachines/Blendtrees, потому что они не представлены с AnimationClip, Поэтому вы не сможете повторить эти состояния через RuntimeAnimatorController потому что он только возвращает AnimationClips
  • AnimatorController может быть трудно понять, потому что состояния называются как AnimationClips, Я не знаю вашу ситуацию здесь, но было бы лучше использовать описательные имена, чем имена из анимационных клипов для лучшего понимания.

Вариант второй

Этот вариант более сложный. Я дам вам краткий обзор рабочего процесса, а затем объясню детали более подробно или дам ссылки, чтобы вы начали!

  1. [Редактор скрипта] Сгенерируйте скрипт со всеми состояниями из вашего AnimatorController. (Вероятно, самая трудная часть)
  2. Используйте сгенерированный скрипт, чтобы заполнить ваш раскрывающийся список состояниями
  3. Играй в своем штате:)

Часть 1. Использование сценария редактора для извлечения всех состояний из вашего AnimatorController. Эта ссылка должна дать вам подсказку о том, как этого добиться. Краткий (не проверенный) пример кода:

private void writeAllStates()
{
    AnimatorControllerLayer[] allLayer = controller.layers;

    List<string> stateNames = new List<string>();

    for (int i = 0; i < allLayer.Length; i++)
    {
        ChildAnimatorState[] states = allLayer[i].stateMachine.states;

        for (int j = 0; j < states.Length; j++)
        {
            // you could do additional filtering here. like "would i like to add this state to my list because it has no exit transition" etc
            if (shouldBeInserted(states[i]))
            {
                // add state to list
                stateNames.Add(states[j].state.name);
            }
        }
    }

    // now generate a textfile to write all the states
    FileGenerator.createFileForController(controller, stateNames);
}

Имейте в виду: б AnimatorController находится в пределах UnityEditor.Animations Пространство имен. Это может быть открытое поле в Editor Script, чтобы вам было легко получить доступ.

Часть 2: Ваш скрипт-файл должен создать такой класс:

public class AnimatorControllerStates
{
    public List<string> states = new List<string>
    {
        "Idle",
        "ComplexRotate 0",
        "Autoplay",
        ...
    }
}

Назовите класс, каким-то образом связанный с вашим AnimatorController, для которого вы его создали. И сделайте этот класс полем в вашем скрипте времени выполнения. Тогда вы можете получить доступ ко всем вашим штатам, как это:

myAnimatorControllerStates.states

Этот массив может заполнить ваш выпадающий список. Вы должны сохранить индекс выпадающего списка, а затем можете воспроизвести состояние по индексу.

Часть 3: Теперь было бы просто воспроизвести ваше состояние в вашем скрипте:

string state = myAnimatorControllerStates.states[mySelectedIndex];
myAnimatorController.Play(mySelectedIndex);

Я не знаю масштаб вашего проекта, но чтобы иметь поддерживаемое приложение, я бы предпочел второй вариант в любое время.

Другие вопросы по тегам