Получить все состояния аниматора и установить их вручную в коде
Я наткнулся на то, что никогда не представлял себе проблемы, но... это так. Я пишу инструментарий для визуализации / моделирования с использованием 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
, Я не знаю вашу ситуацию здесь, но было бы лучше использовать описательные имена, чем имена из анимационных клипов для лучшего понимания.
Вариант второй
Этот вариант более сложный. Я дам вам краткий обзор рабочего процесса, а затем объясню детали более подробно или дам ссылки, чтобы вы начали!
- [Редактор скрипта] Сгенерируйте скрипт со всеми состояниями из вашего AnimatorController. (Вероятно, самая трудная часть)
- Используйте сгенерированный скрипт, чтобы заполнить ваш раскрывающийся список состояниями
- Играй в своем штате:)
Часть 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);
Я не знаю масштаб вашего проекта, но чтобы иметь поддерживаемое приложение, я бы предпочел второй вариант в любое время.