Skip to content

Instantly share code, notes, and snippets.

@RevenantX
Last active September 5, 2016 16:26
Show Gist options
  • Save RevenantX/960b2d6624bc7beccd8332dac222e95c to your computer and use it in GitHub Desktop.
Save RevenantX/960b2d6624bc7beccd8332dac222e95c to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
namespace Game.Shared.Helpers
{
public class StateMachine<TStateEnum, TCommandEnum, TStateMachine>
where TStateEnum : struct, IComparable, IFormattable, IConvertible
where TCommandEnum : struct, IComparable, IFormattable, IConvertible
where TStateMachine : StateMachine<TStateEnum, TCommandEnum, TStateMachine>
{
public interface IStateMachineOwner
{
TStateMachine StateMachine { get; }
}
public abstract class BasicState
{
private readonly IStateMachineOwner _owner;
public IStateMachineOwner Owner { get { return _owner; } }
protected BasicState(IStateMachineOwner owner)
{
_owner = owner;
}
protected void SetState(TStateEnum state)
{
_owner.StateMachine.SetState(state);
}
protected TCommandEnum CurrentCommand
{
get { return _owner.StateMachine.CurrentCommand; }
}
protected void ChangeStateIfCommand(TCommandEnum command, TStateEnum targetState)
{
if (_owner.StateMachine.CurrentCommand.Equals(command))
{
_owner.StateMachine.SetState(targetState);
}
}
protected bool CompareCommand(params TCommandEnum[] possible)
{
for (int i = 0; i < possible.Length; i++)
if (possible[i].Equals(_owner.StateMachine.CurrentCommand))
return true;
return false;
}
public virtual void Update(float deltaTime) { }
public virtual void OnCommand() { }
public virtual void OnEnter() { }
public virtual void OnExit() { }
}
public abstract class TransitionState : BasicState
{
private float _timer;
private bool _forward;
public float TransitionTime = 1f;
public TStateEnum BackwardState { get; private set; }
public TStateEnum ForwardState { get; private set; }
public TCommandEnum[] BackCommands { get; private set; }
public TCommandEnum[] ForwardCommands { get; private set; }
public float Progress { get { return _timer / TransitionTime; } }
public float InversedProgress { get { return TransitionTime - (_timer / TransitionTime); } }
public float Timer { get { return _timer; } }
public bool Forward { get { return _forward; } }
protected TransitionState(IStateMachineOwner owner) : base(owner)
{
}
public override void OnEnter()
{
_timer = 0f;
}
public sealed override void OnCommand()
{
if (CompareCommand(ForwardCommands))
{
if (!_forward && _timer > 0f)
{
_timer = TransitionTime - _timer;
}
_forward = true;
OnStartTransition(_forward);
return;
}
if (CompareCommand(BackCommands))
{
if (_forward && _timer > 0)
{
_timer = TransitionTime - _timer;
}
_forward = false;
OnStartTransition(_forward);
}
}
protected virtual void OnStartTransition(bool forward)
{
}
public void SetBackwardCommands(TStateEnum backwardState, params TCommandEnum[] commands)
{
BackwardState = backwardState;
BackCommands = commands;
}
public void SetForwardCommands(TStateEnum forwardState, params TCommandEnum[] commands)
{
ForwardState = forwardState;
ForwardCommands = commands;
}
public override void Update(float deltaTime)
{
_timer += deltaTime;
if (_timer >= TransitionTime)
{
_timer = TransitionTime;
SetState(_forward ? ForwardState : BackwardState);
}
}
}
private BasicState _currentState;
private TStateEnum _currentStateName;
private TCommandEnum _currentCommand;
private readonly Dictionary<TStateEnum, BasicState> _states = new Dictionary<TStateEnum, BasicState>();
public TStateEnum CurrentStateName
{
get { return _currentStateName; }
}
public BasicState CurrentState
{
get { return _currentState; }
}
public TCommandEnum CurrentCommand
{
get { return _currentCommand; }
}
public void SetState(TStateEnum stateName, BasicState state)
{
_states[stateName] = state;
}
public void CallCommand(TCommandEnum command)
{
if (!command.Equals(_currentCommand))
{
_currentCommand = command;
_currentState.OnCommand();
}
}
public void Update(float deltaTime)
{
_currentState.Update(deltaTime);
}
public void Start(TCommandEnum startCommand, TStateEnum startState)
{
_currentCommand = startCommand;
_currentStateName = startState;
_currentState = _states[startState];
_currentState.OnEnter();
_currentState.OnCommand();
}
public void SetState(TStateEnum state)
{
_currentState.OnExit();
_currentStateName = state;
_currentState = _states[state];
_currentState.OnEnter();
_currentState.OnCommand();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment