private IEnumerator CoTransitToNewState(StateMapping newState, TransitionOptions options) { // Cache this so that we can overwrite it and hijack a transition. _destinationState = newState; if (_currentState != null) { if (_currentState.layout.hasExitCoroutine) { _exitCoroutine = _currentState.exitCoroutine(); // Don't wait for exit if we are overwriting if (_exitCoroutine != null && (options & TransitionOptions.Overwrite) == 0) { yield return(_runner.StartCoroutine(_exitCoroutine)); } _exitCoroutine = null; } else { _currentState.exitCall(); } _currentState.finallyCall(); } _lastState = _currentState; _currentState = _destinationState; _stateChangedAt = Time.time; if (_currentState != null) { if (_currentState.layout.hasEnterCoroutine) { _enterCoroutine = _currentState.enterCoroutine(); if (_enterCoroutine != null) { yield return(_runner.StartCoroutine(_enterCoroutine)); } _enterCoroutine = null; } else { _currentState.enterCall(); } // Broadcast change only after enter transition has begun. Changed?.Invoke(_lastState.state != null ? (T)_lastState.state : default(T), (T)_currentState.state); } _isInTransition = false; }
public void Transit(T newState, TransitionOptions options) { if (_stateLookup == null) { throw new Exception("States have not been configured, please call initialized before trying to set state"); } StateMapping nextState = null; if (!_stateLookup.TryGetValue(newState, out nextState)) { 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"); } // Self transition. if ((options & TransitionOptions.AllowSelfTransition) == 0) { if (_currentState == nextState) { return; } } // Cancel any queued changes. if (_queuedChange != null) { _runner.StopCoroutine(_queuedChange); _queuedChange = null; } if ((options & TransitionOptions.Overwrite) == 0) { if (_isInTransition) { // We are already exiting current state on our way to our previous target state if (_exitCoroutine != null) { // Overwrite with our new target _destinationState = nextState; return; } // We are already entering our previous target state. // Need to wait for that to finish and call the exit routine. if (_enterCoroutine != null) { // Damn, I need to test this hard _queuedChange = CoWaitForPreviousTranstionAndTransitToNext(nextState); _runner.StartCoroutine(_queuedChange); return; } } } else { if (_currentTransition != null) { _runner.StopCoroutine(_currentTransition); } if (_exitCoroutine != null) { _runner.StopCoroutine(_exitCoroutine); } if (_enterCoroutine != null) { _runner.StopCoroutine(_enterCoroutine); } } if ((_currentState != null && _currentState.layout.hasExitCoroutine) || nextState.layout.hasEnterCoroutine) { _isInTransition = true; _currentTransition = CoTransitToNewState(nextState, options); _runner.StartCoroutine(_currentTransition); } else //Same frame transition, no coroutines are present { if (_currentState != null) { _currentState.exitCall(); _currentState.finallyCall(); } _lastState = _currentState; _currentState = nextState; _stateChangedAt = Time.time; if (_currentState != null) { _currentState.enterCall(); Changed?.Invoke(_lastState.state != null ? (T)_lastState.state : default(T), (T)_currentState.state); } _isInTransition = false; } }