It’s possible to add any state transitions through scripts. Example:
var transition = stateMachine.AddAnyStateTransition(state);
transition.conditions = new[] {
new AnimatorCondition {
mode = AnimatorConditionMode.If,
parameter = someParam
}
};
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:
public class AnimatorControllerFix : EditorWindow {
private AnimatorController controller;
[MenuItem("Window/Custom/Animator Controller Fix", false)]
public static void ShowWindow() {
GetWindow<AnimatorControllerFix>();
}
public void OnGUI() {
controller = EditorGUILayout.ObjectField("Controller", controller, typeof (AnimatorController), false) as AnimatorController;
if (GUILayout.Button("Do the fix")) {
Undo.RecordObject(controller, "Transfering transitions");
foreach (var layer in controller.layers) {
var mainMachine = layer.stateMachine;
foreach (var submachineWrapper in mainMachine.stateMachines) {
var submachine = submachineWrapper.stateMachine;
var subTransitions = submachine.anyStateTransitions;
for (int i = 0; i < subTransitions.Length; i++) {
//Must copy, as the submachine.RemoveAnyStateTransition destroys the transition.
var copy = mainMachine.AddAnyStateTransition(subTransitions[i].destinationState);
copy.canTransitionToSelf = subTransitions[i].canTransitionToSelf;
copy.duration = subTransitions[i].duration;
copy.exitTime = subTransitions[i].exitTime;
copy.hasExitTime = subTransitions[i].hasExitTime;
copy.hasFixedDuration = subTransitions[i].hasFixedDuration;
copy.interruptionSource = subTransitions[i].interruptionSource;
copy.offset = subTransitions[i].offset;
copy.orderedInterruption = subTransitions[i].orderedInterruption;
copy.conditions = subTransitions[i].conditions;
copy.destinationState = subTransitions[i].destinationState;
copy.destinationStateMachine = subTransitions[i].destinationStateMachine;
copy.isExit = subTransitions[i].isExit;
copy.mute = subTransitions[i].mute;
copy.solo = subTransitions[i].solo;
}
for (int i = 0; i < subTransitions.Length; i++) {
var transition = subTransitions[i];
submachine.RemoveAnyStateTransition(transition);
}
}
}
}
}
}
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.