This repository has been archived by the owner on Feb 13, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 207
/
SuperStateMachine.cs
127 lines (104 loc) · 3.72 KB
/
SuperStateMachine.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// With a little help from UnityGems
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// State machine model that recieves SuperUpdate messages from the SuperCharacterController
/// </summary>
public class SuperStateMachine : MonoBehaviour {
protected float timeEnteredState;
public class State
{
public Action DoSuperUpdate = DoNothing;
public Action enterState = DoNothing;
public Action exitState = DoNothing;
public Enum currentState;
}
public State state = new State();
public Enum currentState
{
get
{
return state.currentState;
}
set
{
if (state.currentState == value)
return;
ChangingState();
state.currentState = value;
ConfigureCurrentState();
}
}
[HideInInspector]
public Enum lastState;
void ChangingState()
{
lastState = state.currentState;
timeEnteredState = Time.time;
}
/// <summary>
/// Runs the exit method for the previous state. Updates all method delegates to the new
/// state, and then runs the enter method for the new state.
/// </summary>
void ConfigureCurrentState()
{
if (state.exitState != null)
{
state.exitState();
}
//Now we need to configure all of the methods
state.DoSuperUpdate = ConfigureDelegate<Action>("SuperUpdate", DoNothing);
state.enterState = ConfigureDelegate<Action>("EnterState", DoNothing);
state.exitState = ConfigureDelegate<Action>("ExitState", DoNothing);
if (state.enterState != null)
{
state.enterState();
}
}
Dictionary<Enum, Dictionary<string, Delegate>> _cache = new Dictionary<Enum, Dictionary<string, Delegate>>();
/// <summary>
/// Retrieves the specific state method for the provided method root.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="methodRoot">Based method name that is appended to the state name by an underscore, in the form of X_methodRoot where X is a state name</param>
/// <param name="Default"></param>
/// <returns>The state specific method as a delegate or Default if it does not exist</returns>
T ConfigureDelegate<T>(string methodRoot, T Default) where T : class
{
Dictionary<string, Delegate> lookup;
if (!_cache.TryGetValue(state.currentState, out lookup))
{
_cache[state.currentState] = lookup = new Dictionary<string, Delegate>();
}
Delegate returnValue;
if (!lookup.TryGetValue(methodRoot, out returnValue))
{
var mtd = GetType().GetMethod(state.currentState.ToString() + "_" + methodRoot, System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod);
if (mtd != null)
{
returnValue = Delegate.CreateDelegate(typeof(T), this, mtd);
}
else
{
returnValue = Default as Delegate;
}
lookup[methodRoot] = returnValue;
}
return returnValue as T;
}
/// <summary>
/// Message callback from the SuperCharacterController that runs the state specific update between global updates
/// </summary>
void SuperUpdate()
{
EarlyGlobalSuperUpdate();
state.DoSuperUpdate();
LateGlobalSuperUpdate();
}
protected virtual void EarlyGlobalSuperUpdate() { }
protected virtual void LateGlobalSuperUpdate() { }
static void DoNothing() { }
}