StateMachine Component

This commit is contained in:
Matt Thorson 2020-05-26 21:23:46 -07:00
parent aed77272ac
commit be9e1cd877
5 changed files with 171 additions and 36 deletions

View File

@ -0,0 +1,137 @@
using System;
using System.Collections;
namespace Strawberry
{
public class StateMachine<TIndex> : Component where TIndex : struct, IHashable
{
private Dictionary<TIndex, State> states = new Dictionary<TIndex, State>() ~ delete _;
private TIndex state;
private bool inStateCall;
public TIndex PreviousState { get; private set; }
public TIndex NextState { get; private set; }
public this(TIndex startState)
: base(true, false)
{
NextState = PreviousState = state = startState;
}
public ~this()
{
for (let s in states.Values)
delete s;
}
public override void Started()
{
CallEnter();
}
public override void Update()
{
CallUpdate();
}
public override void Draw()
{
}
public void Add(TIndex state, delegate TIndex() enter = null, delegate TIndex() update = null, delegate TIndex() exit = null)
{
let s = new State();
s.Enter = enter;
s.Update = update;
s.Exit = exit;
states[state] = s;
}
public TIndex State
{
get => state;
set => Set(value);
}
private Result<bool> Set(TIndex to)
{
if (inStateCall)
Runtime.FatalError("Cannot set State directly from inside a State Enter/Exit/Update call. Return the desired State change instead.");
if (to != state)
{
NextState = to;
if (CallExit())
return true;
PreviousState = state;
state = to;
CallEnter();
return true;
}
else
return false;
}
private bool CallEnter()
{
let s = states[state];
if (s != null)
{
inStateCall = true;
let set = s.Enter();
inStateCall = false;
return Set(set);
}
else
return false;
}
private bool CallUpdate()
{
let s = states[state];
if (s != null)
{
inStateCall = true;
let set = s.Update();
inStateCall = false;
return Set(set);
}
else
return false;
}
private bool CallExit()
{
let s = states[state];
if (s != null)
{
inStateCall = true;
let set = s.Exit();
inStateCall = false;
return Set(set);
}
else
return false;
}
public class State
{
public delegate TIndex() Enter;
public delegate TIndex() Update;
public delegate TIndex() Exit;
public ~this()
{
if (Enter != null)
delete Enter;
if (Update != null)
delete Update;
if (Exit != null)
delete Exit;
}
}
}
}

View File

@ -24,6 +24,33 @@ namespace Strawberry
RemoveOnComplete = destroyOnComplete;
}
public override void Started()
{
}
public override void Update()
{
if (value > 0)
{
value -= Time.Delta;
if (value <= 0)
{
value = 0;
Active = false;
OnComplete?.Invoke();
if (RemoveOnComplete)
RemoveSelf();
}
}
}
public override void Draw()
{
}
public float Value
{
[Inline]
@ -47,23 +74,6 @@ namespace Strawberry
Active = false;
}
public override void Update()
{
if (value > 0)
{
value -= Time.Delta;
if (value <= 0)
{
value = 0;
Active = false;
OnComplete?.Invoke();
if (RemoveOnComplete)
RemoveSelf();
}
}
}
static public implicit operator bool(Timer timer)
{
return timer.value > 0;

View File

@ -15,30 +15,19 @@ namespace Strawberry
Visible = visible;
}
public void Added(Entity entity)
private void Added(Entity entity)
{
Entity = entity;
}
public void Removed()
private void Removed()
{
Entity = null;
}
public virtual void Started()
{
}
public virtual void Update()
{
}
public virtual void Draw()
{
}
public abstract void Started();
public abstract void Update();
public abstract void Draw();
[Inline]
public void RemoveSelf()

View File

@ -89,7 +89,7 @@ namespace Strawberry
{
components.Remove(c);
Scene.[Friend]UntrackComponent(c);
c.Removed();
c.[Friend]Removed();
delete c;
}
@ -102,7 +102,7 @@ namespace Strawberry
{
components.Add(c);
Scene.[Friend]TrackComponent(c);
c.Added(this);
c.[Friend]Added(this);
}
toAdd.Clear();

View File

@ -39,7 +39,6 @@ namespace Strawberry
public override void Update()
{
base.Update();
MovedByGeometry = Point.Zero;
}