/// <summary> /// Inspects a MonoBehaviour for state methods as definied by the supplied Enum, and returns a stateMachine instance used to trasition states. /// </summary> public static StateMachine <T> Initialize(MonoBehaviour i_Component, T i_StartState) { StateMachineRunner stateMachineRunner = i_Component.GetComponent <StateMachineRunner>(); if (stateMachineRunner == null) { stateMachineRunner = i_Component.gameObject.AddComponent <StateMachineRunner>(); } return(stateMachineRunner.Initialize <T>(i_Component, i_StartState)); }
/// <summary> /// Inspects a MonoBehaviour for state methods as definied by the supplied Enum, and returns a stateMachine instance used to trasition states. /// </summary> /// <param name="component">The component with defined state methods</param> /// <param name="startState">The default starting state</param> /// <returns>A valid stateMachine instance to manage MonoBehaviour state transitions</returns> public static StateMachine <T> Initialize(MonoBehaviour component, T startState) { var engine = component.GetComponent <StateMachineRunner>(); if (engine == null) { engine = component.gameObject.AddComponent <StateMachineRunner>(); } return(engine.Initialize <T>(component, startState)); }
public StateMachine(StateMachineRunner engine, MonoBehaviour component) { this.engine = engine; this.component = component; //Define States var values = Enum.GetValues(typeof(T)); if (values.Length < 1) { throw new ArgumentException("Enum provided to Initialize must have at least 1 visible definition"); } stateLookup = new Dictionary <object, StateMapping>(); for (int i = 0; i < values.Length; i++) { var mapping = new StateMapping((Enum)values.GetValue(i)); stateLookup.Add(mapping.state, mapping); } //Reflect methods var methods = component.GetType().GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic); //Bind methods to states var separator = "_".ToCharArray(); for (int i = 0; i < methods.Length; i++) { if (methods[i].GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Length != 0) { continue; } var names = methods[i].Name.Split(separator); //Ignore functions without an underscore if (names.Length <= 1) { continue; } Enum key; try { key = (Enum)Enum.Parse(typeof(T), names[0]); } catch (ArgumentException) { //Not an method as listed in the state enum continue; } var targetState = stateLookup[key]; switch (names[1]) { case "Enter": if (methods[i].ReturnType == typeof(IEnumerator)) { targetState.hasEnterRoutine = true; targetState.EnterRoutine = CreateDelegate <Func <IEnumerator> >(methods[i], component); } else { targetState.hasEnterRoutine = false; targetState.EnterCall = CreateDelegate <Action>(methods[i], component); } break; case "Exit": if (methods[i].ReturnType == typeof(IEnumerator)) { targetState.hasExitRoutine = true; targetState.ExitRoutine = CreateDelegate <Func <IEnumerator> >(methods[i], component); } else { targetState.hasExitRoutine = false; targetState.ExitCall = CreateDelegate <Action>(methods[i], component); } break; case "Finally": targetState.Finally = CreateDelegate <Action>(methods[i], component); break; case "Update": targetState.Update = CreateDelegate <Action>(methods[i], component); break; case "LateUpdate": targetState.LateUpdate = CreateDelegate <Action>(methods[i], component); break; case "FixedUpdate": targetState.FixedUpdate = CreateDelegate <Action>(methods[i], component); break; case "OnCollisionEnter": targetState.OnCollisionEnter = CreateDelegate <Action <Collision> >(methods[i], component); break; } } //Create nil state mapping currentState = new StateMapping(null); }
// CTOR public StateMachine(StateMachineRunner i_StateMachineRunner, MonoBehaviour i_Component) { m_StateMachineRunner = i_StateMachineRunner; m_Component = i_Component; // Define states. Array values = Enum.GetValues(typeof(T)); if (values.Length < 1) { throw new ArgumentException("Enum provided to Initialize must have at least 1 visible definition."); } m_StateLookup = new Dictionary <object, StateMapping>(); for (int valueIndex = 0; valueIndex < values.Length; ++valueIndex) { StateMapping mapping = new StateMapping((Enum)values.GetValue(valueIndex)); m_StateLookup.Add(mapping.state, mapping); } // Reflect methods. MethodInfo[] methods = i_Component.GetType().GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic); // Bind methods to states. string separatorString = "_"; char[] separator = separatorString.ToCharArray(); for (int methodIndex = 0; methodIndex < methods.Length; ++methodIndex) { MethodInfo methodInfo = methods[methodIndex]; if (methodInfo.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Length != 0) { continue; } string methodName = methodInfo.Name; string[] nameSplit = methodName.Split(separator); // Ignore functions without an underscore. if (nameSplit.Length <= 1) { continue; } Enum key; try { key = (Enum)Enum.Parse(typeof(T), nameSplit[0]); } catch (ArgumentException) { continue; // Selected method is not list in state enum. } StateMapping targetMapping = m_StateLookup[key]; switch (nameSplit[1]) { case "Enter": if (methodInfo.ReturnType == typeof(IEnumerator)) { targetMapping.hasEnterRoutine = true; targetMapping.EnterRoutine = CreateDelegate <Func <IEnumerator> >(methodInfo, i_Component); } else { targetMapping.hasEnterRoutine = false; targetMapping.EnterCall = CreateDelegate <Action>(methodInfo, i_Component); } break; case "Exit": if (methodInfo.ReturnType == typeof(IEnumerator)) { targetMapping.hasExitRoutine = true; targetMapping.ExitRoutine = CreateDelegate <Func <IEnumerator> >(methodInfo, i_Component); } else { targetMapping.hasExitRoutine = false; targetMapping.ExitCall = CreateDelegate <Action>(methodInfo, i_Component); } break; case "Finally": targetMapping.Finally = CreateDelegate <Action>(methodInfo, i_Component); break; case "FixedUpdate": targetMapping.FixedUpdate = CreateDelegate <Action>(methodInfo, i_Component); break; case "Update": targetMapping.Update = CreateDelegate <Action>(methodInfo, i_Component); break; case "LateUpdate": targetMapping.LateUpdate = CreateDelegate <Action>(methodInfo, i_Component); break; } } // Create nil state mapping. m_CurrentState = new StateMapping(null); }