Best practice of handle states and transitions og a level/scene

Hi

I have searched for some time now, to find some sample or discussions about how to handle a problem I’m facing right now. A pretty basic and common problem I would say :slight_smile:

Let’s say I have a scene called Level. This scene were all the 100+ individual levels of my game runs. The way I load in different levels etc. isn’t really interesting here, let’s just say I have that part in place.

My problem is that I have a hard time figuring out how to handle all the transitions and states of a level in a simple and maintainable way.
If you think about a game like Candy Crush for instance, their “level” goes like this:

  • Show of a background
  • The gameboard slides in
  • A lille guy comes down from the top, telling you a brief description of what this particual level is about.
  • You touch the guy and he goes away away, in an smooth animation moving up
  • Game runs
  • You might die and a new thing slides down from the top.
  • etc.

And all of these things are happening over time, which is kind of the problem.

I have a “working solution” now, the game works, but it’s way to complicated codewise, and way to hard to figure out - which isn’t what I want. I want something more clean.

I am doing something like this, which you can see becomes impossible to overcome very quickly.

So my question is really, how to you guys handle this. Can you point to a resource with a good sample or anything else?

NGUITools.SetActive (PrePlayPanel.gameObject, true);
        PrePlayTween.PlayForward ();
        Invoke ("BeginStartLevel", 10.0f);
public void BeginStartLevel()
    {
        if(State == LevelStates.PrePlaying)
        {
            EventDelegate.Add (PrePlayTween.onFinished, StartLevel);
            PrePlayTween.PlayReverse ();
        }
    }
private void StartLevel()
    {
        EventDelegate.Remove (PrePlayTween.onFinished, StartLevel);
        NGUITools.SetActive (PrePlayPanel.gameObject, false);
        State = LevelStates.Playing;
        _currentGameManager.StartLevel (); 
    }

I found something myself, that seems to do the job. Have played with it for some hours, and this is really making things easier for me. Much cleaner code now in my game :slight_smile:

https://github.com/thefuntastic/Unity3d-Finite-State-Machine

1 Like

Glad you found a solution.

In general, in all development the way to approach things is to simply break complex sequences down into smaller parts.

For example, you identified parts of the Candy Crush game sequence:

Basically these are nothing more than the current level state.

Imagine if you declared a simple enumeration and a variable of this type:

public enum LevelStateType
{
    Inactive,
    ShowBackground,
    SlideGameboardIn,
    LittleDudeAppearsFromTop,
    LittleDudeIntroducesLevel,
    LittleDudeWasSentAway,
    LevelStarting,
    LevelBeingPlayed,
    LevelCurrentlyPaused
}

private LevelStateType eLevelCurrentState = Inactive;

In your code all you need to do is move from each step (state) to the next.
At its simplest implementation, you basically have a Level GameObject perhaps even a LevelManager.

The enum goes in there.

In the update you simply have something like this:

void Update()
{
    switch (eLevelCurrentState)
    {
        case LevelStateType.Inactive:
            // probably simply waits until some condition occurs to transition to ShowBackground
            // and this may not even be needed but it gives you something "default" to set the initial state to.
            HandleInactiveState();
            break;

        case LevelStateType.ShowBackground:
            // loads and displays background maybe fading or sliding it in view
            // when complete state changes to SlideGameboardIn
            HandleShowBackgroundState();
            break;

        case LevelStateType.SlideGameboardIn:
            // slides the game board onto the playfield, when complete state changes to LittleDudeAppearsFromTop
            HandleSlideGameboardInState();
            break;

        case LevelStateType.LittleDudeAppearsFromTop:
            // moves the Little Dude down into view, when complete state changes to LittleDudeIntroducesLevel
            HandleLittleDudeAppearsFromTop();
            break;

        case LevelStateType.LittleDudeIntroducesLevel:
            // Audio/Speech Bubble or both introduce this level, when complete state changes to LittleDudeWasSentAway
            HandleLittleDudeIntroducesLevel();
            break;

        case LevelStateType.LittleDudeWasSentAway:
            // Little Dude slides back up out of sight, when complete state changes to LevelStarting
            HandleLittleDudeWasSentAway();
            break;

        case LevelStateType.LevelStarting:
            // Do any FX etc for a level starting maybe LEVEL ONE BEGIN appears and fades out for example.
            // Probably sets up the game objects needed for the level as well
            // When complete state changes to LevelBeingPlayed
            HandleLevelStarting();
            break;

        case LevelStateType.LevelBeingPlayed:
            // Handles whatever is needed during play, probably just looking for certain conditions such as the
            // level being completed, the level being reset, etc.
            HandleLevelBeingPlayed();
            break;
    }
}

Obviously, this is just a general idea, exact flow from one state to another, and exactly what is going on in each state is entirely up to how you want to implement it.

But yes, you hit the nail on the head when you looked for a state machine manager.

I just figured I would post this in the hope that anyone else who is struggling with this sort of thing can have a better understanding of how to solve the problem.

Always… divide and conquer. Break things down. By doing so you can basically pull off any thing you want to achieve because at any one time you are dealing with only one small part of the problem.

2 Likes

Yeah, a finite state machine is definitely the right way to handle this. I like to set up an invisible game object that handles the FSM for the level. I also like using FSM when implementing AI for NPCs. An FSM is a lot easier to work with than a wildly nested if-then structure. In some AI code, I have actually switched to using nested FSM (with state machines inside of state machines). In some instances, a nested FSM can be a really good way to break down complex AI into smaller more manageable code.

1 Like

Here’s a fun idea that’s horrible in it’s own little way. Take the objects that don’t need to transition and parent them to an empty gameobject named “Level 1” and then make a prefab out of it. Then you can delete the parent and your level 1 will be gone, but in your prefab folder. Next, build your second level. Parent everything in it to an empty named “Level 2” and make a prefab of that. Then instead of scene loading and worrying about stuff like that, you can destroy level 1 and instantiate level 2.

Better yet determine which game objects are not shared between scenes and put those into individual level prefabs. Game objects that will be shared can thus be saved from wasting resources from instantiating and destroying them.

There are a few object pool managers on the Asset Store that can assist with reusing objects too.

Don’t destroy things you need in the next level. That’s what I meant for the most part, but the object pooling is a good idea too :smile:

Picked this one up a while back when it was on sale. Haven’t actually put it to use yet though.

https://www.assetstore.unity3d.com/en/#!/content/1010

I don’t do object pooling often because of how light my games tend to be. I don’t even store references to things much haha. I’ll probably do it more because it’s good practice. Maybe in my next big summer project. Maybe. Probably. I have one game where the “projectile” goes something like…

GameObject.Destroy(GameObject.Instantiate(Resources.Load("blap")), 10);

The game just happens to be small enough for that to work.

Thanks for all your answers.

My problem is not really how to handle the different levels etc. it’s the manage of the different states and the transitions between them that I had a problem with.

But I have looked more into the project I found now, and have refactored my LevelManager to use it, and it works very well. My code it MUCH simpler now and easier to read.

https://github.com/thefuntastic/Unity3d-Finite-State-Machine

This makes it even easier then having to do my own switch in void Update() etc. and still I’m able to provide my own states enum to work on.

1 Like

This is how I uses FSM in my games:

  public enum States
  {
      DISABLED,
      ENABLED,
      ROUND1,
      ROUND2
  }

  private States currentState

  public States CurrentState
  {
      get { return currentState; }
      set
      {
          currentState = value;
          OnStateChange();
      }
  }

void OnStateChange()
{
      Switch()
      {
          case: States.DISABLED:
          OnStateDisable();
       break;
          case: States.ENABLED:
          OnStateDisable();
       break;
       //etc…
      }
}

void OnStateDisable()
{
      //DISABLED!
}

void OnStateEnable()
{
      //ENABLED!
}

//When calling:
//CurrentState = States.ENABLED;
//OnStateEnable() is called instantly, by running through OnStateChange()

@GarBenjamin , I like to avoid having stuff happening in Update(), when I don’t need to… :slight_smile:

Feel free to expand on my method guys… Always curious to hear back and improve!:roll_eyes:

2 Likes

That’s a good iimplementation and yes all of my projects have a SetState() method. I didn’t cover that in my post or how to really do the transition etc. Just wanted to show the basic idea of breaking things down in distinct states.

In practice, there is nothing wrong with implementing the structure as I defined in the update. It is basically just sorting out what the current state is using a switch then calling the appropriate method to handle the current state. I have implemented them a lot this way. Another way I sometimes use is to set up delegates to the state methods then the Update can simply call the method to handle the current state by using the delegate eliminating the need for the switch. I’ve always said there are many ways to do this stuff. Each has pros and cons including some ways connecting more with one person while others better match another person or project. Basically I always favor simplicity. Simpler implementations are easier to debug, extend and otherwise enhance.

Regardless of how implemented… I agree state machines rule. And I also use them for AI. Heck I use them for everything. Even in my little Christmas game project the reindeer has states, the gifts have states, even the snowballs have states.

1 Like

Speaking of the christmas games, I just finished the demo of the one I referred to when referring to your original christmas forum game post :smile: Or rather… the code for the demo is done, just waiting on a friend for the models…

Plug

1 Like

PlayMaker works well if you like FSMs …

I agree there are a bunch of ways to implement a State Machine. Even for simple stuff, FSM are very useful. Once you start thinking that way… everything is much more clear and simple.

@GarBenjamin ,
Regarding your example. The issue I see with using Update(), is your enter state methods (HandleInactiveState(), HandleShowBackgroundState, etc.) will be called on every frame.
How do you counter that?

What you see in the update is just looking at current state to determine which we are in and then calling the appropriate method that handles that state. In those methods, if certain conditions are met the state will be changed to progress through the sequence. So that’s all that code illustrates is figuring out the current state and then calling the method that handles that state. Delegates can be set up for the state methods to call those methods directly eliminating the switch entirely. I used to do that because I was use to that implementation using function pointers in C. Over the years I find I am moving to more and more simplistic code. I think because I spent a lot of time trying things in various ways using the “hot” techniques (aka flavor of the month) and in the end it was just as well had I just wrote 1… 2… 3… instead of 1… dependency injection nmaybe2… functionpointerdelegatehidingpathto3… basically unless I have a good reason to do otherwise I focus on simplicity.

1 Like

@GarBenjamin I like the way you see things. Simplicity is always best. :smile:

1 Like

Yeah I like simplicity. My own style is a combo of many different philosophies such as KISS, IID (Incremental & Iterative Development), RERO (Release Early Release Often) and TMTOWTDI (There’s More Than One Way To Do It). I am sure a few more come into play but I’d say those are my core dev principles.

1 Like

Do not forget: DRY (Don’t Repeat Yourself) :smile:

Does anyone have any experience with Terry Norton’s implementation of state machines from his book: Learning C# by Developing Games with Unity 3D Beginner’s Guide? I thought it looked really cool so I implemented it in my game but I keep running into issues that need workarounds.