检索所有动画制作者状态并在代码

时间:2017-01-18 00:15:53

标签: c# unity3d unity5 unity3d-mecanim

我偶然发现了一些我从未想象过会成为问题的东西,但......就是这样。 我正在使用unity 5.5编写visualiazion / simulation工具包。

已导入已使用的模型,并通过编辑器设置动画片段。这就是我的动画状态控制器的样子:

Animation State Controller 我想在DropdownMenu中显示AnimationStates。每当用户选择条目时,应将当前动画状态设置为所选动画状态。

e.G。用户选择自动播放:状态设置为剪辑自动播放,之后是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)
}

最重要的是,如果我可以检查转换FROM和TO状态会很好。 (自动播放是唯一应该在循环的下拉列表中显示的状态)

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

1 个答案:

答案 0 :(得分:4)

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

选项一

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

myAnimator.Play(myAnimationClip.name);

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

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

选项二

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

  1. [编辑器脚本]使用AnimatorController中的所有状态生成脚本。 (可能是“最难”的部分)
  2. 使用生成的脚本填写状态
  3. 的下拉列表
  4. 玩你的州:)
  5. 第1部分: 使用编辑器脚本extract all the States from your 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命名空间内。这可以是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);
    

    我不知道你的项目的范围,但是为了拥有一个可维护的应用程序,我希望随时选择二。