Okay, so this is how you would build the bare bones state machine… This wont fix your problem at hand, that s for the bin. Instead , take this and build your old needs into the way this is pipelined.
Firstly, you will need a good folder structure as we going to utilize namespaces (our own)
So, folder structure like this please…
Inside your Assets windows in Unity 3D make a folder and name it…“Code”, inside the “Code” folder make a directory of other folders named “Interfaces” “Scripts” “States”.
at this point you are good to go.
in your “Interfaces” folder create a new C# script, name it “IStateBase” (I for Interface).
in that script place this code…
using System;
namespace Assets.Code.Interfaces
{
public interface IStateBase
{
//Interface implementable methods
//base declarations should be placed here to derive out to classes inheriting form IStateBase
void StateUpdate();
}
}
Save that.
Now in your “Scripts” folder create a new C# script and name it “StateManager” or something like that, keeping it obvious is best.
in there paste this code below…
using UnityEngine;
// inherit state classes
using Assets.Code.States;
//inherit interface class
using Assets.Code.Interfaces;
public class StateManager : MonoBehaviour
{
//declare a private state class to cache and work on inside script , taken from the namespace declared at the top
private IStateBase iActiveState; //activeState is reference to BeginState class
private static StateManager instanceRef;
// Use this for initialization
void Start ()
{
//instantiate activeState object for use
iActiveState = new BeginState(this);
//Debug.Log ("This is an object of type: " + activeState);
}
// Update is called once per frame
void Update ()
{
if(iActiveState != null)
{
iActiveState.StateUpdate();
}
}
//publically available method to execute that will return a new state when executed
public void SwitchState(IStateBase newState)
{
iActiveState = newState;
}
}
Save that!
Now, in your States folder, make some derived state classes, starting with this one. I named it BeginState, you can name it what you like but keeping these obvious works best really.
using UnityEngine;
using Assets.Code.Interfaces;
using Assets.Code;
namespace Assets.Code.States
{
public class BeginState : IStateBase
{
//declare a statemanger class
private StateManager stateManager;
private float futureTime = 0.0f;
private int countdown = 0;
private float screenDuration = 8.0f;
//private static GUIHelper guiHelper;
public BeginState(StateManager stateManagerRef) //constructor
{
//assign the argument delivered through stateManagerRef to the private instance of our StateManager class
stateManager = stateManagerRef;
//check we are in the start scene
if(Application.loadedLevelName != "Scene0")
{
Application.LoadLevel ("Scene0");
}
//assign futureTime the value derived from adding screenDuration to Unity`s Time.realtime variable
futureTime = screenDuration + Time.realtimeSinceStartup;
Debug.Log ("constructing BeginState");
}
//implementable methods declared in IStateBase and must be declared in any class using the IStateBase class
//this simply means anything in IStateBase must be carried over to the class implementing it.
//this is why it must be a base class that has derived IStates so we can deal with specific things set up form there
public void StateUpdate()
{
//cache the value of this exact moment in time
float asOfNow = Time.realtimeSinceStartup;
//countdown
countdown = (int)futureTime - (int)asOfNow;
//timing above here
//input conditional
if(Input.GetKeyUp (KeyCode.Space) || countdown <= 0)
{
SwitchOver();
}
//just test if countdown is running in console - non-important code
if(Input.GetKeyUp(KeyCode.F))
{
Debug.Log (countdown.ToString());
}
}
/// <summary>
/// this on GUI method could be implemented through the interface IStateBase, as long as an OnGUI methood in the statemanager class called the replacement method that covers GUI in the Interface class
/// </summary>
void OnGUI()
{
//GUI.BeginGroup(new Rect(guiHelper.FullSizeRect));
if(GUI.Button(new Rect(10, 10, 500, 100), " Assign a Game Scene to this button"))
{
SwitchOver ();
}
//show a countdown timer display
GUI.Box (new Rect(Screen.width / 2, 10, 150, 100), countdown.ToString());
//GUI.EndGroup();
}
/// <summary>
/// SwitchOver method made to change state level or scene. (could be another way to implement this? (IStateBase derived maybe or maybe not?))
/// </summary>
void SwitchOver()
{
//Application.LoadLevel ("Scene1");
//Debug.Log (Application.isLoadingLevel + Application.loadedLevelName);
stateManager.SwitchState (new PlayState(stateManager));
}
}
}
Save that!
In your “States” folder make another C# state class, i`m calling this PlayState as the class names are becoming important for state transactions in the code (as can be seen in the above SwitchOver method code)…anyway.
paste the below in to your PlayState class…
using UnityEngine;
using Assets.Code.Interfaces;
namespace Assets.Code.States
{
public class PlayState : IStateBase
{
//declare a statemanger class
private StateManager stateManager;
public PlayState(StateManager stateManagerRef) //constructor
{
//assign the argument delivered through stateManagerRef to the private instance of our StateManager class
stateManager = stateManagerRef;
Debug.Log ("constructing PlayState");
}
//implementable methods declared in IStateBase and must be declared in any class using the IStateBase class
//this simply means anything in IStateBase must be carried over to the class implementing it.
//this is why it must be a base class that has derived IStates that specifically deal with specific things
public void StateUpdate()
{
//if spacebar hit, switch state (same for all IStateBase state classes)
if(Input.GetKeyUp (KeyCode.Space))
{
stateManager.SwitchState (new WonState(stateManager));
}
}
}
}
Save That !
Here is another state, but by now, and with your own knowledge of staet machines , you shold be able to see that all im doing is what you did in your state machine, except I have taken the leg work out a single operation and given a set of classes some commonly implementable methods to handle the data (well one method in this demonstrative case to show that you can do this, I cant write the whole thing for you im afraid, I dont know what you are trying to make lol)
Anyway, the other demo state class…
using UnityEngine;
using Assets.Code.Interfaces;
namespace Assets.Code.States
{
public class WonState : IStateBase
{
//declare a statemanger class
private StateManager stateManager;
public WonState(StateManager stateManagerRef) //constructor
{
//assign the argument delivered through stateManagerRef to the private instance of our StateManager class
stateManager = stateManagerRef;
Debug.Log ("constructing WonState");
}
//implementable methods declared in IStateBase and must be declared in any class using the IStateBase class
//this simply means anything in IStateBase must be carried over to the class implementing it.
//this is why it must be a base class that has derived IStates that specifically deal with specific things
public void StateUpdate()
{
if(Input.GetKeyUp (KeyCode.Space))
{
stateManager.SwitchState (new BeginState(stateManager));
}
}
void OnGUI()
{
if(GUI.Button(new Rect(Screen.width / 2, Screen.height / 2, 150, 100), "Press Me"))
{
//Debug.Log (Application.isLoadingLevel)
//Debug.Log (Application.loadedLevelName.ToString());
stateManager.SwitchState (new BeginState(stateManager));
}
}
}
}
Anyhoo, the bottomline to all this, is…
If you do Not know how to implement a state machine like this, you will undoubtedly come up against issue that reflect its initial planning. These are not super complicated, but do require a slightly different approach to using Unity (You might notice that for the most we are actually running classes outside of MonoBehaviour, where StateManager is handling the pipeline to MonoBehaviour after the classes have executed)
So, I hope this has helped you in some way. Your other options are delegates and the way you have tried already but, if you can get your head round what i`ve laid out here (and im happy to keep conversing about it), you cant go far wrong and should easily see how you can transfer your current state system to this optimized and scalable solution.
take care bud and thanks for reading this long winded Answer.
Gruffy 
P.S.
to se this work you would need to make two scenes and names them “Scene0” and “Scene1” repspectively.
You would also have an empty gameobject in “Scene0” with the “StateManager” script attached to it.
Run in Editor when “Scene0” is the active scene in the Unity Editor.
I don't quite get it. If you want to have multiple workers on the same file, versioning systems like svn or mercurial should do the trick. If you want each state to have its own script, you can make vital variables of the main class public (I don't recall c# having friend classes) and make a new script for each state. Then, on each state, you just call the specific script's "doStuff()" method. Might use inheritance to make life easier. One point to note: will each script be a MonoBehaviour or a normal class? It's a tricky question =)
– KirlimI've written a pretty good answer. Just waiting for it to be approved by a moderator :)
– Jeremy_Hindle@Misaacs The code you showed somewhat remembers me about the objects for states pattern (http://en.wikipedia.org/wiki/State_pattern). It can reduce the size of the swicth statement, but I don't know if it is worth the extra complexity.
– Kirlim