Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,56 +33,83 @@ public class MyGameplayScript : MonoBehaviour
Init,
Play,
Win,
Lose
Lose,
Total // Last state, needed to inherit other states
}

StateMachine<States> fsm;
protected StateMachine fsm;

void Awake(){
fsm = new StateMachine<States>(this); //2. The main bit of "magic".

protected void Awake(){
fsm = new StateMachine(this); //2. The main bit of "magic".
fsm.AddStates<States>(); //2a. Load the states
fsm.ChangeState(States.Init); //3. Easily trigger state transitions
}

void Init_Enter()
protected virtual void Init_Enter() // protected and virtual to allow overriding
{
Debug.Log("Ready");
}

void Play_Enter()
protected virtual void Play_Enter()
{
Debug.Log("Spawning Player");
}

void Play_FixedUpdate()
protected virtual void Play_FixedUpdate()
{
Debug.Log("Doing Physics stuff");
}

void Play_Update()
protected virtual void Play_Update()
{
if(player.health <= 0)
{
fsm.ChangeState(States.Lose); //3. Easily trigger state transitions
}
}

void Play_Exit()
protected virtual void Play_Exit()
{
Debug.Log("Despawning Player");
}

void Win_Enter()
protected virtual void Win_Enter()
{
Debug.Log("Game Over - you won!");
}

void Lose_Enter()
protected virtual void Lose_Enter()
{
Debug.Log("Game Over - you lost!");
}

}

public class ChildTest : MyGameplayScript{
public enum ChildStates
{
First = MyGameplayScript.States.Total,// Extend parent states
Die,
Total // Last state, needed to inherit other states
}

override protected void Awake(){
base.Awake(); // Initialize fsm

fsm.AddStates<ChildStates>(); //Load the extended states
//fsm.ChangeState(ChildStates.Die); //Optionally change state
}

protected virtual void Die_Enter()
{
Debug.Log("You died!");
}

override protected void Win_Enter()
{
Debug.Log("The child won!");
}
}
```

### State Methods are defined by underscore convention ( `StateName_Method` )
Expand Down Expand Up @@ -138,10 +165,11 @@ public class Driver
This is a very simple class. It doesn't have to be called `Driver`; the only constraint is that it must contain `StateEvent` fields. When we pass this to our state machine definition, it will take care of everything needed to set up new State event hooks.

```C#
StateMachine<States, Driver> fsm;
StateMachine<Driver> fsm;

void Awake(){
fsm = new StateMachine<States, Driver>(this);
fsm = new StateMachine<Driver>(this);
fsm.AddStates<States>();
}

void Play_Enter()
Expand Down
99 changes: 49 additions & 50 deletions StateMachine/Assets/MonsterLove/Runtime/Events/StateEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,107 +26,106 @@
// Warning!
// This is somewhat fragile Event pattern implementation. Recommended they aren't used outside of the state machine
//
namespace MonsterLove.StateMachine
{
public class StateEvent
{
namespace MonsterLove.StateMachine {
public class StateEvent {
private Func<int> getStateInt;
private Func<bool> isInvokeAllowed;
private Action[] routingTable;
private List<Action> routingTable;

public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
{
public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider) {
this.isInvokeAllowed = isInvokeAllowed;
this.getStateInt = stateProvider;
routingTable = new Action[capacity];
routingTable = new List<Action>(0);
}

internal void AddListener(int stateInt, Action listener)
{

internal void AddListener(int stateInt, Action listener) {
routingTable[stateInt] = listener;
}

public void Invoke()
{
if (isInvokeAllowed != null && !isInvokeAllowed())
{
public void Invoke() {
if(isInvokeAllowed != null && !isInvokeAllowed()) {
return;
}

Action call = routingTable[getStateInt()];
if (call != null)
{
if(call != null) {
call();
return;
}
}

private void GrowToFill() {
while(routingTable.Count < routingTable.Capacity) {
routingTable.Add(null);
}
}
}

public class StateEvent<T>
{

public class StateEvent<T> {
private Func<int> getStateInt;
private Func<bool> isInvokeAllowed;
private Action<T>[] routingTable;

public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
{
private List<Action<T>> routingTable;

public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider) {
this.isInvokeAllowed = isInvokeAllowed;
this.getStateInt = stateProvider;
routingTable = new Action<T>[capacity];
routingTable = new List<Action<T>>(0);
}

internal void AddListener(int stateInt, Action<T> listener)
{
internal void AddListener(int stateInt, Action<T> listener) {
routingTable[stateInt] = listener;
}

public void Invoke(T param)
{
if (isInvokeAllowed != null && !isInvokeAllowed())
{
public void Invoke(T param) {
if(isInvokeAllowed != null && !isInvokeAllowed()) {
return;
}

Action<T> call = routingTable[getStateInt()];
if (call != null)
{
if(call != null) {
call(param);
return;
}
}

private void GrowToFill() {
while(routingTable.Count < routingTable.Capacity) {
routingTable.Add(null);
}
}
}

public class StateEvent<T1, T2>
{

public class StateEvent<T1, T2> {
private Func<int> getStateInt;
private Func<bool> isInvokeAllowed;
private Action<T1,T2>[] routingTable;

public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
{
private List<Action<T1, T2>> routingTable;

public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider) {
this.isInvokeAllowed = isInvokeAllowed;
this.getStateInt = stateProvider;
routingTable = new Action<T1, T2>[capacity];
routingTable = new List<Action<T1, T2>>(0);
}

internal void AddListener(int stateInt, Action<T1, T2> listener)
{
internal void AddListener(int stateInt, Action<T1, T2> listener) {
routingTable[stateInt] = listener;
}

public void Invoke(T1 param1, T2 param2)
{
if (isInvokeAllowed != null && !isInvokeAllowed())
{
public void Invoke(T1 param1, T2 param2) {
if(isInvokeAllowed != null && !isInvokeAllowed()) {
return;
}

Action<T1, T2> call = routingTable[getStateInt()];
if (call != null)
{
if(call != null) {
call(param1, param2);
return;
}
}

private void GrowToFill() {
while(routingTable.Count < routingTable.Capacity) {
routingTable.Add(null);
}
}
}
}
Loading