Search Unity

Animator any state transitions added by script potentially broken in 5.5 + fix

Discussion in 'Animation' started by Baste, Jan 5, 2017.

  1. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    It's possible to add any state transitions through scripts. Example:

    Code (csharp):
    1. var transition = stateMachine.AddAnyStateTransition(state);
    2. transition.conditions = new[] {
    3.     new AnimatorCondition {
    4.         mode = AnimatorConditionMode.If,
    5.         parameter = someParam
    6.     }
    7. };
    In 5.4, this worked just fine. In 5.5, this only works if stateMachine is the base machine in a layer. If it's a sub state machine, the transition will not show up, and not do anything. It will still be added to the asset, but be ignored by both the Animator window and the game. If you create the transition in 5.5, and then open the project in 5.4, it will show up and work again.

    The really bad thing here is that if you created such a transition in 5.4 or earlier, it will now be broken.

    The fix is pretty simple - transfer the transitions to the main state machine. Here's a fix, put it in an editor window:

    Code (csharp):
    1.  
    2. public class AnimatorControllerFix : EditorWindow {
    3.  
    4.     private AnimatorController controller;
    5.  
    6.     [MenuItem("Window/Custom/Animator Controller Fix", false)]
    7.     public static void ShowWindow() {
    8.         GetWindow<AnimatorControllerFix>();
    9.     }
    10.  
    11.     public void OnGUI() {
    12.         controller = EditorGUILayout.ObjectField("Controller", controller, typeof (AnimatorController), false) as AnimatorController;
    13.  
    14.         if (GUILayout.Button("Do the fix")) {
    15.             Undo.RecordObject(controller, "Transfering transitions");
    16.  
    17.             foreach (var layer in controller.layers) {
    18.                 var mainMachine = layer.stateMachine;
    19.                 foreach (var submachineWrapper in mainMachine.stateMachines) {
    20.  
    21.                     var submachine = submachineWrapper.stateMachine;
    22.                     var subTransitions = submachine.anyStateTransitions;
    23.  
    24.                     for (int i = 0; i < subTransitions.Length; i++) {
    25.                         //Must copy, as the submachine.RemoveAnyStateTransition destroys the transition.
    26.                         var copy = mainMachine.AddAnyStateTransition(subTransitions[i].destinationState);
    27.  
    28.                         copy.canTransitionToSelf = subTransitions[i].canTransitionToSelf;
    29.                         copy.duration = subTransitions[i].duration;
    30.                         copy.exitTime = subTransitions[i].exitTime;
    31.                         copy.hasExitTime = subTransitions[i].hasExitTime;
    32.                         copy.hasFixedDuration = subTransitions[i].hasFixedDuration;
    33.                         copy.interruptionSource = subTransitions[i].interruptionSource;
    34.                         copy.offset = subTransitions[i].offset;
    35.                         copy.orderedInterruption = subTransitions[i].orderedInterruption;
    36.                         copy.conditions = subTransitions[i].conditions;
    37.                         copy.destinationState = subTransitions[i].destinationState;
    38.                         copy.destinationStateMachine = subTransitions[i].destinationStateMachine;
    39.                         copy.isExit = subTransitions[i].isExit;
    40.                         copy.mute = subTransitions[i].mute;
    41.                         copy.solo = subTransitions[i].solo;
    42.                     }
    43.  
    44.                     for (int i = 0; i < subTransitions.Length; i++) {
    45.                         var transition = subTransitions[i];
    46.                         submachine.RemoveAnyStateTransition(transition);
    47.                     }
    48.                 }
    49.             }
    50.         }
    51.     }
    52. }
    53.  
    I've run this on our affected controllers, and it seems to work fine. I've got no guarantees though - always use source control!

    if @DavidGeoffroy or @Mecanim-Dev are interested, the bug report for this is 867568.
     
  2. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    283
    IIRC, those transitions looked like they were working in 5.4, but they were actually ignored. Only the ones on the top level SM were effective.

    We hid them in 5.5, since they were misleading. I could swear I had added a warning somewhere that informed you of that fact, probably at build time (where we can verify that your SM is indeed the top level one).

    We had a discussion about supporting any state transitions on other SMs (by transposing them to the base SM automatically) but this would limit the possibility of supporting any state transitions per state machine in the future.
     
  3. pepipe

    pepipe

    Joined:
    Jun 2, 2014
    Posts:
    4
    Thanks Baste to alert on this.
    I was following the documentation https://docs.unity3d.com/ScriptReference/Animations.AnimatorController.html and I was getting no transition using the AddAnyStateTransition method in Unity 5.5.0f3.
    When I switch to Unity 5.4.4 it worked so I start looking until I found this and like you said the solution is to change the AddAnyStateTransition to the main state machine instead of the child one.

    I alert that unity documentation is wrong, where it has:
    Code (CSharp):
    1. var resetTransition = stateMachineA.AddAnyStateTransition(stateA1);
    it should be:
    Code (CSharp):
    1. var resetTransition = rootStateMachine.AddAnyStateTransition(stateA1);
     
  4. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    283
    Indeed.
    I'll get this fixed ASAP
     
  5. numbercrunchee

    numbercrunchee

    Joined:
    Feb 12, 2018
    Posts:
    1
    @DavidGeoffroy Any news on this issue? Since it still doesn't seem to work in Unity 2018.4.
    Is there a case number in the issue tracker?