Unity Animator 窗口的控制

问题描述


Animator 窗口默认显示的是 Base Layer 的动画状态机,每次要编辑子状态机里的状态动画时,都得手动双击进到子状态机里,非常不便。研究编辑器代码,来达到自动显示子状态机界面,如下面所示:

实现分析

Animator 窗口的实现类,位于目录 "Unity\Editor\Data\Managed\UnityEditor.Graphs.dll",反编译 DLL,AnimatorControllerTool 类就是具体实现。

这是顶部的状态机视图切换导航,它的列表保存在 AnimatorControllerTool.m_BreadCrumbs (面包屑)数组里面,点击的时候会调用 GoToBreadCrumbTarget 方法,将跳到所点击的状态机里,这个方法会将 m_BreadCrumbs  所点击的数组索引之后的值删除掉,然后调用 UpdateStateMachineSelection 方法。这个方法,会将  m_BreadCrumbs  数组的最后一个值作为显示的状态机。

所要用到的 API 接口:
  1. 当前显示的动画状态机,通过接口 UnityEditor.Graphs.AnimationStateMachine.Graph.activeStateMachine 来获得。
  2. 构建面包屑路径通过 AnimatorControllerTool.BuildBreadCrumbsFromSMHierarchy 方法来实现。

如果当前已经是要设置的动画状态机了,那就不做任何操作。如果不是的话,再来构建面包屑路径。

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
     public  static  void SetActiveStateMachine(AnimatorController animatorController, AnimatorStateMachine animatorStateMachine)
    {
        InitReflect();

        AnimatorStateMachine activeStateMachine = animatorControllerToolReflect.activeStateMachine;
if (animatorStateMachine != activeStateMachine && animatorStateMachine !=  null)
        {
            List<AnimatorStateMachine> hierarchy =  new List<AnimatorStateMachine>();
            AnimatorControllerUtil.MecanimUtilities_StateMachineRelativePath(
                AnimatorControllerUtil.AnimatorController_BaseLayerStateMachine(animatorController), 
                animatorStateMachine,  ref hierarchy);
            animatorControllerToolReflect.BuildBreadCrumbsFromSMHierarchy(hierarchy);
        }
    }
  1. animatorControllerToolReflect 是反射类,方便控制 AnimatorControllerTool 对象;
  2. MecanimUtilities_StateMachineRelativePath 方法,是获取两个状态机直接的路径,详见 UnityEditor.Animations.MecanimUtilities 类;
  3. AnimatorController_BaseLayerStateMachine 方法,是获取控制器的最底层状态机;

视图滚动到指定的状态

每当状态机里面状态过多的时候,寻找指定的状态,总是很麻烦,要一直拖动视图。现在通过获取状态的 position 来滚动到此位置。

通过打印坐标位置来得到上面的关系

信息分别如下:
  • 状态的坐标,即 ChildAnimatorState 的 position 值;
  • 当前视图的 scrollPosition 值;
  • 当前视图的 graphExtents 值;
那么要控制滚动位置的话,通过 graphExtents 减去状态的 position 值来实现,代码如下:
1
2
3
4
5
6
7
8
9
10
     public  static  void ScrollToState(AnimatorStateMachine animatorStateMachine, AnimatorState state)
    {
        InitReflect();

        Vector3 pos = AnimatorControllerUtil.AnimatorStateMachine_GetStatePosition(animatorStateMachine, state);
        Rect graphExtents = animatorControllerToolReflect.graphExtents;

        Vector2 pos2 =  new Vector2(pos.x - graphExtents.x, pos.y - graphExtents.y);
        animatorControllerToolReflect.scrollPosition = pos2;
    }
 效果如下:

但是一般都是将状态至于中间,才能方便看到与状态有关的过渡线。视图的大小保存在 GraphGUI 的 m_GraphClientArea 变量里。那么居中的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
     public  static  void ScrollToState(AnimatorStateMachine animatorStateMachine, AnimatorState state)
    {
        InitReflect();

        Vector3 pos = AnimatorControllerUtil.AnimatorStateMachine_GetStatePosition(animatorStateMachine, state);
        Rect graphExtents = animatorControllerToolReflect.graphExtents;
        Rect graphClientArea = animatorControllerToolReflect.graphClientArea;

        Vector2 pos2 =  new Vector2(pos.x - graphExtents.x - graphClientArea.width /  2 + 100f, 
            pos.y - graphExtents.y - graphClientArea.height /  2 + 25f);
        animatorControllerToolReflect.scrollPosition = pos2;
    }
效果如下:

完整代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值