Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on Thursday, June 8, for a Q&A with Unity's Content Pipeline group here on the forum, and on the Unity Discord, and discuss topics around Content Build, Import Workflows, Asset Database, and Addressables!
    Dismiss Notice

Question Animation Controller modifications via script not saving on reload.

Discussion in 'Animation' started by Cascadian215, Nov 30, 2022.

  1. Cascadian215

    Cascadian215

    Joined:
    Dec 8, 2018
    Posts:
    2
    Hello,

    I am working on an editor script to automatically setup an animation controller in a specific way for myself. I have it all working correctly except for when I reload the project, the states and the transitions are gone (The layers are still there though). Below are images of what happens before and after I reload the editor.

    Some help on troubleshooting this would be greatly appreciated. I'm sure it has something to so with my modifying a copy without setting it to the original or something, just can't seem to fond it.

    Thank you!

    Before:
    upload_2022-11-30_12-26-20.png

    After reload:
    upload_2022-11-30_12-26-59.png

    Code:
    Code (CSharp):
    1. private void ApplyToAnimator()
    2.     {
    3.         foreach (var toggle in Toggles)
    4.         {
    5.             // Check if the parameter or layer already exists. If not, add parameter
    6.             bool existParam = doesNameExistParam(toggle.toggleName + "Toggle", controller.parameters);
    7.             if (existParam == false)
    8.             {
    9.                 controller.AddParameter(toggle.toggleName + "Toggle", AnimatorControllerParameterType.Bool);
    10.             }
    11.  
    12.             //Check if a layer already Exists with that name. If so, remove and add new one.
    13.             bool existLayer = doesNameExistLayer(toggle.toggleName, controller.layers);
    14.             if (existLayer)
    15.             {
    16.                 controller.RemoveLayer(controller.layers.Length-1);
    17.             }
    18.            
    19.             controller.AddLayer(toggle.toggleName);
    20.  
    21.             //Creating On and Off states
    22.             AnimatorState stateOn = new AnimatorState
    23.             {
    24.                 name = "ON",
    25.                 motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/On{toggle.toggleName}.anim", typeof(Motion)),
    26.                 writeDefaultValues = false
    27.             };
    28.             AnimatorState stateOff = new AnimatorState
    29.             {
    30.                 name = "OFF",
    31.                 motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Off{toggle.toggleName}.anim", typeof(Motion)),
    32.                 writeDefaultValues = false
    33.             };
    34.             AnimatorState stateIdle = new AnimatorState
    35.             {
    36.                 name = "Idle",
    37.                 motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Idle{toggle.toggleName}.anim", typeof(Motion)),
    38.                 writeDefaultValues = true
    39.             };
    40.  
    41.             AnimatorController animatorController = controller;
    42.             var sm = animatorController.layers[controller.layers.Length - 1].stateMachine;
    43.  
    44.             // Adding created states to controller layer
    45.             controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateIdle, new Vector3(300, 0, 0));
    46.             controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateOff, new Vector3(100, -110, 0));
    47.             controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateOn, new Vector3(300, -220, 0));
    48.  
    49.             // If True, go to ON state.
    50.             sm.states[2].state.AddTransition(sm.states[1].state);
    51.             sm.states[2].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, toggle.toggleName + "Toggle");
    52.             sm.states[2].state.transitions[0].duration = 0.1f;
    53.  
    54.             // If False, go to Off state.
    55.             sm.states[0].state.AddTransition(sm.states[2].state);
    56.             sm.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, toggle.toggleName + "Toggle");
    57.             sm.states[0].state.transitions[0].duration = 0.1f;
    58.            
    59.             // Go to Idle after Off state immediately.
    60.             sm.states[1].state.AddTransition(sm.states[0].state);
    61.             sm.states[1].state.transitions[0].duration = 0.1f;
    62.             sm.states[1].state.transitions[0].hasExitTime = true;
    63.            
    64.             AssetDatabase.AddObjectToAsset(stateOn, AssetDatabase.GetAssetPath(controller));
    65.             AssetDatabase.AddObjectToAsset(stateOff, AssetDatabase.GetAssetPath(controller));
    66.             AssetDatabase.AddObjectToAsset(stateIdle, AssetDatabase.GetAssetPath(controller));
    67.            
    68.             //Set Layer Weight
    69.             AnimatorControllerLayer[] layers = controller.layers;
    70.             layers[controller.layers.Length - 1].defaultWeight = 1;
    71.             controller.layers = layers;
    72.         }
    73.         AssetDatabase.SaveAssets();
    74.     }
    Code (CSharp):
    1.     private void Postprocessing() // Ran at end
    2.     {
    3.         AssetDatabase.Refresh();
    4.         EditorUtility.SetDirty(controller);
    5.         AssetDatabase.SaveAssets();
    6.     }
    Update:
    I managed to keep the states on reload by adding this following code:
    Code (CSharp):
    1. AssetDatabase.AddObjectToAsset(stateOn, AssetDatabase.GetAssetPath(controller));
    2.             AssetDatabase.AddObjectToAsset(stateOff, AssetDatabase.GetAssetPath(controller));
    3.             AssetDatabase.AddObjectToAsset(stateIdle, AssetDatabase.GetAssetPath(controller));
     
  2. Cascadian215

    Cascadian215

    Joined:
    Dec 8, 2018
    Posts:
    2
    I've solved the issue. I'm not sure exactly what it was, but I started from scratch and slowly reimplemented following the instructions form this forum post here.

    The changed chunk of code now looks like this below. I hope this help someone else!

    Code (CSharp):
    1. private void ApplyToAnimator()
    2.     {
    3.         foreach (var toggle in Toggles)
    4.         {
    5.             // Check if the parameter or layer already exists. If not, add parameter
    6.             bool existParam = doesNameExistParam(toggle.toggleName + "Toggle", controller.parameters);
    7.             if (existParam == false)
    8.             {
    9.                 controller.AddParameter(toggle.toggleName + "Toggle", UnityEngine.AnimatorControllerParameterType.Bool);
    10.             }
    11.  
    12.             //Check if a layer already Exists with that name. If so, remove and add new one.
    13.             bool existLayer = doesNameExistLayer(toggle.toggleName, controller.layers);
    14.             if (existLayer)
    15.             {
    16.                 controller.RemoveLayer(controller.layers.Length-1);
    17.             }
    18.            
    19.             controller.AddLayer(toggle.toggleName);
    20.  
    21.             AnimatorController animatorController = controller as AnimatorController;
    22.             var sm = animatorController.layers[controller.layers.Length - 1].stateMachine;
    23.  
    24.             sm.AddState("stateIdle", new Vector3(300, 0, 0));
    25.             sm.AddState("stateOn", new Vector3(300, -220, 0));
    26.             sm.AddState("stateOff", new Vector3(100, -110, 0));
    27.  
    28.             sm.states[0].state.name = "IDLE" + toggle.toggleName;
    29.             sm.states[0].state.motion = null;
    30.             sm.states[0].state.writeDefaultValues = true;
    31.            
    32.             sm.states[1].state.name = "ON" + toggle.toggleName;
    33.             sm.states[1].state.motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/On{toggle.toggleName}.anim", typeof(Motion));
    34.             sm.states[1].state.writeDefaultValues = false;
    35.            
    36.             sm.states[2].state.name = "OFF" + toggle.toggleName;
    37.             sm.states[2].state.motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Off{toggle.toggleName}.anim", typeof(Motion));
    38.             sm.states[2].state.writeDefaultValues = false;
    39.  
    40.             sm.states[0].state.AddTransition(sm.states[1].state);
    41.             sm.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, toggle.toggleName + "Toggle");
    42.             sm.states[1].state.AddTransition(sm.states[2].state);
    43.             sm.states[1].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, toggle.toggleName + "Toggle");
    44.             sm.states[2].state.AddTransition(sm.states[0].state);
    45.             sm.states[2].state.transitions[0].hasExitTime = true;
    46.  
    47.             //Set Layer Weight
    48.             AnimatorControllerLayer[] layers = controller.layers;
    49.             layers[controller.layers.Length - 1].defaultWeight = 1;
    50.             controller.layers = layers;
    51.         }
    52.     }