/// <summary> /// Create state machine info for a given type /// </summary> /// <param name="type"></param> /// <returns></returns> public static StateMachineInfo Create(Type type) { if (_cache.TryGetValue(type, out var info)) { return(info); } // Collect all info from the type var states = new List <StateInfo>(); var triggers = new List <StateTriggerInfo>(); var transitions = new List <StateTransitionInfo>(); GetInfo(type, states, triggers, transitions); // Validate that all the states referenced were found foreach (var state in states) { GetStateDelegate(state, type); } info = new StateMachineInfo(); info.TargetType = type; info.States = states.ToArray(); info.Triggers = triggers.ToArray(); info.Transitions = transitions.ToArray(); return(info); }
/// <summary> /// Start a new state machine on the given target using the given initial state /// </summary> public static void Start(Object target, string initialState, string key, UpdateMode mode) { var sm = _stateMachinePool.Get(); sm._sminfo = StateMachineInfo.Create(target.GetType()); sm._key = key; sm._target = target; sm._updateMode = mode; sm._elapsedTimeInState = 0.0f; // Track all running state machines _stateMachines.Add(sm); // Set the initial state sm.SetState(initialState); }
/// <summary> /// Attempt to add a transition to the given transitions list /// </summary> private static StateTransitionInfo CreateTransition(StateMachineInfo info, StateInfo from, StateInfo to) { if (from == to) { return(null); } // Check for the transition method var methodInfo = info.TargetType.GetMethod( $"On{from?.Name??"Any"}To{to?.Name??"Any"}", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (methodInfo == null) { return(null); } return(new StateTransitionInfo { From = from, To = to, InvokeDelegate = OpenDelegate.Create(methodInfo) }); }
/// <summary> /// Create state machine info for a given type /// </summary> /// <param name="type"></param> /// <returns></returns> public static StateMachineInfo Create(Type type, Type statesType) { var typeName = type.FullName; if (_cache.TryGetValue(typeName, out var info)) { return(info); } var values = Enum.GetValues(statesType); var states = new StateInfo[values.Length]; foreach (var value in values) { var index = (int)value; var name = value.ToString(); if (index < 0 || index >= states.Length) { throw new UnityException("State enum must be sequential and start from zero"); } states[index] = new StateInfo { Name = value.ToString(), Mask = (1UL << index), Index = index }; } // Create a new state machine info info = new StateMachineInfo(); info.TargetType = type; info.States = states; info._transitionStride = states.Length + 1; _cache.Add(typeName, info); // Get state method and transitions info._transitions = new StateTransitionInfo[states.Length * info._transitionStride]; foreach (var stateToInfo in states) { // State method? var stateMethod = type.GetMethod($"On{stateToInfo.Name}", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (null != stateMethod) { var parameters = stateMethod.GetParameters(); if (parameters.Length == 0) { stateToInfo.InvokeDelegate = OpenDelegate.Create(stateMethod); } else if (parameters.Length == 1 && parameters[0].ParameterType == typeof(float)) { stateToInfo.InvokeWithTimeDelegate = OpenDelegate <float> .Create(stateMethod); } else { throw new UnityException($"method for state '{stateToInfo.Name}' does not match a valid state signature"); } } // Add the "Any" to state transition info._transitions[info.GetTransitionIndex(-1, stateToInfo.Index)] = CreateTransition(info, null, stateToInfo); // Add transition from all other states foreach (var stateFromInfo in states) { info._transitions[info.GetTransitionIndex(stateFromInfo.Index, stateToInfo.Index)] = CreateTransition(info, stateFromInfo, stateToInfo); } } return(info); }