3

我偶然发现了一些我从未想过会成为问题的事情,但是……确实如此。我正在使用统一 5.5 编写可视化/模拟工具包。

使用的模型已经导入,动画剪辑已通过编辑器进行设置。这是我的动画状态控制器的样子:

动画状态控制器 我想在 DropdownMenu 中显示 AnimationStates。每当用户选择一个条目时,当前的动画状态都应该设置为选中的那个。

eG 用户选择自动播放:状态设置为剪辑自动播放,然后设置为 SimpleRotate,然后设置为 ComplexRotate,然后再次设置为自动播放(只是一个简单的循环)。

但如果用户选择 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)
}

最重要的是,如果我可以检查从和到状态的转换,那就太好了。(自动播放是循环下拉菜单中唯一应该显示的状态)

这可以通过自定义动画控制器来实现吗?还是我错过了什么?

4

1 回答 1

7

我在这里看到两个选项。一个相当简单的一个,一个更复杂但强大的一个。

选项一

您使用RuntimeAnimatorController. 这将在运行时为您提供给定 Animator 中的所有 AnimationClip。您可以在任何给定时间使用 AnimatorController 在 AnimatorController 中播放状态Animator.Play(StateNameOrHash)。不幸的是,对于这个选项,这只会通过其 Name 或 NameHash 播放 State(如docs中的 statet )。因为我们只有控制器中的AnimationClips状态而不是状态,所以这个选项将涉及将控制器中的状态重命名为动画剪辑的确切名称。然后你可以玩这样的状态:

myAnimator.Play(myAnimationClip.name);

这是一个快速入门的选择,但从长远来看不是一个好的选择,因为它基本上有两个缺点:

  • 您只能在 AnimatorController 中使用平面层次结构。没有 SubStateMachines/Blendtrees,因为它们没有用AnimationClip. 因此,您将无法通过 检索这些状态,RuntimeAnimatorController因为它只返回AnimationClips
  • AnimatorController 可能很难理解,因为状态的名称类似于AnimationClips. 我不知道您的情况,但最好使用描述性名称然后使用 AnimationClips 中的名称以便更好地理解。

选项二

这个选项更复杂。我将为您提供工作流程的快速概述,然后更详细地解释这些部分或提供参考以帮助您入门!

  1. [Editor Script] 从 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);
}

请记住: usedAnimatorControllerUnityEditor.Animations命名空间内。这可以是 EditorScript 中的公共字段,以便您轻松访问。

第 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);

我不知道您的项目的范围,但要拥有一个可维护的应用程序,我随时都希望选项二。

于 2017-01-18T20:13:58.113 回答