/// <summary> /// Attempts to advance to a new state, checking for unknown and null states. /// </summary> /// <param name="nextState">The name of the state to go to (as sent to AddState).</param> protected void AdvanceToState(String nextState) { // If they passed a value state name... if (!String.IsNullOrEmpty(nextState)) { // ...and it is one that we are managing. if (mStates.ContainsKey(nextState)) { // Request a new state and move to the END pass of this flow. mNextState = mStates[nextState]; mCurrentFlowState = FlowStates.END; } else { System.Diagnostics.Debug.Assert(false, "FSMState returned a new state which is not managed by this state machine: " + nextState); } } }
/// <summary> /// Called by GameObjectFactory when object is recycled. /// </summary> public override void Reset() { mCurrentState = mNextState = mInitialState; mCurrentFlowState = FlowStates.INITIAL_STATE; }
/// <summary> /// Interface for adding new FSMState to this FiniteStateMachine. /// </summary> /// <param name="state">Implementation of the FSMState.</param> /// <param name="id">An indentifier used to manage and transition between states.</param> protected void AddState(FSMState state, String id) { // The state will be expecting to access the Parent GameObject a lot. state.pParentGOH = mParentGOH; // Check for duplicate entries. if (mStates.ContainsKey(id)) { System.Diagnostics.Debug.Assert(false, "Attempting to add two FSMState objects with the same ID to a FiniteStateMachine: " + id); return; } else { // Add it to our list of states. mStates.Add(id, state); } // If this is the first state to be added, use it as the initial FSMState to be run. if (mCurrentState == null) { mInitialState = mCurrentState = mNextState = state; mCurrentFlowState = FlowStates.INITIAL_STATE; } }
/// <summary> /// Called once per frame by the game object. /// </summary> /// <param name="gameTime">The amount of time that has passed this frame.</param> public override void Update(GameTime gameTime) { // The basic flow for every state machine: // 1) Run OnBegin (1 frame). // 2) Run OnUpdate (Indefinitly; until it returns a new state to transition to). // 3) Run OnEnd (1 frame). // switch (mCurrentFlowState) { case FlowStates.BEGIN: { // Transition directly to the UPDATE pass. Do it before calling OnBegin incase // OnBegin actually sets the current state through a message, in which case we // don't want to go to UPDATE. mCurrentFlowState = FlowStates.UPDATE; mCurrentState.OnBegin(); break; } case FlowStates.UPDATE: { // Update the state which will potentially return a new state in which to transition to. String nextState = mCurrentState.OnUpdate(); AdvanceToState(nextState); break; } case FlowStates.END: { mCurrentState.OnEnd(); // Once the FlowStates.END has finished it is time to move onto the next FSMState. mCurrentState = mNextState; // On the next update pass we will be running a new FSMState, so we want to be sitting // in the BEGIN flow state. mCurrentFlowState = FlowStates.BEGIN; break; } default: { System.Diagnostics.Debug.Assert(false, "Unhandled FSM Flow State."); break; } } // Keep going until we get to an update state. This is to avoid objects popping out and // in between states. if (mCurrentFlowState != FlowStates.UPDATE) { Update(gameTime); } }