private IEnumerator ChangeToNewStateRoutine(StateMapping newState, StateTransition transtiion) { _destinationState = newState; if (_currentState != null) { if (_currentState.hasExitRoutine) { _exitRoutine = _currentState.ExitRoutine(); if (_exitRoutine != null && transtiion != StateTransition.Overwrite) { yield return(_engine.StartCoroutine(_exitRoutine)); } _exitRoutine = null; } else { _currentState.ExitCall(); } _currentState.Finally(); } _lastState = _currentState; _currentState = _destinationState; if (_currentState != null) { if (_currentState.hasEnterRoutine) { _enterRoutine = _currentState.EnterRoutine(); if (_enterRoutine != null) { yield return(_engine.StartCoroutine(_enterRoutine)); } _enterRoutine = null; } else { _currentState.EnterCall(); } if (Changed != null) { Changed(_currentState.State); } } _isInTransition = false; }
public void ChangeState(Enum newState, StateTransition transition = StateTransition.Safe) { if (stateLookup == null) { throw new Exception("States have not been configured, please call initialized before trying to set state"); } if (!stateLookup.ContainsKey(newState)) { throw new Exception("No state with the name " + newState.ToString() + " can be found. Please make sure you are called the correct type the statemachine was initialized with"); } var nextState = stateLookup[newState]; // Uncomment this to block loop transitions // if (currentState == nextState) return; // Cancel any queued changes. if (queuedChange != null) { StopCoroutine(queuedChange); queuedChange = null; } switch (transition) { // case StateMachineTransition.Blend: // Do nothing - allows the state transitions to overlap each other. This is a dumb idea, as previous state might trigger new changes. // A better way would be to start the two couroutines at the same time. IE don't wait for exit before starting start. // How does this work in terms of overwrite? // Is there a way to make this safe, I don't think so? // break; case StateTransition.Safe: if (isInTransition) { if (exitRoutine != null) // We are already exiting current state on our way to our previous target state { // Overwrite with our new target destinationState = nextState; return; } if (enterRoutine != null) // We are already entering our previous target state. Need to wait for that to finish and call the exit routine. { // Damn, I need to test this hard queuedChange = WaitForPreviousTransition(nextState); StartCoroutine(queuedChange); return; } } break; case StateTransition.Overwrite: if (currentTransition != null) { StopCoroutine(currentTransition); } if (exitRoutine != null) { StopCoroutine(exitRoutine); } if (enterRoutine != null) { StopCoroutine(enterRoutine); } if (currentState != null) { currentState.Finally(); } currentState = null; // We need to set current state to null so that we don't trigger it's exit routine break; } isInTransition = true; currentTransition = ChangeToNewStateRoutine(nextState); StartCoroutine(currentTransition); }
public void ChangeState(T newState, StateTransition transition) { if (stateLookup == null) { throw new Exception("States have not been configured, please call initialized before trying to set state"); } if (!stateLookup.ContainsKey(newState)) { throw new Exception("No state with the name " + newState.ToString() + " can be found. Please make sure you are called the correct type the statemachine was initialized with"); } var nextState = stateLookup[newState]; if (currentState == nextState) { return; } //Cancel any queued changes. if (queuedChange != null) { engine.StopCoroutine(queuedChange); queuedChange = null; } switch (transition) { //case StateMachineTransition.Blend: //Do nothing - allows the state transitions to overlap each other. This is a dumb idea, as previous state might trigger new changes. //A better way would be to start the two couroutines at the same time. IE don't wait for exit before starting start. //How does this work in terms of overwrite? //Is there a way to make this safe, I don't think so? //break; case StateTransition.Safe: if (isInTransition) { if (exitRoutine != null) //We are already exiting current state on our way to our previous target state { //Overwrite with our new target destinationState = nextState; return; } if (enterRoutine != null) //We are already entering our previous target state. Need to wait for that to finish and call the exit routine. { //Damn, I need to test this hard queuedChange = WaitForPreviousTransition(nextState); engine.StartCoroutine(queuedChange); return; } } break; case StateTransition.Overwrite: if (currentTransition != null) { engine.StopCoroutine(currentTransition); } if (exitRoutine != null) { engine.StopCoroutine(exitRoutine); } if (enterRoutine != null) { engine.StopCoroutine(enterRoutine); } //Note: if we are currently in an EnterRoutine and Exit is also a routine, this will be skipped in ChangeToNewStateRoutine() break; } if ((currentState != null && currentState.hasExitRoutine) || nextState.hasEnterRoutine) { isInTransition = true; currentTransition = ChangeToNewStateRoutine(nextState, transition); engine.StartCoroutine(currentTransition); } else //Same frame transition, no coroutines are present { if (currentState != null) { currentState.ExitCall(); currentState.Finally(); } lastState = currentState; currentState = nextState; if (currentState != null) { currentState.EnterCall(); if (Changed != null) { Changed((T)currentState.state); } } isInTransition = false; } }