I see two options here. A rather simple one and a bit more complex, but robust, one.
Option One
You use the RuntimeAnimatorController
. This will get you all the AnimationClips in the given Animator at runtime. You can play a State in an AnimatorController at any given time by using Animator.Play(StateNameOrHash)
. Unfortunately, for this option, this will only play a State by its Name or NameHash (as statet in the docs). Because we only have the AnimationClips
and not the States from the Controller this option would involve to rename the States in the controller to the exact name of the Animation Clip. Then you could play a State like this:
myAnimator.Play(myAnimationClip.name);
This is a fast option to get you started but not a good option in the long run because it has essentially two drawbacks:
- You could only use a flat hierarchy in your AnimatorController. No SubStateMachines/Blendtrees because they are not represented with an
AnimationClip
. Therefore you would not be able to retrief these States through the RuntimeAnimatorController
because it only returns the AnimationClips
- The AnimatorController could be hard to understand because the states are named like the
AnimationClips
. I dont know your situation here but it would be better to use descriptive names then the names from the AnimationClips for better understanding.
Option Two
This option is more complex. I will give you a quick overview of the Workflow and then explain the parts in more detail or give references to get you started!
- [Editor Script] Generate a script with all the States from your AnimatorController. (Probably the "hardest" part)
- Use the generated Script to fill your dropdown with the States
- Play your state :)
Part 1:
Use an Editor Script to extract all the States from your AnimatorController. This link should give you an hint on how to achieve this. Short (not tested) example code:
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);
}
Keep in mind: the used AnimatorController
is within the UnityEditor.Animations
namespace. This can be a public field in an EditorScript to easily give you access.
Part 2: Your scriptfile should create a class like this one:
public class AnimatorControllerStates
{
public List<string> states = new List<string>
{
"Idle",
"ComplexRotate 0",
"Autoplay",
...
}
}
Name the class somehow related to your AnimatorController you created it for. And make this class a field in your runtime script. Then you could get access to all your states like this:
myAnimatorControllerStates.states
This array can fill your dropdown. You would save the index of the dropdown and then can play the state by the index.
Part 3: Now it would be realy easy to just play your state in your script:
string state = myAnimatorControllerStates.states[mySelectedIndex];
myAnimatorController.Play(mySelectedIndex);
I dont know the scope of your project but to have a maintainable application I would prefer option two at any time.