Search Unity

Handling Too Many Game States

Discussion in 'Scripting' started by faultymoose, Jun 4, 2011.

  1. faultymoose

    faultymoose

    Joined:
    Oct 1, 2010
    Posts:
    246
    I'm after some conceptual assistance.

    The problem:

    I have a sequence of actions which occur in a turn-based game. A common 'round' might be something like:

    1. Ask the player to PRESS A to move
    2. Wait for the player to select a target location
    3. Move the avatar to the target location
    4. Display a short "You have reached your destination" type message
    5. Wait for the player to PRESS A to continue
    6. Move to the next player and repeat

    The individual logistics of each task don't give me any trouble, but the overall conceptual framework for structuring this code, does.

    I have a GameManager singleton which tracks pretty much everything, and I would like to keep most of the gameplay-type stuff encapsulated here, with individual units and such just data containers. Unless someone proposed an alternative, of course.

    At the moment, I'm pretty much 'brute forcing' the solution:

    switch (m_gameState)
    {
    case GameState.WaitForA:
    ...
    case GameState.WaitForTargetSelect:
    ...
    case GameState.MoveAvatarToLocation:
    ...
    case GameState.WaitForAAgain:
    ...
    case GameState.SelectNextPlayer:
    ...
    }

    In a short example like this, it's not that bad. But when I start introducing potentially repetetive and overlapping 'game states', such as the option to Pause at any time, or frequent requests to Press A To Continue, the need to wait for animations to finish, etc., it turns into spaghetti in my head and I end up staring at my screen for 20 minutes without typing anything.

    I guess what I'm asking is: How would you recommend I manage my states? How should I divide them up into multiple, layered states? Should I make some super cool use of coroutines (just discovered them, love them to bits) to manage this? Does anyone have any in-depth game state examples they wouldn't mind sharing?

    I'd love any anecdotal advice that could be offered.

    Thanks for any help, it's appreciated.
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I guess that's all in Update? Coroutines would simplify things massively. Your list could be written like:

    Code (csharp):
    1. function GameLoop () {
    2.     while (true) {
    3.         for (i = 0; i < numberOfPlayers; i++) {
    4.             yield WaitForAButton();
    5.             yield PlayerSelectTargetLocation (i);
    6.             yield PlayerMove (player[i].position, target[i].position);
    7.             DisplayMessage ("You have reached your destination");
    8.             yield WaitForAButton();
    9.         }  
    10.     }  
    11. }
    --Eric
     
  3. faultymoose

    faultymoose

    Joined:
    Oct 1, 2010
    Posts:
    246
    Awesome, thanks for the fast reply! I'll need to do some more reading on Coroutines to understand how they work. At the moment I've got a problem I'm trying to solve myself, but I can't see what I've done wrong compared to examples:

    I have the following method. It is called once with StartCoroutine(GameLoop()). Every Debug.Log() prints as expected to the console:

    Code (csharp):
    1.  
    2.     private IEnumerator             GameLoop()
    3.     {
    4.         Debug.Log("GameLoop started!");
    5.         Debug.Log("Player count = " + PlayerCount);
    6.        
    7.         for(int i = 0; i < PlayerCount; i++)
    8.         {
    9.             Debug.Log("Calling MainCamera.Instance.MoveToTarget(" + m_players[i] + ", 2.0f)");
    10.             yield return MainCamera.Instance.MoveToTarget(m_players[i], 2.0f);
    11.         }
    12.     }
    13.  
    However, the very first Debug.Log() in this code does not print to console (this method is located in the MainCamera monobehaviour).

    Code (csharp):
    1.  
    2.     // Move the camera to the specified player's position.
    3.     public IEnumerator              MoveToTarget(Player player, float duration)
    4.     {
    5.         Debug.Log("MoveToTarget() called...");
    6.        
    7.         Vector3 srceLoc = transform.position;
    8.         Vector3 destLoc = player.transform.position;
    9.        
    10.         if (duration <= 0.0f)
    11.             duration = 0.0f;
    12.            
    13.         bool repeat = true;
    14.         float transition = 0.0f;
    15.        
    16.         while (repeat)
    17.         {
    18.             if (transition >= 1.0f)
    19.             {
    20.                 repeat = false;
    21.                 transition = 1.0f;
    22.             }
    23.            
    24.             transform.position = Vector3.Slerp(srceLoc, destLoc, transition);
    25.             transition += (1.0f / duration) * Time.deltaTime;
    26.            
    27.             yield return 0;
    28.         }
    29.     }
    30.  
    I can't see why the code isn't executing correctly. I'm expecting it's something very simple that eludes me.
     
  4. NomadKing

    NomadKing

    Joined:
    Feb 11, 2010
    Posts:
    1,461
    Does the rest of the code execute apart from the Debug line at the top of it?
     
  5. arzi

    arzi

    Joined:
    Apr 6, 2009
    Posts:
    154
    You'll need to execute the subsequent Coroutines with StartCoroutine too:

    Code (csharp):
    1.  
    2. yield return MainCamera.Instance.StartCoroutine(MoveToTarget(m_players[i], 2.0f));
    3.  
     
  6. faultymoose

    faultymoose

    Joined:
    Oct 1, 2010
    Posts:
    246
    Ah! Thankyou arzi, that fixed the problem!