/// <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));
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        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);
        }