Unitygems is for the time being pending as to reopen or not. Owner of the domain name promissed he would take care of it but seems to be busy with personal matters. (I am one of the admin but was not taking care of the domain).
You can get it from the provided link in the other answer (the videos should still be on Youtube), there is also someone on Facebook claiming to have the tutorial on his HD, so you can ask nicely,
Finally, I have my own version of a StateMachine available:
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateMachine : MonoBehaviour {
public event Action<object, string, string> OnStateTransition =
(object behaviour, string oldState, string newState) => { };
class State {
public string name;
public List<string> transitions;
public bool allowAnyTransition;
public Action updateMethod = ()=>{};
public Action<string> enterMethod = (string oldState) => { };
public Action<string> exitMethod = (string oldState) => { };
public State(string name) {
this.name = name;
this.allowAnyTransition = false;
this.transitions = new List<string>();
}
}
private Dictionary<string, State> states;
private State currentState = null;
private bool inTransition = false;
private bool initialized = false;
private bool debugTransitions;
private Action OnUpdate = () => { };
public string CurrentState {
get { return currentState.name; }
}
protected void Initialize( bool debug ) {
if (initialized) {
Debug.LogWarning( GetType().ToString() + " is trying to initialize statefulness multiple times." );
return;
}
this.states = new Dictionary<string, State>();
this.AddState( "InitialState" );
State initial = states["InitialState"];
initial.allowAnyTransition = true;
currentState = initial;
inTransition = false;
transitionSource = null;
transitionTarget = null;
initialized = true;
debugTransitions = debug;
}
protected bool IsLegalTransition(string sourceState, string nextState) {
if (states.ContainsKey(sourceState) && states.ContainsKey(nextState)) {
if (states[sourceState].allowAnyTransition || states[sourceState].transitions.Contains(nextState)) {
return true;
}
}
return false;
}
private void TransitionTo(string nextState) {
transitionSource = currentState;
transitionTarget = states[nextState];
inTransition = true;
currentState.exitMethod(transitionTarget.name);
transitionTarget.enterMethod(currentState.name);
currentState = transitionTarget;
}
private void FinalizeCurrentTransition() {
if (transitionTarget == null || transitionSource == null){
Debug.LogError(this.GetType().ToString() + " cannot finalize transition; source or target state is null!");
return;
}
OnStateTransition( this, transitionSource.name, transitionTarget.name );
inTransition = false;
transitionSource = null;
transitionTarget = null;
}
protected bool RequestState(string newstate) {
if (!initialized) {
Debug.LogError( this.GetType().ToString()+ " requests transition to state " + newstate + " but statefulness is not initialized!");
return false;
}
if (inTransition) {
if (debugTransitions)
Debug.Log(this.GetType().ToString() + " requests transition to state " + newstate +
" when still transitioning to state " + transitionTarget.name);
return false;
}
if( IsLegalTransition( currentState.name, newstate )) {
if (debugTransitions) {
Debug.Log( this.GetType().ToString() + " transition: " + currentState.name + " => " + newstate );
}
TransitionTo(newstate);
FinalizeCurrentTransition();
} else {
Debug.LogError( this.GetType().ToString() + " requests transition: " + currentState.name + " => " + newstate + " but it is not a legal transition!" );
return false;
}
OnUpdate = null;
OnUpdate = currentState.updateMethod;
return true;
}
protected void DeclareState(string newstate) {
State s = new State( newstate );
System.Type ourType = this.GetType();
MethodInfo update = ourType.GetMethod("Update" + newstate, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
MethodInfo enter = ourType.GetMethod("Enter" + newstate, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
MethodInfo exit = ourType.GetMethod("Exit" + newstate, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (update != null) {
s.updateMethod = (Action)Delegate.CreateDelegate(typeof(Action), this, update);
}
if (enter != null){
s.enterMethod = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), this,enter);
}
if (exit != null){
s.exitMethod = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), this, exit);
}
this.states.Add( newstate, s );
}
protected void DeclareStateWithTransitions(string newstate, string[] transitions) {
AddState(newstate);
State s = states[newstate];
foreach (string t in transitions) {
s.transitions.Add( t );
}
}
protected virtual void StateUpdate() {
OnUpdate();
}
}
You use it like this:
public class Controller:StateMachine
{
void Awake(){
Initialize(true); // false if you don’t want the debug
// The first parameter declares the state,
// the array of string declares the legal transitions from that state
// Idle can get to Walk and Die, Die can only move to Idle
// Requesting from Die to Walk would print an error and would be discarded
DeclareStateWithTransitions("Idle", new string[]{"Walk, Die"});
DeclareStateWithTransitions("Walk", new string[]{"Idle, Die"});
DeclareStateWithTransitions("Die", new string[]{"Idle"});
RequestState("Idle");
}
void EnterIdle(string previous){
Debug.Log("Entering Idle state");
}
void UpdateIdle(){
Debug.Log("Idle update");
if(specialCondition)
RequestState("Walk");
}
void ExitIdle(string previous){
Debug.Log("Exit idle");
}
// Same for other states, only add method if you need it
void Update(){
// StateUpdate is needed to run the update of each state
StateUpdate();
// Rest of the Update code
}
}
This state machine does not allow to change state while in a transition, that is if you are changing state from Idle to Walk and in the same frame, you are about to die, it won’t do, I am thinking of fixing since when I have time, maybe someone wants to work it out and improve it for some wiki state machine.
Shoot if you have any questions.