- Home /
Stop everything on first error + state machine
Let me explain, I have a FSM called "GameStates" which basically sets up a bunch of things and then switches to the correct state. I also have many scripts which rely on it, for example, the state machine sends a message to my Managers class, which in turn caches everything I need and then tells the state machine when it's done, and the state machine moves on.
All the scripts that rely on it are caching their own things on start, by accessing my Managers class and getting its components/cached scripts and objects.
But what I am currently doing in all these scripts is this, which I don't like much:
private Transform player;
private Camera playerCam;
void Start ()
{
if( !GameStates.initDone )
{
Debug.LogWarning("Initialization failed! Disabling " + this);
this.enabled = false;
return;
}
else
{
// Do what I need
player = Managers.PC.transform;
playerCam = Managers.Cameras.PlayerCam;
etc...
}
}
This works fine, but I hate having to add the check for successful initialization in every scripts that depend on it.
Is there another way I can 'stop' everything from only one main class, like my GameStates class? I'm not sure I'm doing this very efficiently, and it can also introduce a lot more user errors then if only one script took care of stopping everything that needs to be stopped.
Any suggestion is greatly appreciated as always, thanks for your time guys!
Stephane
Could your state machine not call an initialization method in each object it manages and then you'd put your Start() code in there ins$$anonymous$$d?
Or perhaps this is more of a subscription model. In that case you could define an public static event in the state machine class and subscribe to it.
$$anonymous$$y state machines work rather like this second - I have a class called StatefulBehaviour which is derived from $$anonymous$$onoBehaviour and does all of the event subscription stuff - then it sends an Initialized() message. All of my classes that rely on this then derive from StatefulBehaviour rather than $$anonymous$$onoBehaviour.
Why not broadcast a message to everything from your FS$$anonymous$$?
whydoidoit, thanks for the suggestion. When you talk about a subscription model, and subscribing to a public static event, what do you mean exactly? Could you give a small example? I use events in some of my scripts, but nothing fancy yet...
asafsitner, I like your idea as well, I already do this for my $$anonymous$$anagers class so I might as well try and do it for other classes as well.
Thanks for your help guys!
Answer by whydoidoit · May 17, 2012 at 11:42 AM
So you have two choices listed here, by far the simplest is to take asafsitner's BroadcastMessage concept when your initialisation is complete. This is a slow method, but you don't really care as this happens only once. The event model is fast and works well if you need components to react to changes in your state machine on a regular basis.
Unity doesn't have a "root" scene object, so it turns out that you should probably use a loop and SendMessage something like this:
Add Linq to your usings:
using Systen.Linq;
The when you've initialized
foreach(var go in GameObject.FindObjectsOfType(typeof(GameObject))
.Cast<GameObject>())
{
go.SendMessage("StateMachineInitialized",
null, SendMessageOptions.DontRequireReceiver);
}
In each object you can now optionally add a void StateMachineInitialized() method to do what you need to do on initialization, like enabling things.
If you wanted to use events then to your state machine you would add some event definitions, in this case Initialized. I'm guess you have one master statemachine, if you had multiple this would be more tricky.
public class SomeStateMachine
{
public static event Action Initialized = delegate {};
void Start()
{
// Some kind of initialization
Initialized();
}
}
Your other objects subscribe to this event:
public class SomeOtherBehaviour : MonoBehaviour
{
void Awake()
{
SomeStateMachine.Initialized += MethodCalledAfterInitialization;
}
void MethodCalledAfterInitialization()
{
// enable or whatever
SomeStateMachine.Initialized -= MethodCalledAfterInitialization;
}
}
You could have events for states changing etc.
$$anonymous$$ike, thanks a lot for the examples above, they are very helpful and exactly what I needed to see in order to understand both options!
One quick question though, I'm using "CSharp$$anonymous$$essenger Extended" from the wiki for all my events and broadcasts, and from the looks of it and how you use it, it already does subscribing to events internally...is this correct or am I completely wrong?
Either way, I like option 2 better, so I'm gonna try it out :)
Thanks for your help!
After looking into it a little more, i found out that the "CSharp$$anonymous$$essenger Extended" event system does use a subscription model for all its events so it works out great, just like solution 2 above.
Thanks for the help guys!