Skip to content

Instantly share code, notes, and snippets.

@eka
Last active May 22, 2024 06:58
Show Gist options
  • Save eka/5f88e80142fe9569687797cde387d806 to your computer and use it in GitHub Desktop.
Save eka/5f88e80142fe9569687797cde387d806 to your computer and use it in GitHub Desktop.
using Godot;
public partial class State : Node
{
[Signal]
public delegate void FinishedEventHandler(string nextState);
[Signal]
public delegate void StackEventHandler(string nextState);
public virtual void Enter(Node host)
{
}
public virtual void Exit(Node host)
{
}
public virtual void HandleInput(Node host, InputEvent @event)
{
}
public virtual void UnhandledInput(Node host, InputEvent @event)
{
}
public virtual void Update(Node host, double delta)
{
}
public virtual void PhysicsUpdate(Node host, double delta)
{
}
public override string ToString()
{
return Name;
}
}
using System.Collections.Generic;
using Godot;
public partial class StateMachine : Node
{
private Godot.Collections.Dictionary<string, State> _statesMap = new();
private State _currentState;
public string CurrentState => _currentState.Name;
private Stack<string> _statesStack;
private bool _initialized;
public StateMachine()
{
_statesStack = new Stack<string>();
}
public override void _PhysicsProcess(double delta)
{
_currentState?.PhysicsUpdate(this, delta);
}
public override void _Process(double delta)
{
_currentState?.Update(this, delta);
}
public override void _Input(InputEvent @event)
{
_currentState?.HandleInput(this, @event);
}
public override void _UnhandledInput(InputEvent @event)
{
_currentState?.UnhandledInput(this, @event);
}
public void ChangeState(State state, bool stacked = false)
{
ChangeState(state.Name, stacked);
}
public void ChangeState(string stateName, bool stacked = false)
{
if (_statesStack.Count > 0 && !stacked)
{
_statesStack.Pop();
}
if (stateName != "__previous__")
{
_statesStack.Push(stateName);
}
// Get the state object
var newState = States(_statesStack.Peek());
// Call exit on current state
_currentState?.Exit(this);
// Call enter on new state
if (stateName != "__previous__")
{
newState.Enter(this);
}
// Set current state on new state
_currentState = newState;
}
private State States(string stateName)
{
return _statesMap[stateName];
}
public override void _Ready()
{
foreach (Node node in GetChildren())
{
var state = node as State;
if (state == null)
{
continue;
}
_statesMap[node.Name] = state;
state.Finished += OnStateChanged;
state.Stack += OnStateStacked;
}
_initialized = true;
}
public override void _ExitTree()
{
_currentState?.Exit(this);
foreach (var state in _statesMap.Values)
{
state.Finished -= OnStateChanged;
state.Stack -= OnStateStacked;
}
}
// Signals
public void OnStateChanged(string nextState)
{
ChangeState(nextState);
}
public void OnStateStacked(string nextState)
{
ChangeState(nextState, stacked: true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment