x


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

more ▼

asked May 16 '12 at 07:00 AM

ronronmx gravatar image

ronronmx
806 84 99 121

Could your state machine not call an initialization method in each object it manages and then you'd put your Start() code in there instead?

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.

My state machines work rather like this second - I have a class called StatefulBehaviour which is derived from MonoBehaviour 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 MonoBehaviour.

May 16 '12 at 07:53 AM whydoidoit

Why not broadcast a message to everything from your FSM?

May 16 '12 at 10:32 AM asafsitner

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 Managers class so I might as well try and do it for other classes as well.

Thanks for your help guys!

May 17 '12 at 06:52 AM ronronmx
(comments are locked)
10|3000 characters needed characters left

1 answer: sort voted first

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.

more ▼

answered May 17 '12 at 11:42 AM

whydoidoit gravatar image

whydoidoit
33k 11 23 100

Mike, 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 "CSharpMessenger 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!

May 17 '12 at 05:06 PM ronronmx

After looking into it a little more, i found out that the "CSharpMessenger 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!

May 18 '12 at 05:03 PM ronronmx
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x5072
x239
x40
x27
x21

asked: May 16 '12 at 07:00 AM

Seen: 545 times

Last Updated: May 18 '12 at 05:03 PM