├── .gitignore ├── Test ├── Test1 │ ├── Message.cs │ ├── Test1Info.txt │ ├── Test1Controller.cs │ ├── TestBehaviour.cs │ ├── Test1.controller │ └── Test1.unity ├── Test2 │ ├── Test2Controller.cs │ ├── Test2.controller │ └── Test2.unity ├── SampleAnim.anim └── TestController.cs ├── Things to implement.txt ├── Messages.txt ├── Plugins └── AnimatorFix │ ├── StateMachineBehaviourFix.cs │ └── AnimatorFix.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.meta -------------------------------------------------------------------------------- /Test/Test1/Message.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Test/Test1/Test1Info.txt: -------------------------------------------------------------------------------- 1 | This tests checks that OnStateEnter, OnStateUpdate and OnStateExit are executed in order, as expected. 2 | 3 | The default StateMachineBehaviour behaviour is that if we transition from state A to state B, there's quite a few frames between 4 | OnStateEnter is called on state B before OnStateExit is called on State A. During that time, OnStateUpdate is called on both states. -------------------------------------------------------------------------------- /Test/Test1/Test1Controller.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System; 3 | 4 | public class Test1Controller : TestController { 5 | 6 | private readonly Message[] _expectedOrder = { 7 | new Message(MessageType.StateEnter, "State 1"), 8 | new Message(MessageType.StateUpdate, "State 1"), 9 | new Message(MessageType.StateExit, "State 1"), 10 | new Message(MessageType.StateEnter, "State 2"), 11 | new Message(MessageType.StateUpdate, "State 2"), 12 | new Message(MessageType.StateExit, "State 2"), 13 | new Message(MessageType.StateEnter, "State 3"), 14 | new Message(MessageType.StateUpdate, "State 3"), 15 | }; 16 | 17 | protected override IMessageMatcher[] expectedOrder { 18 | get { return _expectedOrder; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Test/Test1/TestBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class TestBehaviour : StateMachineBehaviourFix { 5 | 6 | public override void StateEnter(Animator animator) { 7 | TestController.ReportStateEnter(stateName); 8 | } 9 | 10 | public override void StateUpdate(Animator animator) { 11 | TestController.ReportStateUpdate(stateName); 12 | } 13 | 14 | public override void StateExit(Animator animator) { 15 | TestController.ReportStateExit(stateName); 16 | } 17 | 18 | public override void StateMachineEnter(Animator animator) { 19 | TestController.ReportStateMachineEnter(stateName); 20 | } 21 | 22 | public override void StateMachineUpdate(Animator animator) { 23 | TestController.ReportStateMachineUpdate(stateName); 24 | } 25 | 26 | public override void StateMachineExit(Animator animator) { 27 | TestController.ReportStateMachineExit(stateName); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Test/Test2/Test2Controller.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class Test2Controller : TestController { 5 | 6 | private IMessageMatcher[] _expectedOrder = { 7 | new Message(MessageType.StateEnter, "State 1"), 8 | new Message(MessageType.StateUpdate, "State 1"), 9 | new Message(MessageType.StateExit, "State 1"), 10 | 11 | new Message(MessageType.SubStateMachineEnter, "SubStateMachine"), 12 | 13 | new Message(MessageType.StateEnter, "State 2"), 14 | new OrderedMessages( 15 | new Message(MessageType.StateUpdate, "State 2"), 16 | new Message(MessageType.SubStateMachineUpdate, "SubStateMachine")), 17 | new Message(MessageType.StateExit, "State 2"), 18 | 19 | new Message(MessageType.SubStateMachineExit, "SubStateMachine"), 20 | 21 | new Message(MessageType.StateEnter, "State 3"), 22 | new Message(MessageType.StateUpdate, "State 3"), 23 | }; 24 | 25 | protected override IMessageMatcher[] expectedOrder { 26 | get { return _expectedOrder; } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Things to implement.txt: -------------------------------------------------------------------------------- 1 | 1: Proper OnState-messages. This means that the order when transitioning from state A to state B is guaranteed to be: 2 | 3 | - A.StateUpdate 4 | - A.StateExit 5 | - B.StateEnter 6 | - B.StateUpdate 7 | 8 | This also means that StateMachineEnter and StateMachineExit will be called whenever a state machine is entered/exited, not 9 | just when the flow goes through the entry/exit nodes. 10 | 11 | 2: Awake and OnEnable for the states. This will be the same as for the AnimatorFix script 12 | 13 | 3: A bigger and better API for getting information about the current state of the Animator. This will include: 14 | - CurrentStateName 15 | - CurrentStateMachine/s 16 | - IsInState/Machine that looks a lot better than the default ones 17 | - IsTransitioningTo/From + GetCurrentTransition 18 | 19 | All of these will default to layer 0. This means that this attrocity: 20 | if(animator.GetCurrentAnimatorStateInfo(0).IsName("Foo")) 21 | 22 | Is turned into: 23 | if(animator.IsInState("Foo")) 24 | 25 | Which just reads so_much_better 26 | 27 | 4: Performance: Once all the other stuff is done, this has to be measured and fixed. Both for GC and for general speed. -------------------------------------------------------------------------------- /Messages.txt: -------------------------------------------------------------------------------- 1 | The methods that are defined in StateMachineBehaviourFix are: 2 | 3 | StateMachineEnter 4 | StateMachineUpdate 5 | StateMachineExit 6 | StateEnter 7 | StateUpdate 8 | StateExit 9 | 10 | The default (Unity) methods that have not been changed are: 11 | OnStateMove 12 | OnStateIK 13 | 14 | On a frame (Update), if the state machine doesn't change state, and state A is the current state, this happens: 15 | 16 | StateUpdate is called on state A. 17 | StateMachineUpdate is called on any subStateMachine that contains A. 18 | - if A is contained in several machines, the methods will be called first on the innermost state machine, 19 | and then progressing outwards. So if the AnimatorController contains SubStateMachine1, which again 20 | contains SubStateMachine2, which contains state A, the order will be: 21 | StateUpdate called on A 22 | StateMachineUpdate called on SubStateMachine2 23 | StateMachineUpdate called on SubStateMachine1 24 | 25 | When the current state changes from state A to state B, this happens: 26 | - StateExit is called on A 27 | - StateMachineExit is called on any state machine exited - that is, state machines that contains A, but not B 28 | As in Update, this happens innermost state to outmost state 29 | - StateMachineEnter is called on any state machine entered - again, this is states that contain B, but not A. 30 | This happens in the reverse order as Update - so the outermost state machine is called Enter on first. 31 | - StateEnter is called on B 32 | - Then StateUpdate and StateMachineUpdate is called on State B and machines containing B as normal. 33 | 34 | 35 | The change is triggered when the Animator changes which state is returned by GetCurrentAnimatorStateInfo 36 | -------------------------------------------------------------------------------- /Plugins/AnimatorFix/StateMachineBehaviourFix.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Experimental.Director; 3 | 4 | /// 5 | /// Use this class instead of StateMachineBehaviour, and attach an AnimatorState to the same object as the Animator. 6 | /// 7 | /// That will give you access to a proper OnStateMachineExit 8 | /// 9 | public abstract class StateMachineBehaviourFix : StateMachineBehaviour { 10 | 11 | [HideInInspector] public string stateName; 12 | [HideInInspector] public int stateHash; 13 | [HideInInspector] public bool attachedToStateMachine; 14 | 15 | #region sealedOriginalMethods 16 | 17 | public sealed override void OnStateMachineExit(Animator animator, int stateMachinePathHash) {} 18 | public sealed override void OnStateMachineExit(Animator animator, int stateMachinePathHash, AnimatorControllerPlayable controller) {} 19 | public sealed override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {} 20 | public sealed override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) {} 21 | public sealed override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {} 22 | public sealed override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) {} 23 | public sealed override void OnStateMachineEnter(Animator animator, int stateMachinePathHash) {} 24 | public sealed override void OnStateMachineEnter(Animator animator, int stateMachinePathHash, AnimatorControllerPlayable controller) {} 25 | public sealed override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {} 26 | public sealed override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) {} 27 | 28 | #endregion 29 | 30 | #region customMethods 31 | 32 | public virtual void StateMachineExit(Animator animator) {} 33 | public virtual void StateMachineUpdate(Animator animator) {} 34 | public virtual void StateMachineEnter(Animator animator) {} 35 | public virtual void StateEnter(Animator animator) {} 36 | public virtual void StateUpdate(Animator animator) {} 37 | public virtual void StateExit(Animator animator) {} 38 | 39 | #endregion 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | A lean project that aims to fix a bunch of the many issues with Unity's Animator and StateMachineBehaviour systems. 3 | The Animator is a really powerfull system, but it has some major disadvantages. First of all, the API for getting information about the current state of the Animator is horribly obtuse and cumbersome to use. Secondly, the StateMachineBehaviour's messages - especially OnStateMachineEnter/Exit - doesn't fire when you expect them to. Both of these disadvantages are by design, so this project aims to create the tools needed to use the Animator comfortably. 4 | 5 | I want the code to work with your existing Animator-based projects, so this isn't a replacement or a framework. The start of this project is code I wrote for [World To The West](http://www.worldtothewest.com/), in order to work with Animators there. I have seen a lot of people on Unity Answers and the Unity forums that have the same gripes with this stuff as I do, so I figured that there would be interest both in using the code, and helping improve it. 6 | 7 | # Contents 8 | There's two main scripts: 9 | - StateMachineBehaviourFix is supposed to be a replacement for StateMachineBehaviour. It's got an OnStateMachineExit method that's called whenever a state machine is exited. The default Unity StateMachineBehaviour generally doesn't do that. 10 | - AnimatorFix is neccessary to make StateMachineBehaviourFix work. It's attached to the same object as the Animator, and works by parsing the Animator's AnimatorController to find out what methods should be called when. It's also got some convenience methods that the Animator should have had - like GetCurrentStateName(int layer) and IsInSubStateMachine(string name, int layer) 11 | 12 | # Setup: 13 | The repo is meant to be placed directly in your Assets folder. The code's all in Plugins/AnimatorFix. If you want to just use the code for production, you should just copy over the Plugins folder directly. 14 | 15 | # Current issues 16 | This is a very work in progress project. The code from the inital commit is exactly what I needed to work with Animators in World To The West. There's a couple of things that are problematic, and some things that I think this needs to be a worthy stand-alone project: 17 | 18 | Bugs: 19 | - The AnimatorFix script requires you to select the object it's attached to once after you update the corresponding AnimatorController. That's a big inconvenicene 20 | 21 | Problems: 22 | - AnimatorFix isn't a really good name. This project isn't about fixing bugs, but about a fundamental disagreement with Unity about the Animator/StateMachineBehaviour API. Name suggestions are welcome! 23 | 24 | To be considered: 25 | - Right now, the system only replaces OnStateMachineExit. This is the most broken method. The system could easily be expanded to handle all of the state machine messages. That would probably be advantageous; OnStateEnter and OnStateExit are not neccessarily called when you expect them to. 26 | -------------------------------------------------------------------------------- /Test/SampleAnim.anim: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!74 &7400000 4 | AnimationClip: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 0} 8 | m_Name: SampleAnim 9 | serializedVersion: 6 10 | m_Legacy: 0 11 | m_Compressed: 0 12 | m_UseHighQualityCurve: 1 13 | m_RotationCurves: [] 14 | m_CompressedRotationCurves: [] 15 | m_EulerCurves: [] 16 | m_PositionCurves: 17 | - curve: 18 | serializedVersion: 2 19 | m_Curve: 20 | - time: 0 21 | value: {x: 0, y: 0, z: 0} 22 | inSlope: {x: 0, y: 6, z: 0} 23 | outSlope: {x: 0, y: 6, z: 0} 24 | tangentMode: 0 25 | - time: 0.5 26 | value: {x: 0, y: 3, z: 0} 27 | inSlope: {x: 0, y: 6, z: 0} 28 | outSlope: {x: 0, y: -12, z: 0} 29 | tangentMode: 0 30 | - time: 1 31 | value: {x: 0, y: -3, z: 0} 32 | inSlope: {x: 0, y: -12, z: 0} 33 | outSlope: {x: 0, y: 6, z: 0} 34 | tangentMode: 0 35 | - time: 1.5 36 | value: {x: 0, y: 0, z: 0} 37 | inSlope: {x: 0, y: 6, z: 0} 38 | outSlope: {x: 0, y: 6, z: 0} 39 | tangentMode: 0 40 | m_PreInfinity: 2 41 | m_PostInfinity: 2 42 | m_RotationOrder: 4 43 | path: 44 | m_ScaleCurves: [] 45 | m_FloatCurves: [] 46 | m_PPtrCurves: [] 47 | m_SampleRate: 60 48 | m_WrapMode: 0 49 | m_Bounds: 50 | m_Center: {x: 0, y: 0, z: 0} 51 | m_Extent: {x: 0, y: 0, z: 0} 52 | m_ClipBindingConstant: 53 | genericBindings: 54 | - path: 0 55 | attribute: 1 56 | script: {fileID: 0} 57 | classID: 4 58 | customType: 0 59 | isPPtrCurve: 0 60 | pptrCurveMapping: [] 61 | m_AnimationClipSettings: 62 | serializedVersion: 2 63 | m_AdditiveReferencePoseClip: {fileID: 0} 64 | m_AdditiveReferencePoseTime: 0 65 | m_StartTime: 0 66 | m_StopTime: 1.5 67 | m_OrientationOffsetY: 0 68 | m_Level: 0 69 | m_CycleOffset: 0 70 | m_HasAdditiveReferencePose: 0 71 | m_LoopTime: 1 72 | m_LoopBlend: 0 73 | m_LoopBlendOrientation: 0 74 | m_LoopBlendPositionY: 0 75 | m_LoopBlendPositionXZ: 0 76 | m_KeepOriginalOrientation: 0 77 | m_KeepOriginalPositionY: 1 78 | m_KeepOriginalPositionXZ: 0 79 | m_HeightFromFeet: 0 80 | m_Mirror: 0 81 | m_EditorCurves: 82 | - curve: 83 | serializedVersion: 2 84 | m_Curve: 85 | - time: 0 86 | value: 0 87 | inSlope: 0 88 | outSlope: 0 89 | tangentMode: 10 90 | - time: 0.5 91 | value: 0 92 | inSlope: 0 93 | outSlope: 0 94 | tangentMode: 10 95 | - time: 1 96 | value: 0 97 | inSlope: 0 98 | outSlope: 0 99 | tangentMode: 10 100 | - time: 1.5 101 | value: 0 102 | inSlope: 0 103 | outSlope: 0 104 | tangentMode: 10 105 | m_PreInfinity: 2 106 | m_PostInfinity: 2 107 | m_RotationOrder: 4 108 | attribute: m_LocalPosition.x 109 | path: 110 | classID: 4 111 | script: {fileID: 0} 112 | - curve: 113 | serializedVersion: 2 114 | m_Curve: 115 | - time: 0 116 | value: 0 117 | inSlope: 6 118 | outSlope: 6 119 | tangentMode: 10 120 | - time: 0.5 121 | value: 3 122 | inSlope: 6 123 | outSlope: -12 124 | tangentMode: 21 125 | - time: 1 126 | value: -3 127 | inSlope: -12 128 | outSlope: 6 129 | tangentMode: 21 130 | - time: 1.5 131 | value: 0 132 | inSlope: 6 133 | outSlope: 6 134 | tangentMode: 10 135 | m_PreInfinity: 2 136 | m_PostInfinity: 2 137 | m_RotationOrder: 4 138 | attribute: m_LocalPosition.y 139 | path: 140 | classID: 4 141 | script: {fileID: 0} 142 | - curve: 143 | serializedVersion: 2 144 | m_Curve: 145 | - time: 0 146 | value: 0 147 | inSlope: 0 148 | outSlope: 0 149 | tangentMode: 10 150 | - time: 0.5 151 | value: 0 152 | inSlope: 0 153 | outSlope: 0 154 | tangentMode: 10 155 | - time: 1 156 | value: 0 157 | inSlope: 0 158 | outSlope: 0 159 | tangentMode: 10 160 | - time: 1.5 161 | value: 0 162 | inSlope: 0 163 | outSlope: 0 164 | tangentMode: 10 165 | m_PreInfinity: 2 166 | m_PostInfinity: 2 167 | m_RotationOrder: 4 168 | attribute: m_LocalPosition.z 169 | path: 170 | classID: 4 171 | script: {fileID: 0} 172 | m_EulerEditorCurves: [] 173 | m_HasGenericRootTransform: 1 174 | m_HasMotionFloatCurves: 0 175 | m_GenerateMotionCurves: 0 176 | m_Events: [] 177 | -------------------------------------------------------------------------------- /Test/Test1/Test1.controller: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!91 &9100000 4 | AnimatorController: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 0} 8 | m_Name: Test1 9 | serializedVersion: 5 10 | m_AnimatorParameters: [] 11 | m_AnimatorLayers: 12 | - serializedVersion: 5 13 | m_Name: Base Layer 14 | m_StateMachine: {fileID: 110721062} 15 | m_Mask: {fileID: 0} 16 | m_Motions: [] 17 | m_Behaviours: [] 18 | m_BlendingMode: 0 19 | m_SyncedLayerIndex: -1 20 | m_DefaultWeight: 0 21 | m_IKPass: 0 22 | m_SyncedLayerAffectsTiming: 0 23 | m_Controller: {fileID: 9100000} 24 | --- !u!114 &11434432 25 | MonoBehaviour: 26 | m_ObjectHideFlags: 1 27 | m_PrefabParentObject: {fileID: 0} 28 | m_PrefabInternal: {fileID: 0} 29 | m_GameObject: {fileID: 0} 30 | m_Enabled: 1 31 | m_EditorHideFlags: 0 32 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 33 | m_Name: 34 | m_EditorClassIdentifier: 35 | parentMachine: 36 | stateName: State 3 37 | stateHash: 1000687306 38 | --- !u!114 &11443904 39 | MonoBehaviour: 40 | m_ObjectHideFlags: 1 41 | m_PrefabParentObject: {fileID: 0} 42 | m_PrefabInternal: {fileID: 0} 43 | m_GameObject: {fileID: 0} 44 | m_Enabled: 1 45 | m_EditorHideFlags: 0 46 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 47 | m_Name: 48 | m_EditorClassIdentifier: 49 | parentMachine: 50 | stateName: State 1 51 | stateHash: -710203418 52 | --- !u!114 &11449336 53 | MonoBehaviour: 54 | m_ObjectHideFlags: 1 55 | m_PrefabParentObject: {fileID: 0} 56 | m_PrefabInternal: {fileID: 0} 57 | m_GameObject: {fileID: 0} 58 | m_Enabled: 1 59 | m_EditorHideFlags: 0 60 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 61 | m_Name: 62 | m_EditorClassIdentifier: 63 | parentMachine: 64 | stateName: State 2 65 | stateHash: 1285715548 66 | --- !u!1101 &110154082 67 | AnimatorStateTransition: 68 | m_ObjectHideFlags: 1 69 | m_PrefabParentObject: {fileID: 0} 70 | m_PrefabInternal: {fileID: 0} 71 | m_Name: 72 | m_Conditions: [] 73 | m_DstStateMachine: {fileID: 0} 74 | m_DstState: {fileID: 110202840} 75 | m_Solo: 0 76 | m_Mute: 0 77 | m_IsExit: 0 78 | serializedVersion: 3 79 | m_TransitionDuration: 0.25 80 | m_TransitionOffset: 0 81 | m_ExitTime: 0.8333333 82 | m_HasExitTime: 1 83 | m_HasFixedDuration: 1 84 | m_InterruptionSource: 0 85 | m_OrderedInterruption: 1 86 | m_CanTransitionToSelf: 1 87 | --- !u!1101 &110177320 88 | AnimatorStateTransition: 89 | m_ObjectHideFlags: 1 90 | m_PrefabParentObject: {fileID: 0} 91 | m_PrefabInternal: {fileID: 0} 92 | m_Name: 93 | m_Conditions: [] 94 | m_DstStateMachine: {fileID: 0} 95 | m_DstState: {fileID: 110203410} 96 | m_Solo: 0 97 | m_Mute: 0 98 | m_IsExit: 0 99 | serializedVersion: 3 100 | m_TransitionDuration: 0.25 101 | m_TransitionOffset: 0 102 | m_ExitTime: 0.8333333 103 | m_HasExitTime: 1 104 | m_HasFixedDuration: 1 105 | m_InterruptionSource: 0 106 | m_OrderedInterruption: 1 107 | m_CanTransitionToSelf: 1 108 | --- !u!1102 &110202840 109 | AnimatorState: 110 | serializedVersion: 5 111 | m_ObjectHideFlags: 1 112 | m_PrefabParentObject: {fileID: 0} 113 | m_PrefabInternal: {fileID: 0} 114 | m_Name: State 2 115 | m_Speed: 1 116 | m_CycleOffset: 0 117 | m_Transitions: 118 | - {fileID: 110177320} 119 | m_StateMachineBehaviours: 120 | - {fileID: 11449336} 121 | m_Position: {x: 50, y: 50, z: 0} 122 | m_IKOnFeet: 0 123 | m_WriteDefaultValues: 1 124 | m_Mirror: 0 125 | m_SpeedParameterActive: 0 126 | m_MirrorParameterActive: 0 127 | m_CycleOffsetParameterActive: 0 128 | m_Motion: {fileID: 7400000, guid: 0e96c4a802ce07644bc7b69ff0864dae, type: 2} 129 | m_Tag: 130 | m_SpeedParameter: 131 | m_MirrorParameter: 132 | m_CycleOffsetParameter: 133 | --- !u!1102 &110203410 134 | AnimatorState: 135 | serializedVersion: 5 136 | m_ObjectHideFlags: 1 137 | m_PrefabParentObject: {fileID: 0} 138 | m_PrefabInternal: {fileID: 0} 139 | m_Name: State 3 140 | m_Speed: 1 141 | m_CycleOffset: 0 142 | m_Transitions: [] 143 | m_StateMachineBehaviours: 144 | - {fileID: 11434432} 145 | m_Position: {x: 50, y: 50, z: 0} 146 | m_IKOnFeet: 0 147 | m_WriteDefaultValues: 1 148 | m_Mirror: 0 149 | m_SpeedParameterActive: 0 150 | m_MirrorParameterActive: 0 151 | m_CycleOffsetParameterActive: 0 152 | m_Motion: {fileID: 7400000, guid: 0e96c4a802ce07644bc7b69ff0864dae, type: 2} 153 | m_Tag: 154 | m_SpeedParameter: 155 | m_MirrorParameter: 156 | m_CycleOffsetParameter: 157 | --- !u!1102 &110287390 158 | AnimatorState: 159 | serializedVersion: 5 160 | m_ObjectHideFlags: 1 161 | m_PrefabParentObject: {fileID: 0} 162 | m_PrefabInternal: {fileID: 0} 163 | m_Name: State 1 164 | m_Speed: 1 165 | m_CycleOffset: 0 166 | m_Transitions: 167 | - {fileID: 110154082} 168 | m_StateMachineBehaviours: 169 | - {fileID: 11443904} 170 | m_Position: {x: 50, y: 50, z: 0} 171 | m_IKOnFeet: 0 172 | m_WriteDefaultValues: 1 173 | m_Mirror: 0 174 | m_SpeedParameterActive: 0 175 | m_MirrorParameterActive: 0 176 | m_CycleOffsetParameterActive: 0 177 | m_Motion: {fileID: 7400000, guid: 0e96c4a802ce07644bc7b69ff0864dae, type: 2} 178 | m_Tag: 179 | m_SpeedParameter: 180 | m_MirrorParameter: 181 | m_CycleOffsetParameter: 182 | --- !u!1107 &110721062 183 | AnimatorStateMachine: 184 | serializedVersion: 5 185 | m_ObjectHideFlags: 1 186 | m_PrefabParentObject: {fileID: 0} 187 | m_PrefabInternal: {fileID: 0} 188 | m_Name: Base Layer 189 | m_ChildStates: 190 | - serializedVersion: 1 191 | m_State: {fileID: 110287390} 192 | m_Position: {x: 264, y: 120, z: 0} 193 | - serializedVersion: 1 194 | m_State: {fileID: 110202840} 195 | m_Position: {x: 492, y: 120, z: 0} 196 | - serializedVersion: 1 197 | m_State: {fileID: 110203410} 198 | m_Position: {x: 720, y: 120, z: 0} 199 | m_ChildStateMachines: [] 200 | m_AnyStateTransitions: [] 201 | m_EntryTransitions: [] 202 | m_StateMachineTransitions: {} 203 | m_StateMachineBehaviours: [] 204 | m_AnyStatePosition: {x: 50, y: 20, z: 0} 205 | m_EntryPosition: {x: 50, y: 120, z: 0} 206 | m_ExitPosition: {x: 48, y: 168, z: 0} 207 | m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} 208 | m_DefaultState: {fileID: 110287390} 209 | -------------------------------------------------------------------------------- /Test/TestController.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | 4 | public abstract class TestController : MonoBehaviour { 5 | 6 | [SerializeField] private bool logToConsole; 7 | 8 | protected abstract IMessageMatcher[] expectedOrder { get; } 9 | 10 | private Text text; 11 | private static Message lastMessage; 12 | private static TestController instance; 13 | private static bool testEnded; 14 | 15 | private int currentIndex; 16 | 17 | void Awake() { 18 | instance = this; 19 | currentIndex = -1; 20 | 21 | Canvas c = new GameObject("Canvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster)).GetComponent(); 22 | c.renderMode = RenderMode.ScreenSpaceOverlay; 23 | 24 | GameObject textHolder = new GameObject("Text"); 25 | 26 | textHolder.transform.parent = c.transform; 27 | text = textHolder.AddComponent(); 28 | text.font = (Font)Resources.GetBuiltinResource(typeof(Font), "Arial.ttf"); 29 | var gray = 50f / 360f; 30 | text.color = new Color(gray, gray, gray, 1f); 31 | text.fontSize = 195; 32 | text.verticalOverflow = VerticalWrapMode.Overflow; 33 | 34 | var rectTransform = textHolder.GetComponent(); 35 | rectTransform.anchorMin = new Vector2(0, 0.5f); 36 | rectTransform.anchorMax = new Vector2(0, 0.5f); 37 | rectTransform.pivot = new Vector2(0, 0.5f); 38 | rectTransform.anchoredPosition = Vector2.zero; 39 | rectTransform.localScale = Vector3.one * .3f; 40 | 41 | rectTransform.sizeDelta = new Vector2(3000, 30); 42 | rectTransform.anchoredPosition = new Vector2(0, 150f); 43 | } 44 | 45 | public static void ReportStateEnter(string name) { 46 | instance.ReportState(new Message(MessageType.StateEnter, name)); 47 | } 48 | 49 | public static void ReportStateUpdate(string name) { 50 | instance.ReportState(new Message(MessageType.StateUpdate, name)); 51 | } 52 | 53 | public static void ReportStateExit(string name) { 54 | instance.ReportState(new Message(MessageType.StateExit, name)); 55 | } 56 | 57 | public static void ReportStateMachineEnter(string name) { 58 | instance.ReportState(new Message(MessageType.StateEnter, name)); 59 | } 60 | 61 | public static void ReportStateMachineUpdate(string name) { 62 | instance.ReportState(new Message(MessageType.SubStateMachineUpdate, name)); 63 | } 64 | 65 | public static void ReportStateMachineExit(string name) { 66 | instance.ReportState(new Message(MessageType.SubStateMachineExit, name)); 67 | } 68 | 69 | private void ReportState(Message m) { 70 | if(testEnded) 71 | return; 72 | 73 | if (expectedOrder[currentIndex + 1].Matches(m)) { 74 | currentIndex++; 75 | var stateChangeMsg = "Moved to: " + m; 76 | text.text = stateChangeMsg; 77 | if (logToConsole) { 78 | Debug.Log(stateChangeMsg); 79 | } 80 | if (currentIndex == expectedOrder.Length - 1) { 81 | var successMsg = "All messages received in expected order!"; 82 | if (logToConsole) { 83 | Debug.Log(successMsg); 84 | } 85 | text.text = successMsg; 86 | testEnded = true; 87 | return; 88 | } 89 | } 90 | else if (currentIndex != -1 && expectedOrder[currentIndex].Matches(m)) { 91 | return; 92 | } 93 | else { 94 | var failMsg = expectedOrder[currentIndex + 1].FailMessageFor(m); 95 | if (logToConsole) { 96 | Debug.Log(failMsg); 97 | } 98 | text.text = failMsg; 99 | testEnded = true; 100 | return; 101 | } 102 | } 103 | 104 | protected interface IMessageMatcher { 105 | bool Matches(Message message); 106 | 107 | string FailMessageFor(Message message); 108 | } 109 | 110 | protected class Message : IMessageMatcher { 111 | 112 | public override bool Equals(object obj) { 113 | if (ReferenceEquals(null, obj)) return false; 114 | if (ReferenceEquals(this, obj)) return true; 115 | if (obj.GetType() != GetType()) return false; 116 | return (Message) obj == this; 117 | } 118 | 119 | public override int GetHashCode() { 120 | unchecked { return ((int) type * 397) ^ (state != null ? state.GetHashCode() : 0); } 121 | } 122 | 123 | MessageType type; 124 | string state; 125 | 126 | public Message(MessageType type, string state) { 127 | this.type = type; 128 | this.state = state; 129 | } 130 | 131 | public override string ToString() { 132 | return type + ": " + state; 133 | } 134 | 135 | public bool Matches(Message message) { 136 | return this == message; 137 | } 138 | 139 | public string FailMessageFor(Message message) { 140 | return "Failed! Expected: " + this + ", but got: " + message; 141 | } 142 | 143 | public static bool operator ==(Message a, Message b) { 144 | if (ReferenceEquals(a, null)) 145 | return ReferenceEquals(b, null); 146 | if (ReferenceEquals(b, null)) 147 | return false; 148 | return a.type == b.type && a.state == b.state; 149 | } 150 | 151 | public static bool operator !=(Message a, Message b) { 152 | if (ReferenceEquals(a, null)) 153 | return !ReferenceEquals(b, null); 154 | if (ReferenceEquals(b, null)) 155 | return true; 156 | return !(a == b); 157 | } 158 | 159 | } 160 | 161 | protected class OrderedMessages : IMessageMatcher { 162 | private Message[] messages; 163 | private int currentIndex = 0; 164 | 165 | public OrderedMessages(params Message[] messages) { 166 | if (messages== null || messages.Length == 0) { 167 | throw new UnityException("OrderedMessages requires at least one message to work!"); 168 | } 169 | this.messages = messages; 170 | } 171 | 172 | public bool Matches(Message message) { 173 | bool matches = message == messages[currentIndex]; 174 | currentIndex = (currentIndex + 1) % messages.Length; 175 | return matches; 176 | } 177 | 178 | public string FailMessageFor(Message message) { 179 | return "Failed! Expected: " + messages[currentIndex] + ", but got: " + message; 180 | } 181 | } 182 | 183 | protected enum MessageType { 184 | 185 | StateEnter, 186 | StateUpdate, 187 | StateExit, 188 | SubStateMachineEnter, 189 | SubStateMachineUpdate, 190 | SubStateMachineExit 191 | 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /Test/Test2/Test2.controller: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!91 &9100000 4 | AnimatorController: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 0} 8 | m_Name: Test2 9 | serializedVersion: 5 10 | m_AnimatorParameters: [] 11 | m_AnimatorLayers: 12 | - serializedVersion: 5 13 | m_Name: Base Layer 14 | m_StateMachine: {fileID: 110784444} 15 | m_Mask: {fileID: 0} 16 | m_Motions: [] 17 | m_Behaviours: [] 18 | m_BlendingMode: 0 19 | m_SyncedLayerIndex: -1 20 | m_DefaultWeight: 0 21 | m_IKPass: 0 22 | m_SyncedLayerAffectsTiming: 0 23 | m_Controller: {fileID: 9100000} 24 | --- !u!114 &11460676 25 | MonoBehaviour: 26 | m_ObjectHideFlags: 1 27 | m_PrefabParentObject: {fileID: 0} 28 | m_PrefabInternal: {fileID: 0} 29 | m_GameObject: {fileID: 0} 30 | m_Enabled: 1 31 | m_EditorHideFlags: 0 32 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 33 | m_Name: 34 | m_EditorClassIdentifier: 35 | stateName: SubStateMachine 36 | stateHash: 0 37 | attachedToStateMachine: 1 38 | --- !u!114 &11461480 39 | MonoBehaviour: 40 | m_ObjectHideFlags: 1 41 | m_PrefabParentObject: {fileID: 0} 42 | m_PrefabInternal: {fileID: 0} 43 | m_GameObject: {fileID: 0} 44 | m_Enabled: 1 45 | m_EditorHideFlags: 0 46 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 47 | m_Name: 48 | m_EditorClassIdentifier: 49 | stateName: State 3 50 | stateHash: 1000687306 51 | attachedToStateMachine: 0 52 | --- !u!114 &11474362 53 | MonoBehaviour: 54 | m_ObjectHideFlags: 1 55 | m_PrefabParentObject: {fileID: 0} 56 | m_PrefabInternal: {fileID: 0} 57 | m_GameObject: {fileID: 0} 58 | m_Enabled: 1 59 | m_EditorHideFlags: 0 60 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 61 | m_Name: 62 | m_EditorClassIdentifier: 63 | stateName: State 1 64 | stateHash: -710203418 65 | attachedToStateMachine: 0 66 | --- !u!114 &11493880 67 | MonoBehaviour: 68 | m_ObjectHideFlags: 1 69 | m_PrefabParentObject: {fileID: 0} 70 | m_PrefabInternal: {fileID: 0} 71 | m_GameObject: {fileID: 0} 72 | m_Enabled: 1 73 | m_EditorHideFlags: 0 74 | m_Script: {fileID: 11500000, guid: 8a38c01ae6569c340a5e3148eea848bd, type: 3} 75 | m_Name: 76 | m_EditorClassIdentifier: 77 | stateName: State 2 78 | stateHash: 1285715548 79 | attachedToStateMachine: 0 80 | --- !u!1101 &110121776 81 | AnimatorStateTransition: 82 | m_ObjectHideFlags: 1 83 | m_PrefabParentObject: {fileID: 0} 84 | m_PrefabInternal: {fileID: 0} 85 | m_Name: 86 | m_Conditions: [] 87 | m_DstStateMachine: {fileID: 0} 88 | m_DstState: {fileID: 110233372} 89 | m_Solo: 0 90 | m_Mute: 0 91 | m_IsExit: 0 92 | serializedVersion: 3 93 | m_TransitionDuration: 0.25 94 | m_TransitionOffset: 0 95 | m_ExitTime: 0.8333333 96 | m_HasExitTime: 1 97 | m_HasFixedDuration: 1 98 | m_InterruptionSource: 0 99 | m_OrderedInterruption: 1 100 | m_CanTransitionToSelf: 1 101 | --- !u!1101 &110142972 102 | AnimatorStateTransition: 103 | m_ObjectHideFlags: 1 104 | m_PrefabParentObject: {fileID: 0} 105 | m_PrefabInternal: {fileID: 0} 106 | m_Name: 107 | m_Conditions: [] 108 | m_DstStateMachine: {fileID: 0} 109 | m_DstState: {fileID: 110227856} 110 | m_Solo: 0 111 | m_Mute: 0 112 | m_IsExit: 0 113 | serializedVersion: 3 114 | m_TransitionDuration: 0.25 115 | m_TransitionOffset: 0 116 | m_ExitTime: 0.8333333 117 | m_HasExitTime: 1 118 | m_HasFixedDuration: 1 119 | m_InterruptionSource: 0 120 | m_OrderedInterruption: 1 121 | m_CanTransitionToSelf: 1 122 | --- !u!1102 &110227856 123 | AnimatorState: 124 | serializedVersion: 5 125 | m_ObjectHideFlags: 1 126 | m_PrefabParentObject: {fileID: 0} 127 | m_PrefabInternal: {fileID: 0} 128 | m_Name: State 3 129 | m_Speed: 1 130 | m_CycleOffset: 0 131 | m_Transitions: [] 132 | m_StateMachineBehaviours: 133 | - {fileID: 11461480} 134 | m_Position: {x: 50, y: 50, z: 0} 135 | m_IKOnFeet: 0 136 | m_WriteDefaultValues: 1 137 | m_Mirror: 0 138 | m_SpeedParameterActive: 0 139 | m_MirrorParameterActive: 0 140 | m_CycleOffsetParameterActive: 0 141 | m_Motion: {fileID: 7400000, guid: 0e96c4a802ce07644bc7b69ff0864dae, type: 2} 142 | m_Tag: 143 | m_SpeedParameter: 144 | m_MirrorParameter: 145 | m_CycleOffsetParameter: 146 | --- !u!1102 &110233372 147 | AnimatorState: 148 | serializedVersion: 5 149 | m_ObjectHideFlags: 1 150 | m_PrefabParentObject: {fileID: 0} 151 | m_PrefabInternal: {fileID: 0} 152 | m_Name: State 2 153 | m_Speed: 1 154 | m_CycleOffset: 0 155 | m_Transitions: 156 | - {fileID: 110142972} 157 | m_StateMachineBehaviours: 158 | - {fileID: 11493880} 159 | m_Position: {x: 50, y: 50, z: 0} 160 | m_IKOnFeet: 0 161 | m_WriteDefaultValues: 1 162 | m_Mirror: 0 163 | m_SpeedParameterActive: 0 164 | m_MirrorParameterActive: 0 165 | m_CycleOffsetParameterActive: 0 166 | m_Motion: {fileID: 7400000, guid: 0e96c4a802ce07644bc7b69ff0864dae, type: 2} 167 | m_Tag: 168 | m_SpeedParameter: 169 | m_MirrorParameter: 170 | m_CycleOffsetParameter: 171 | --- !u!1102 &110277474 172 | AnimatorState: 173 | serializedVersion: 5 174 | m_ObjectHideFlags: 1 175 | m_PrefabParentObject: {fileID: 0} 176 | m_PrefabInternal: {fileID: 0} 177 | m_Name: State 1 178 | m_Speed: 1 179 | m_CycleOffset: 0 180 | m_Transitions: 181 | - {fileID: 110121776} 182 | m_StateMachineBehaviours: 183 | - {fileID: 11474362} 184 | m_Position: {x: 50, y: 50, z: 0} 185 | m_IKOnFeet: 0 186 | m_WriteDefaultValues: 1 187 | m_Mirror: 0 188 | m_SpeedParameterActive: 0 189 | m_MirrorParameterActive: 0 190 | m_CycleOffsetParameterActive: 0 191 | m_Motion: {fileID: 7400000, guid: 0e96c4a802ce07644bc7b69ff0864dae, type: 2} 192 | m_Tag: 193 | m_SpeedParameter: 194 | m_MirrorParameter: 195 | m_CycleOffsetParameter: 196 | --- !u!1107 &110771782 197 | AnimatorStateMachine: 198 | serializedVersion: 5 199 | m_ObjectHideFlags: 1 200 | m_PrefabParentObject: {fileID: 0} 201 | m_PrefabInternal: {fileID: 0} 202 | m_Name: SubStateMachine 203 | m_ChildStates: 204 | - serializedVersion: 1 205 | m_State: {fileID: 110233372} 206 | m_Position: {x: 396, y: 108, z: 0} 207 | m_ChildStateMachines: [] 208 | m_AnyStateTransitions: [] 209 | m_EntryTransitions: [] 210 | m_StateMachineTransitions: {} 211 | m_StateMachineBehaviours: 212 | - {fileID: 11460676} 213 | m_AnyStatePosition: {x: 50, y: 20, z: 0} 214 | m_EntryPosition: {x: 50, y: 120, z: 0} 215 | m_ExitPosition: {x: 48, y: 72, z: 0} 216 | m_ParentStateMachinePosition: {x: 396, y: 24, z: 0} 217 | m_DefaultState: {fileID: 110233372} 218 | --- !u!1107 &110784444 219 | AnimatorStateMachine: 220 | serializedVersion: 5 221 | m_ObjectHideFlags: 1 222 | m_PrefabParentObject: {fileID: 0} 223 | m_PrefabInternal: {fileID: 0} 224 | m_Name: Base Layer 225 | m_ChildStates: 226 | - serializedVersion: 1 227 | m_State: {fileID: 110277474} 228 | m_Position: {x: 288, y: 120, z: 0} 229 | - serializedVersion: 1 230 | m_State: {fileID: 110227856} 231 | m_Position: {x: 804, y: 120, z: 0} 232 | m_ChildStateMachines: 233 | - serializedVersion: 1 234 | m_StateMachine: {fileID: 110771782} 235 | m_Position: {x: 552, y: 120, z: 0} 236 | m_AnyStateTransitions: [] 237 | m_EntryTransitions: [] 238 | m_StateMachineTransitions: 239 | data: 240 | first: {fileID: 110771782} 241 | second: [] 242 | m_StateMachineBehaviours: [] 243 | m_AnyStatePosition: {x: 50, y: 20, z: 0} 244 | m_EntryPosition: {x: 50, y: 120, z: 0} 245 | m_ExitPosition: {x: 48, y: -48, z: 0} 246 | m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} 247 | m_DefaultState: {fileID: 110277474} 248 | -------------------------------------------------------------------------------- /Plugins/AnimatorFix/AnimatorFix.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | #if UNITY_EDITOR 6 | using UnityEditor; 7 | using UnityEditor.Animations; 8 | 9 | #endif 10 | 11 | /// 12 | /// This combines with StateMachineBehaviourFix to allow OnStateMachineExit to function properly. 13 | /// 14 | public class AnimatorFix : MonoBehaviour, ISerializationCallbackReceiver { 15 | 16 | private Dictionary[] stateInfos; 17 | //@TODO: This currently only supports one state on each state/machine! 18 | private Dictionary stateBehaviours; 19 | private Dictionary machineBehaviours; 20 | 21 | private Animator animator; 22 | private int lastNameHash = -1; 23 | private StateInfo lastStateInfo; 24 | 25 | public void OnBeforeSerialize() { 26 | #if UNITY_EDITOR 27 | if (!EditorApplication.isPlayingOrWillChangePlaymode) { 28 | var anim = GetComponent(); 29 | 30 | var serializedObject = new SerializedObject(anim); 31 | var animatorControllerProperty = serializedObject.FindProperty("m_Controller"); 32 | var animatorControllerObject = animatorControllerProperty.objectReferenceValue; 33 | 34 | if (animatorControllerObject == null) { 35 | // This happens in one of the many possible OnBeforeSerialize steps that happen 36 | // if you recompile with the controller open. Other OnBeforeSerialize steps saves 37 | // the correct data. We don't do null-checks on the serializedProperty - if that's null, 38 | // Unity changed the name of the AnimatorController field and this script must be rewritten. 39 | 40 | // Of course, the object reference value is null if the controller isn't assigned. That's cool too. 41 | return; 42 | } 43 | AnimatorController controller = (AnimatorController) animatorControllerObject; 44 | 45 | stateInfos = new Dictionary[controller.layers.Length]; 46 | 47 | for (int i = 0; i < controller.layers.Length; i++) { 48 | stateInfos[i] = new Dictionary(); 49 | } 50 | 51 | for (int i = 0; i < controller.layers.Length; i++) { 52 | var layer = controller.layers[i]; 53 | FindStateInfoRecursively(layer.stateMachine, stateInfos[i], new List()); 54 | } 55 | 56 | SerializeHashToStateInfoDict(); 57 | } 58 | #endif 59 | } 60 | 61 | #if UNITY_EDITOR 62 | private void FindStateInfoRecursively(AnimatorStateMachine stateMachine, Dictionary dict, List stateMachineStack) { 63 | stateMachineStack.Add(stateMachine); 64 | 65 | foreach (var state in stateMachine.states) { 66 | AnimatorState actualState = state.state; 67 | int hash = actualState.nameHash; 68 | 69 | if (!dict.ContainsKey(hash)) { 70 | dict[hash] = new StateInfo(actualState.name); 71 | } 72 | 73 | foreach (var behaviour in actualState.behaviours) { 74 | var behaviourFix = behaviour as StateMachineBehaviourFix; 75 | if (behaviourFix != null) { 76 | behaviourFix.attachedToStateMachine = false; 77 | behaviourFix.stateName = actualState.name; 78 | behaviourFix.stateHash = actualState.nameHash; 79 | } 80 | } 81 | 82 | foreach (var machine in stateMachineStack) { 83 | dict[hash].containingStateMachines.Add(machine.name); 84 | } 85 | } 86 | 87 | foreach (var machine in stateMachine.stateMachines) { 88 | var actualMachine = machine.stateMachine; 89 | var behaviours = actualMachine.behaviours; 90 | foreach (var behaviour in behaviours) { 91 | var behaviourFix = behaviour as StateMachineBehaviourFix; 92 | if (behaviourFix != null) { 93 | behaviourFix.attachedToStateMachine = true; 94 | var machineName = actualMachine.name; 95 | behaviourFix.stateName = machineName; 96 | } 97 | } 98 | 99 | FindStateInfoRecursively(actualMachine, dict, stateMachineStack); 100 | } 101 | stateMachineStack.Remove(stateMachine); 102 | } 103 | #endif 104 | 105 | public void OnAfterDeserialize() { 106 | DeserializeHashToStateInfoDict(); 107 | } 108 | 109 | private void Awake() { 110 | animator = GetComponent(); 111 | } 112 | 113 | private void Update() { 114 | if (stateInfos == null) { 115 | Debug.LogWarning("missing information about the Animator on " + name + ", please update the prefab/object"); 116 | return; 117 | } 118 | 119 | if (stateBehaviours == null) { 120 | InitBehaviours(); 121 | } 122 | 123 | var currentNameHash = animator.GetCurrentAnimatorStateInfo(0).shortNameHash; 124 | 125 | bool firstUpdate = lastNameHash == -1; 126 | if (firstUpdate) { 127 | lastNameHash = currentNameHash; 128 | lastStateInfo = stateInfos[0][lastNameHash]; 129 | } 130 | 131 | bool changedState = currentNameHash != lastNameHash; 132 | if (firstUpdate || changedState) { 133 | HandleStateChanged(currentNameHash, firstUpdate); 134 | } 135 | else { 136 | if (!stateBehaviours.ContainsKey(currentNameHash)) { 137 | Debug.LogError("Does not have information about a state! failing to run the animatorFix!"); 138 | return; 139 | } 140 | 141 | stateBehaviours[currentNameHash].StateUpdate(animator); 142 | } 143 | 144 | } 145 | 146 | private void InitBehaviours() { 147 | stateBehaviours = new Dictionary(); 148 | machineBehaviours = new Dictionary(); 149 | var allBehaviours = animator.GetBehaviours(); 150 | 151 | for (int i = 0; i < allBehaviours.Length; i++) { 152 | if (allBehaviours[i].attachedToStateMachine) { 153 | machineBehaviours[allBehaviours[i].stateHash] = allBehaviours[i]; 154 | } 155 | else { 156 | stateBehaviours[allBehaviours[i].stateHash] = allBehaviours[i]; 157 | } 158 | } 159 | } 160 | 161 | private void HandleStateChanged(int currentNameHash, bool firstUpdate) { 162 | if (!stateInfos[0].ContainsKey(currentNameHash)) { 163 | Debug.LogWarning("missing information about the Animator on " + name + ", please update the prefab/object"); 164 | return; 165 | } 166 | 167 | if (!firstUpdate) { 168 | stateBehaviours[lastNameHash].StateExit(animator); 169 | } 170 | stateBehaviours[currentNameHash].StateEnter(animator); 171 | 172 | 173 | 174 | StateInfo currentStateInfo = stateInfos[0][currentNameHash]; 175 | 176 | 177 | 178 | lastNameHash = currentNameHash; 179 | lastStateInfo = currentStateInfo; 180 | } 181 | 182 | public bool IsInSubStateMachine(string name, int layerIndex) { 183 | return GetCurrentStateInfo(layerIndex).containingStateMachines.Contains(name); 184 | } 185 | 186 | public string GetCurrentStateName(int layerIndex) { 187 | return GetCurrentStateInfo(layerIndex).stateName; 188 | } 189 | 190 | public StateInfo GetCurrentStateInfo(int layerIndex) { 191 | return stateInfos[layerIndex][animator.GetCurrentAnimatorStateInfo(layerIndex).shortNameHash]; 192 | } 193 | 194 | [SerializeField] 195 | private int numLayers; 196 | [SerializeField] 197 | private HashStateInfoPair[] layer0Serialized; 198 | [SerializeField] 199 | private HashStateInfoPair[] layer1Serialized; 200 | [SerializeField] 201 | private HashStateInfoPair[] layer2Serialized; 202 | [SerializeField] 203 | private HashStateInfoPair[] layer3Serialized; 204 | 205 | private void SerializeHashToStateInfoDict() { 206 | numLayers = stateInfos.Length; 207 | for (int i = 0; i < stateInfos.Length; i++) { 208 | if (i > 3) { 209 | break; 210 | } 211 | HashStateInfoPair[] arr = null; 212 | 213 | if (i == 0) { 214 | layer0Serialized = new HashStateInfoPair[stateInfos[i].Count]; 215 | arr = layer0Serialized; 216 | } 217 | 218 | if (i == 1) { 219 | layer1Serialized = new HashStateInfoPair[stateInfos[i].Count]; 220 | arr = layer1Serialized; 221 | } 222 | 223 | if (i == 2) { 224 | layer2Serialized = new HashStateInfoPair[stateInfos[i].Count]; 225 | arr = layer2Serialized; 226 | } 227 | 228 | if (i == 3) { 229 | layer3Serialized = new HashStateInfoPair[stateInfos[i].Count]; 230 | arr = layer3Serialized; 231 | } 232 | 233 | int cntr = 0; 234 | foreach (var keyValuePair in stateInfos[i]) { 235 | arr[cntr++] = new HashStateInfoPair(keyValuePair.Key, keyValuePair.Value); 236 | } 237 | } 238 | if (numLayers < 4) { 239 | layer3Serialized = null; 240 | } 241 | if (numLayers < 3) { 242 | layer2Serialized = null; 243 | } 244 | if (numLayers < 2) { 245 | layer1Serialized = null; 246 | } 247 | } 248 | 249 | private void DeserializeHashToStateInfoDict() { 250 | stateInfos = new Dictionary[numLayers]; 251 | for (int i = 0; i < numLayers; i++) { 252 | stateInfos[i] = new Dictionary(); 253 | HashStateInfoPair[] arr = null; 254 | 255 | if (i == 0) { 256 | arr = layer0Serialized; 257 | } 258 | 259 | if (i == 1) { 260 | arr = layer1Serialized; 261 | } 262 | 263 | if (i == 2) { 264 | arr = layer2Serialized; 265 | } 266 | 267 | if (i == 3) { 268 | arr = layer3Serialized; 269 | } 270 | 271 | for (int j = 0; j < arr.Length; j++) { 272 | stateInfos[i][arr[j].intVal] = arr[j].stateInfo; 273 | } 274 | } 275 | } 276 | 277 | } 278 | 279 | /// 280 | /// Contains all the information about a state 281 | /// 282 | [Serializable] 283 | public class StateInfo { 284 | 285 | public StateInfo(string stateName) { 286 | this.stateName = stateName; 287 | containingStateMachines = new List(); 288 | } 289 | 290 | public string stateName; 291 | public List containingStateMachines; 292 | 293 | public override string ToString() { 294 | StringBuilder sb = new StringBuilder(); 295 | sb.Append(stateName); 296 | foreach (var machine in containingStateMachines) { 297 | sb.Append("<-" + machine); 298 | } 299 | 300 | return sb.ToString(); 301 | } 302 | } 303 | 304 | [Serializable] 305 | public class HashStateInfoPair { 306 | 307 | public int intVal; 308 | public StateInfo stateInfo; 309 | 310 | public HashStateInfoPair(int intVal, StateInfo stateInfo) { 311 | this.intVal = intVal; 312 | this.stateInfo = stateInfo; 313 | } 314 | 315 | } 316 | -------------------------------------------------------------------------------- /Test/Test2/Test2.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | SceneSettings: 5 | m_ObjectHideFlags: 0 6 | m_PVSData: 7 | m_PVSObjectsArray: [] 8 | m_PVSPortalsArray: [] 9 | m_OcclusionBakeSettings: 10 | smallestOccluder: 5 11 | smallestHole: 0.25 12 | backfaceThreshold: 100 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 6 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 29 | m_HaloStrength: 0.5 30 | m_FlareStrength: 1 31 | m_FlareFadeSpeed: 3 32 | m_HaloTexture: {fileID: 0} 33 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 34 | m_DefaultReflectionMode: 0 35 | m_DefaultReflectionResolution: 128 36 | m_ReflectionBounces: 1 37 | m_ReflectionIntensity: 1 38 | m_CustomReflection: {fileID: 0} 39 | m_Sun: {fileID: 0} 40 | --- !u!157 &3 41 | LightmapSettings: 42 | m_ObjectHideFlags: 0 43 | serializedVersion: 6 44 | m_GIWorkflowMode: 0 45 | m_LightmapsMode: 1 46 | m_GISettings: 47 | serializedVersion: 2 48 | m_BounceScale: 1 49 | m_IndirectOutputScale: 1 50 | m_AlbedoBoost: 1 51 | m_TemporalCoherenceThreshold: 1 52 | m_EnvironmentLightingMode: 0 53 | m_EnableBakedLightmaps: 1 54 | m_EnableRealtimeLightmaps: 1 55 | m_LightmapEditorSettings: 56 | serializedVersion: 3 57 | m_Resolution: 2 58 | m_BakeResolution: 40 59 | m_TextureWidth: 1024 60 | m_TextureHeight: 1024 61 | m_AOMaxDistance: 1 62 | m_Padding: 2 63 | m_CompAOExponent: 0 64 | m_LightmapParameters: {fileID: 0} 65 | m_TextureCompression: 1 66 | m_FinalGather: 0 67 | m_FinalGatherRayCount: 1024 68 | m_ReflectionCompression: 2 69 | m_LightingDataAsset: {fileID: 0} 70 | m_RuntimeCPUUsage: 25 71 | --- !u!196 &4 72 | NavMeshSettings: 73 | serializedVersion: 2 74 | m_ObjectHideFlags: 0 75 | m_BuildSettings: 76 | serializedVersion: 2 77 | agentRadius: 0.5 78 | agentHeight: 2 79 | agentSlope: 45 80 | agentClimb: 0.4 81 | ledgeDropHeight: 0 82 | maxJumpAcrossDistance: 0 83 | accuratePlacement: 0 84 | minRegionArea: 2 85 | cellSize: 0.16666667 86 | manualCellSize: 0 87 | m_NavMeshData: {fileID: 0} 88 | --- !u!1 &59045090 89 | GameObject: 90 | m_ObjectHideFlags: 0 91 | m_PrefabParentObject: {fileID: 0} 92 | m_PrefabInternal: {fileID: 0} 93 | serializedVersion: 4 94 | m_Component: 95 | - 4: {fileID: 59045094} 96 | - 33: {fileID: 59045093} 97 | - 23: {fileID: 59045091} 98 | - 95: {fileID: 59045095} 99 | - 114: {fileID: 59045092} 100 | m_Layer: 0 101 | m_Name: Cube 102 | m_TagString: Untagged 103 | m_Icon: {fileID: 0} 104 | m_NavMeshLayer: 0 105 | m_StaticEditorFlags: 0 106 | m_IsActive: 1 107 | --- !u!23 &59045091 108 | MeshRenderer: 109 | m_ObjectHideFlags: 0 110 | m_PrefabParentObject: {fileID: 0} 111 | m_PrefabInternal: {fileID: 0} 112 | m_GameObject: {fileID: 59045090} 113 | m_Enabled: 1 114 | m_CastShadows: 1 115 | m_ReceiveShadows: 1 116 | m_Materials: 117 | - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} 118 | m_SubsetIndices: 119 | m_StaticBatchRoot: {fileID: 0} 120 | m_UseLightProbes: 1 121 | m_ReflectionProbeUsage: 1 122 | m_ProbeAnchor: {fileID: 0} 123 | m_ScaleInLightmap: 1 124 | m_PreserveUVs: 1 125 | m_IgnoreNormalsForChartDetection: 0 126 | m_ImportantGI: 0 127 | m_MinimumChartSize: 4 128 | m_AutoUVMaxDistance: 0.5 129 | m_AutoUVMaxAngle: 89 130 | m_LightmapParameters: {fileID: 0} 131 | m_SortingLayerID: 0 132 | m_SortingOrder: 0 133 | --- !u!114 &59045092 134 | MonoBehaviour: 135 | m_ObjectHideFlags: 0 136 | m_PrefabParentObject: {fileID: 0} 137 | m_PrefabInternal: {fileID: 0} 138 | m_GameObject: {fileID: 59045090} 139 | m_Enabled: 1 140 | m_EditorHideFlags: 0 141 | m_Script: {fileID: 11500000, guid: c443be157d62c2c4caf426baa2fa5962, type: 3} 142 | m_Name: 143 | m_EditorClassIdentifier: 144 | numLayers: 1 145 | layer0Serialized: 146 | - intVal: -710203418 147 | stateInfo: 148 | stateName: State 1 149 | containingStateMachines: 150 | - Base Layer 151 | - intVal: 1000687306 152 | stateInfo: 153 | stateName: State 3 154 | containingStateMachines: 155 | - Base Layer 156 | - intVal: 1285715548 157 | stateInfo: 158 | stateName: State 2 159 | containingStateMachines: 160 | - Base Layer 161 | - SubStateMachine 162 | layer1Serialized: [] 163 | layer2Serialized: [] 164 | layer3Serialized: [] 165 | --- !u!33 &59045093 166 | MeshFilter: 167 | m_ObjectHideFlags: 0 168 | m_PrefabParentObject: {fileID: 0} 169 | m_PrefabInternal: {fileID: 0} 170 | m_GameObject: {fileID: 59045090} 171 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 172 | --- !u!4 &59045094 173 | Transform: 174 | m_ObjectHideFlags: 0 175 | m_PrefabParentObject: {fileID: 0} 176 | m_PrefabInternal: {fileID: 0} 177 | m_GameObject: {fileID: 59045090} 178 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 179 | m_LocalPosition: {x: 0, y: 0, z: 0} 180 | m_LocalScale: {x: 1, y: 1, z: 1} 181 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 182 | m_Children: [] 183 | m_Father: {fileID: 0} 184 | m_RootOrder: 2 185 | --- !u!95 &59045095 186 | Animator: 187 | serializedVersion: 3 188 | m_ObjectHideFlags: 0 189 | m_PrefabParentObject: {fileID: 0} 190 | m_PrefabInternal: {fileID: 0} 191 | m_GameObject: {fileID: 59045090} 192 | m_Enabled: 1 193 | m_Avatar: {fileID: 0} 194 | m_Controller: {fileID: 9100000, guid: a69e422aeeeeac54abfe0f75f1aad188, type: 2} 195 | m_CullingMode: 0 196 | m_UpdateMode: 0 197 | m_ApplyRootMotion: 0 198 | m_LinearVelocityBlending: 0 199 | m_WarningMessage: 200 | m_HasTransformHierarchy: 1 201 | m_AllowConstantClipSamplingOptimization: 1 202 | --- !u!1 &813071372 203 | GameObject: 204 | m_ObjectHideFlags: 0 205 | m_PrefabParentObject: {fileID: 0} 206 | m_PrefabInternal: {fileID: 0} 207 | serializedVersion: 4 208 | m_Component: 209 | - 4: {fileID: 813071374} 210 | - 108: {fileID: 813071373} 211 | m_Layer: 0 212 | m_Name: Directional Light 213 | m_TagString: Untagged 214 | m_Icon: {fileID: 0} 215 | m_NavMeshLayer: 0 216 | m_StaticEditorFlags: 0 217 | m_IsActive: 1 218 | --- !u!108 &813071373 219 | Light: 220 | m_ObjectHideFlags: 0 221 | m_PrefabParentObject: {fileID: 0} 222 | m_PrefabInternal: {fileID: 0} 223 | m_GameObject: {fileID: 813071372} 224 | m_Enabled: 1 225 | serializedVersion: 6 226 | m_Type: 1 227 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} 228 | m_Intensity: 1 229 | m_Range: 10 230 | m_SpotAngle: 30 231 | m_CookieSize: 10 232 | m_Shadows: 233 | m_Type: 2 234 | m_Resolution: -1 235 | m_Strength: 1 236 | m_Bias: 0.05 237 | m_NormalBias: 0.4 238 | m_NearPlane: 0.2 239 | m_Cookie: {fileID: 0} 240 | m_DrawHalo: 0 241 | m_Flare: {fileID: 0} 242 | m_RenderMode: 0 243 | m_CullingMask: 244 | serializedVersion: 2 245 | m_Bits: 4294967295 246 | m_Lightmapping: 4 247 | m_BounceIntensity: 1 248 | m_ShadowRadius: 0 249 | m_ShadowAngle: 0 250 | m_AreaSize: {x: 1, y: 1} 251 | --- !u!4 &813071374 252 | Transform: 253 | m_ObjectHideFlags: 0 254 | m_PrefabParentObject: {fileID: 0} 255 | m_PrefabInternal: {fileID: 0} 256 | m_GameObject: {fileID: 813071372} 257 | m_LocalRotation: {x: 0.40821794, y: -0.23456973, z: 0.109381676, w: 0.87542605} 258 | m_LocalPosition: {x: 0, y: 3, z: 0} 259 | m_LocalScale: {x: 1, y: 1, z: 1} 260 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} 261 | m_Children: [] 262 | m_Father: {fileID: 0} 263 | m_RootOrder: 1 264 | --- !u!1 &894761381 265 | GameObject: 266 | m_ObjectHideFlags: 0 267 | m_PrefabParentObject: {fileID: 0} 268 | m_PrefabInternal: {fileID: 0} 269 | serializedVersion: 4 270 | m_Component: 271 | - 4: {fileID: 894761386} 272 | - 20: {fileID: 894761385} 273 | - 92: {fileID: 894761384} 274 | - 124: {fileID: 894761383} 275 | - 81: {fileID: 894761382} 276 | m_Layer: 0 277 | m_Name: Main Camera 278 | m_TagString: MainCamera 279 | m_Icon: {fileID: 0} 280 | m_NavMeshLayer: 0 281 | m_StaticEditorFlags: 0 282 | m_IsActive: 1 283 | --- !u!81 &894761382 284 | AudioListener: 285 | m_ObjectHideFlags: 0 286 | m_PrefabParentObject: {fileID: 0} 287 | m_PrefabInternal: {fileID: 0} 288 | m_GameObject: {fileID: 894761381} 289 | m_Enabled: 1 290 | --- !u!124 &894761383 291 | Behaviour: 292 | m_ObjectHideFlags: 0 293 | m_PrefabParentObject: {fileID: 0} 294 | m_PrefabInternal: {fileID: 0} 295 | m_GameObject: {fileID: 894761381} 296 | m_Enabled: 1 297 | --- !u!92 &894761384 298 | Behaviour: 299 | m_ObjectHideFlags: 0 300 | m_PrefabParentObject: {fileID: 0} 301 | m_PrefabInternal: {fileID: 0} 302 | m_GameObject: {fileID: 894761381} 303 | m_Enabled: 1 304 | --- !u!20 &894761385 305 | Camera: 306 | m_ObjectHideFlags: 0 307 | m_PrefabParentObject: {fileID: 0} 308 | m_PrefabInternal: {fileID: 0} 309 | m_GameObject: {fileID: 894761381} 310 | m_Enabled: 1 311 | serializedVersion: 2 312 | m_ClearFlags: 1 313 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} 314 | m_NormalizedViewPortRect: 315 | serializedVersion: 2 316 | x: 0 317 | y: 0 318 | width: 1 319 | height: 1 320 | near clip plane: 0.3 321 | far clip plane: 1000 322 | field of view: 60 323 | orthographic: 0 324 | orthographic size: 5 325 | m_Depth: -1 326 | m_CullingMask: 327 | serializedVersion: 2 328 | m_Bits: 4294967295 329 | m_RenderingPath: -1 330 | m_TargetTexture: {fileID: 0} 331 | m_TargetDisplay: 0 332 | m_TargetEye: 3 333 | m_HDR: 0 334 | m_OcclusionCulling: 1 335 | m_StereoConvergence: 10 336 | m_StereoSeparation: 0.022 337 | m_StereoMirrorMode: 0 338 | --- !u!4 &894761386 339 | Transform: 340 | m_ObjectHideFlags: 0 341 | m_PrefabParentObject: {fileID: 0} 342 | m_PrefabInternal: {fileID: 0} 343 | m_GameObject: {fileID: 894761381} 344 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 345 | m_LocalPosition: {x: 0, y: 1, z: -10} 346 | m_LocalScale: {x: 1, y: 1, z: 1} 347 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 348 | m_Children: [] 349 | m_Father: {fileID: 0} 350 | m_RootOrder: 0 351 | --- !u!1 &2065542341 352 | GameObject: 353 | m_ObjectHideFlags: 0 354 | m_PrefabParentObject: {fileID: 0} 355 | m_PrefabInternal: {fileID: 0} 356 | serializedVersion: 4 357 | m_Component: 358 | - 4: {fileID: 2065542343} 359 | - 114: {fileID: 2065542342} 360 | m_Layer: 0 361 | m_Name: TestController 362 | m_TagString: Untagged 363 | m_Icon: {fileID: 0} 364 | m_NavMeshLayer: 0 365 | m_StaticEditorFlags: 0 366 | m_IsActive: 1 367 | --- !u!114 &2065542342 368 | MonoBehaviour: 369 | m_ObjectHideFlags: 0 370 | m_PrefabParentObject: {fileID: 0} 371 | m_PrefabInternal: {fileID: 0} 372 | m_GameObject: {fileID: 2065542341} 373 | m_Enabled: 1 374 | m_EditorHideFlags: 0 375 | m_Script: {fileID: 11500000, guid: 576bacae909b73942973c792fb0d9ca5, type: 3} 376 | m_Name: 377 | m_EditorClassIdentifier: 378 | logToConsole: 1 379 | --- !u!4 &2065542343 380 | Transform: 381 | m_ObjectHideFlags: 0 382 | m_PrefabParentObject: {fileID: 0} 383 | m_PrefabInternal: {fileID: 0} 384 | m_GameObject: {fileID: 2065542341} 385 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 386 | m_LocalPosition: {x: 0, y: 0, z: 0} 387 | m_LocalScale: {x: 1, y: 1, z: 1} 388 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 389 | m_Children: [] 390 | m_Father: {fileID: 0} 391 | m_RootOrder: 3 392 | -------------------------------------------------------------------------------- /Test/Test1/Test1.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | SceneSettings: 5 | m_ObjectHideFlags: 0 6 | m_PVSData: 7 | m_PVSObjectsArray: [] 8 | m_PVSPortalsArray: [] 9 | m_OcclusionBakeSettings: 10 | smallestOccluder: 5 11 | smallestHole: 0.25 12 | backfaceThreshold: 100 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 6 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 29 | m_HaloStrength: 0.5 30 | m_FlareStrength: 1 31 | m_FlareFadeSpeed: 3 32 | m_HaloTexture: {fileID: 0} 33 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 34 | m_DefaultReflectionMode: 0 35 | m_DefaultReflectionResolution: 128 36 | m_ReflectionBounces: 1 37 | m_ReflectionIntensity: 1 38 | m_CustomReflection: {fileID: 0} 39 | m_Sun: {fileID: 0} 40 | --- !u!157 &3 41 | LightmapSettings: 42 | m_ObjectHideFlags: 0 43 | serializedVersion: 6 44 | m_GIWorkflowMode: 0 45 | m_LightmapsMode: 1 46 | m_GISettings: 47 | serializedVersion: 2 48 | m_BounceScale: 1 49 | m_IndirectOutputScale: 1 50 | m_AlbedoBoost: 1 51 | m_TemporalCoherenceThreshold: 1 52 | m_EnvironmentLightingMode: 0 53 | m_EnableBakedLightmaps: 1 54 | m_EnableRealtimeLightmaps: 1 55 | m_LightmapEditorSettings: 56 | serializedVersion: 3 57 | m_Resolution: 2 58 | m_BakeResolution: 40 59 | m_TextureWidth: 1024 60 | m_TextureHeight: 1024 61 | m_AOMaxDistance: 1 62 | m_Padding: 2 63 | m_CompAOExponent: 0 64 | m_LightmapParameters: {fileID: 0} 65 | m_TextureCompression: 1 66 | m_FinalGather: 0 67 | m_FinalGatherRayCount: 1024 68 | m_ReflectionCompression: 2 69 | m_LightingDataAsset: {fileID: 0} 70 | m_RuntimeCPUUsage: 25 71 | --- !u!196 &4 72 | NavMeshSettings: 73 | serializedVersion: 2 74 | m_ObjectHideFlags: 0 75 | m_BuildSettings: 76 | serializedVersion: 2 77 | agentRadius: 0.5 78 | agentHeight: 2 79 | agentSlope: 45 80 | agentClimb: 0.4 81 | ledgeDropHeight: 0 82 | maxJumpAcrossDistance: 0 83 | accuratePlacement: 0 84 | minRegionArea: 2 85 | cellSize: 0.16666667 86 | manualCellSize: 0 87 | m_NavMeshData: {fileID: 0} 88 | --- !u!1 &29848305 89 | GameObject: 90 | m_ObjectHideFlags: 0 91 | m_PrefabParentObject: {fileID: 0} 92 | m_PrefabInternal: {fileID: 0} 93 | serializedVersion: 4 94 | m_Component: 95 | - 4: {fileID: 29848307} 96 | - 114: {fileID: 29848306} 97 | m_Layer: 0 98 | m_Name: TestController 99 | m_TagString: Untagged 100 | m_Icon: {fileID: 0} 101 | m_NavMeshLayer: 0 102 | m_StaticEditorFlags: 0 103 | m_IsActive: 1 104 | --- !u!114 &29848306 105 | MonoBehaviour: 106 | m_ObjectHideFlags: 0 107 | m_PrefabParentObject: {fileID: 0} 108 | m_PrefabInternal: {fileID: 0} 109 | m_GameObject: {fileID: 29848305} 110 | m_Enabled: 1 111 | m_EditorHideFlags: 0 112 | m_Script: {fileID: 11500000, guid: c6e68cb4df83bf94cb71912a19ef6b3f, type: 3} 113 | m_Name: 114 | m_EditorClassIdentifier: 115 | logToConsole: 0 116 | --- !u!4 &29848307 117 | Transform: 118 | m_ObjectHideFlags: 0 119 | m_PrefabParentObject: {fileID: 0} 120 | m_PrefabInternal: {fileID: 0} 121 | m_GameObject: {fileID: 29848305} 122 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 123 | m_LocalPosition: {x: 0, y: 0, z: 0} 124 | m_LocalScale: {x: 1, y: 1, z: 1} 125 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 126 | m_Children: [] 127 | m_Father: {fileID: 0} 128 | m_RootOrder: 3 129 | --- !u!1 &938641515 130 | GameObject: 131 | m_ObjectHideFlags: 0 132 | m_PrefabParentObject: {fileID: 0} 133 | m_PrefabInternal: {fileID: 0} 134 | serializedVersion: 4 135 | m_Component: 136 | - 4: {fileID: 938641518} 137 | - 114: {fileID: 938641517} 138 | - 114: {fileID: 938641516} 139 | m_Layer: 0 140 | m_Name: EventSystem 141 | m_TagString: Untagged 142 | m_Icon: {fileID: 0} 143 | m_NavMeshLayer: 0 144 | m_StaticEditorFlags: 0 145 | m_IsActive: 1 146 | --- !u!114 &938641516 147 | MonoBehaviour: 148 | m_ObjectHideFlags: 0 149 | m_PrefabParentObject: {fileID: 0} 150 | m_PrefabInternal: {fileID: 0} 151 | m_GameObject: {fileID: 938641515} 152 | m_Enabled: 1 153 | m_EditorHideFlags: 0 154 | m_Script: {fileID: 1077351063, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} 155 | m_Name: 156 | m_EditorClassIdentifier: 157 | m_HorizontalAxis: Horizontal 158 | m_VerticalAxis: Vertical 159 | m_SubmitButton: Submit 160 | m_CancelButton: Cancel 161 | m_InputActionsPerSecond: 10 162 | m_RepeatDelay: 0.5 163 | m_ForceModuleActive: 0 164 | --- !u!114 &938641517 165 | MonoBehaviour: 166 | m_ObjectHideFlags: 0 167 | m_PrefabParentObject: {fileID: 0} 168 | m_PrefabInternal: {fileID: 0} 169 | m_GameObject: {fileID: 938641515} 170 | m_Enabled: 1 171 | m_EditorHideFlags: 0 172 | m_Script: {fileID: -619905303, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} 173 | m_Name: 174 | m_EditorClassIdentifier: 175 | m_FirstSelected: {fileID: 0} 176 | m_sendNavigationEvents: 1 177 | m_DragThreshold: 5 178 | --- !u!4 &938641518 179 | Transform: 180 | m_ObjectHideFlags: 0 181 | m_PrefabParentObject: {fileID: 0} 182 | m_PrefabInternal: {fileID: 0} 183 | m_GameObject: {fileID: 938641515} 184 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 185 | m_LocalPosition: {x: 0, y: 0, z: 0} 186 | m_LocalScale: {x: 1, y: 1, z: 1} 187 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 188 | m_Children: [] 189 | m_Father: {fileID: 0} 190 | m_RootOrder: 4 191 | --- !u!1 &1105301341 192 | GameObject: 193 | m_ObjectHideFlags: 0 194 | m_PrefabParentObject: {fileID: 0} 195 | m_PrefabInternal: {fileID: 0} 196 | serializedVersion: 4 197 | m_Component: 198 | - 4: {fileID: 1105301345} 199 | - 33: {fileID: 1105301344} 200 | - 23: {fileID: 1105301342} 201 | - 95: {fileID: 1105301346} 202 | - 114: {fileID: 1105301343} 203 | m_Layer: 0 204 | m_Name: Cube 205 | m_TagString: Untagged 206 | m_Icon: {fileID: 0} 207 | m_NavMeshLayer: 0 208 | m_StaticEditorFlags: 0 209 | m_IsActive: 1 210 | --- !u!23 &1105301342 211 | MeshRenderer: 212 | m_ObjectHideFlags: 0 213 | m_PrefabParentObject: {fileID: 0} 214 | m_PrefabInternal: {fileID: 0} 215 | m_GameObject: {fileID: 1105301341} 216 | m_Enabled: 1 217 | m_CastShadows: 1 218 | m_ReceiveShadows: 1 219 | m_Materials: 220 | - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} 221 | m_SubsetIndices: 222 | m_StaticBatchRoot: {fileID: 0} 223 | m_UseLightProbes: 1 224 | m_ReflectionProbeUsage: 1 225 | m_ProbeAnchor: {fileID: 0} 226 | m_ScaleInLightmap: 1 227 | m_PreserveUVs: 1 228 | m_IgnoreNormalsForChartDetection: 0 229 | m_ImportantGI: 0 230 | m_MinimumChartSize: 4 231 | m_AutoUVMaxDistance: 0.5 232 | m_AutoUVMaxAngle: 89 233 | m_LightmapParameters: {fileID: 0} 234 | m_SortingLayerID: 0 235 | m_SortingOrder: 0 236 | --- !u!114 &1105301343 237 | MonoBehaviour: 238 | m_ObjectHideFlags: 0 239 | m_PrefabParentObject: {fileID: 0} 240 | m_PrefabInternal: {fileID: 0} 241 | m_GameObject: {fileID: 1105301341} 242 | m_Enabled: 1 243 | m_EditorHideFlags: 0 244 | m_Script: {fileID: 11500000, guid: c443be157d62c2c4caf426baa2fa5962, type: 3} 245 | m_Name: 246 | m_EditorClassIdentifier: 247 | numLayers: 1 248 | layer0Serialized: 249 | - intVal: -710203418 250 | stateInfo: 251 | stateName: State 1 252 | containingStateMachines: 253 | - Base Layer 254 | - intVal: 1285715548 255 | stateInfo: 256 | stateName: State 2 257 | containingStateMachines: 258 | - Base Layer 259 | - intVal: 1000687306 260 | stateInfo: 261 | stateName: State 3 262 | containingStateMachines: 263 | - Base Layer 264 | layer1Serialized: [] 265 | layer2Serialized: [] 266 | layer3Serialized: [] 267 | --- !u!33 &1105301344 268 | MeshFilter: 269 | m_ObjectHideFlags: 0 270 | m_PrefabParentObject: {fileID: 0} 271 | m_PrefabInternal: {fileID: 0} 272 | m_GameObject: {fileID: 1105301341} 273 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 274 | --- !u!4 &1105301345 275 | Transform: 276 | m_ObjectHideFlags: 0 277 | m_PrefabParentObject: {fileID: 0} 278 | m_PrefabInternal: {fileID: 0} 279 | m_GameObject: {fileID: 1105301341} 280 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 281 | m_LocalPosition: {x: 0, y: 0, z: 0} 282 | m_LocalScale: {x: 1, y: 1, z: 1} 283 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 284 | m_Children: [] 285 | m_Father: {fileID: 0} 286 | m_RootOrder: 2 287 | --- !u!95 &1105301346 288 | Animator: 289 | serializedVersion: 3 290 | m_ObjectHideFlags: 0 291 | m_PrefabParentObject: {fileID: 0} 292 | m_PrefabInternal: {fileID: 0} 293 | m_GameObject: {fileID: 1105301341} 294 | m_Enabled: 1 295 | m_Avatar: {fileID: 0} 296 | m_Controller: {fileID: 9100000, guid: 05b17e96685708c408b59ff8f4adb715, type: 2} 297 | m_CullingMode: 0 298 | m_UpdateMode: 0 299 | m_ApplyRootMotion: 0 300 | m_LinearVelocityBlending: 0 301 | m_WarningMessage: 302 | m_HasTransformHierarchy: 1 303 | m_AllowConstantClipSamplingOptimization: 1 304 | --- !u!1 &1948855265 305 | GameObject: 306 | m_ObjectHideFlags: 0 307 | m_PrefabParentObject: {fileID: 0} 308 | m_PrefabInternal: {fileID: 0} 309 | serializedVersion: 4 310 | m_Component: 311 | - 4: {fileID: 1948855267} 312 | - 108: {fileID: 1948855266} 313 | m_Layer: 0 314 | m_Name: Directional Light 315 | m_TagString: Untagged 316 | m_Icon: {fileID: 0} 317 | m_NavMeshLayer: 0 318 | m_StaticEditorFlags: 0 319 | m_IsActive: 1 320 | --- !u!108 &1948855266 321 | Light: 322 | m_ObjectHideFlags: 0 323 | m_PrefabParentObject: {fileID: 0} 324 | m_PrefabInternal: {fileID: 0} 325 | m_GameObject: {fileID: 1948855265} 326 | m_Enabled: 1 327 | serializedVersion: 6 328 | m_Type: 1 329 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} 330 | m_Intensity: 1 331 | m_Range: 10 332 | m_SpotAngle: 30 333 | m_CookieSize: 10 334 | m_Shadows: 335 | m_Type: 2 336 | m_Resolution: -1 337 | m_Strength: 1 338 | m_Bias: 0.05 339 | m_NormalBias: 0.4 340 | m_NearPlane: 0.2 341 | m_Cookie: {fileID: 0} 342 | m_DrawHalo: 0 343 | m_Flare: {fileID: 0} 344 | m_RenderMode: 0 345 | m_CullingMask: 346 | serializedVersion: 2 347 | m_Bits: 4294967295 348 | m_Lightmapping: 4 349 | m_BounceIntensity: 1 350 | m_ShadowRadius: 0 351 | m_ShadowAngle: 0 352 | m_AreaSize: {x: 1, y: 1} 353 | --- !u!4 &1948855267 354 | Transform: 355 | m_ObjectHideFlags: 0 356 | m_PrefabParentObject: {fileID: 0} 357 | m_PrefabInternal: {fileID: 0} 358 | m_GameObject: {fileID: 1948855265} 359 | m_LocalRotation: {x: 0.40821794, y: -0.23456973, z: 0.109381676, w: 0.87542605} 360 | m_LocalPosition: {x: 0, y: 3, z: 0} 361 | m_LocalScale: {x: 1, y: 1, z: 1} 362 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} 363 | m_Children: [] 364 | m_Father: {fileID: 0} 365 | m_RootOrder: 1 366 | --- !u!1 &2036048490 367 | GameObject: 368 | m_ObjectHideFlags: 0 369 | m_PrefabParentObject: {fileID: 0} 370 | m_PrefabInternal: {fileID: 0} 371 | serializedVersion: 4 372 | m_Component: 373 | - 4: {fileID: 2036048495} 374 | - 20: {fileID: 2036048494} 375 | - 92: {fileID: 2036048493} 376 | - 124: {fileID: 2036048492} 377 | - 81: {fileID: 2036048491} 378 | m_Layer: 0 379 | m_Name: Main Camera 380 | m_TagString: MainCamera 381 | m_Icon: {fileID: 0} 382 | m_NavMeshLayer: 0 383 | m_StaticEditorFlags: 0 384 | m_IsActive: 1 385 | --- !u!81 &2036048491 386 | AudioListener: 387 | m_ObjectHideFlags: 0 388 | m_PrefabParentObject: {fileID: 0} 389 | m_PrefabInternal: {fileID: 0} 390 | m_GameObject: {fileID: 2036048490} 391 | m_Enabled: 1 392 | --- !u!124 &2036048492 393 | Behaviour: 394 | m_ObjectHideFlags: 0 395 | m_PrefabParentObject: {fileID: 0} 396 | m_PrefabInternal: {fileID: 0} 397 | m_GameObject: {fileID: 2036048490} 398 | m_Enabled: 1 399 | --- !u!92 &2036048493 400 | Behaviour: 401 | m_ObjectHideFlags: 0 402 | m_PrefabParentObject: {fileID: 0} 403 | m_PrefabInternal: {fileID: 0} 404 | m_GameObject: {fileID: 2036048490} 405 | m_Enabled: 1 406 | --- !u!20 &2036048494 407 | Camera: 408 | m_ObjectHideFlags: 0 409 | m_PrefabParentObject: {fileID: 0} 410 | m_PrefabInternal: {fileID: 0} 411 | m_GameObject: {fileID: 2036048490} 412 | m_Enabled: 1 413 | serializedVersion: 2 414 | m_ClearFlags: 1 415 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} 416 | m_NormalizedViewPortRect: 417 | serializedVersion: 2 418 | x: 0 419 | y: 0 420 | width: 1 421 | height: 1 422 | near clip plane: 0.3 423 | far clip plane: 1000 424 | field of view: 60 425 | orthographic: 0 426 | orthographic size: 5 427 | m_Depth: -1 428 | m_CullingMask: 429 | serializedVersion: 2 430 | m_Bits: 4294967295 431 | m_RenderingPath: -1 432 | m_TargetTexture: {fileID: 0} 433 | m_TargetDisplay: 0 434 | m_TargetEye: 3 435 | m_HDR: 0 436 | m_OcclusionCulling: 1 437 | m_StereoConvergence: 10 438 | m_StereoSeparation: 0.022 439 | m_StereoMirrorMode: 0 440 | --- !u!4 &2036048495 441 | Transform: 442 | m_ObjectHideFlags: 0 443 | m_PrefabParentObject: {fileID: 0} 444 | m_PrefabInternal: {fileID: 0} 445 | m_GameObject: {fileID: 2036048490} 446 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 447 | m_LocalPosition: {x: 0, y: 1, z: -10} 448 | m_LocalScale: {x: 1, y: 1, z: 1} 449 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 450 | m_Children: [] 451 | m_Father: {fileID: 0} 452 | m_RootOrder: 0 453 | --------------------------------------------------------------------------------