Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

GameState stack - modification while enumerating problem

Started by Proudest Dec 7, 2005 at 6:35 AM 9 replies 1.1k views
Original Post
Proudest
Proudest
I'm using the System.Collection.Stack class in C# to represent a stack of game states. I have a StateManager class which loops through and updates each state in the stack. To test it out, I made "WorldMap" and "MainMenu" states. I gave each state a "hasFocus" variable to determine when to get user input. In my update function for the main menu I want it to remove (pop) itself if it has focus and if the enter key was pressed. This would then give focus to the world map. The problem is when I try and pop the main menu, the enumeration process of "foreach" tells me I can't modify the collection while enumerating. Here's the enumeration:

using System.Collections;

class StateManager
{
    Stack states = new Stack();
    
	public void Update()
	{
		foreach (GameState item in states)
		{
			item.Update();
		}
	}
}


Here's my update function:

class MainMenu : GameState
{
	public override void Update()
	{
		if (hasFocus)
		{
			if (Input.Instance.GetKey(Key.BackSpace))
			{
				StateManager.Instance.Pop();
			}
		}
	}
}


I'm not able to modify the stack within the enumeration. How should I implement the control and modification of game states in this situation?
Dave Hunt
Dave Hunt
Ordinarily, you only have one active state, so you would only be updating the current (top-most) state. In that case, you wouldn't need an enumerator for updating. May I ask why you are updating inactive states?

Any changes made to a collection during enumeration will invalidate the enumerator. So there is no way to do what you want using an enumerator/foreach. If you use an ArrayList, you can iterate using an index and that will allow you to modify the list, if needed.
Proudest
Proudest
I guess I should decouple Update() and GetInput(). I want to update "inactive" states because they might need to be updated for animation, etc. For example, imagine if my WorldMap state wasnt being updated while a MessageBox state was pushed on top of it. I would still want the game to be moving in the background, but only the user input would be cut off from it.
Proudest
Proudest
Decoupling input and updates worked, but now I have a new problem. I made two menus, MainMenu and SubMenu. MainMenu creates SubMenu and ideally SubMenu should be drawn on top of MainMenu.

The problem is, I draw each gamestate in order from the top of the stack to the bottom. This results in the submenu being drawn first, and the mainmenu second, so my submenu is behind the mainmenu.

I wonder if I'll have to somehow draw everything in reverse. Maybe I should create a separate ArrayList to hold the same items but in the opposite order and draw from that. Anyone have any ideas on how to solve this?
DrunkenHyena
DrunkenHyena
I think you're going to have problems with how you are handling your states. If you've switched to a Submenu, you shouldn't be updating or drawing your Main Menu at all.

While you're in your Play state, if you need to pop up a messagebox, you haven't really changed state. You're still in Play, just with a messagebox showing. The messagebox should just be a UI component attached to your Play state.
Stay Casual,KenDrunken Hyena</FON
Proudest
Proudest
I could be making my game states too generic, but don't a message box and a real game state do exactly the same thing? They control the flow of the game by defining what is drawn and what input is processed. Technically, they seem too similar to separate.

Regarding the menus; the reason I want to draw both menus is because the sub menu won't be taking up the whole screen or overlapping the main menu completely. Similarly, if the main menu was animated, I would still want to update it, because it would still be visible, just not focused.

Here's an example:


This is my first attempt at a GUI and game states, so maybe I'm approaching it from the wrong angle.
Simagery
Simagery
This is a blurry area. The practical problem you're dealing with is modal dialogs (or at least all of your examples revolve around that). The question is blurred by discussing gamestate. Some people use that term to mean different things (see a recent thread elsewhere on the forum talking about GameStack).

I think it's fine to achieve what you're wanting with a stack of what you'll call gamestates. But, you won't be able to use a standard stack implementation (unless the stack has forward/backward iterators, not just top() -- which is the case for the STL stack).

You'll definitely want to render your gamestates from bottom to top if your intention is a literal "stack" of gamestates. Updating them is perfectly reasonable (I agree about wanting the animation to keep going in the background).

But, using the term gamestates to refer this is not exactly standard terminology for a lot of folks (witness the arguing of semantics already in the thread). Many would refer to gamestates as a more coarse-grained thing, like "Front-End Shell," "Scenario Designer," "Main Game" and "Results" (thinking of an RTS-like game in this case). Your use of gamestates is more fine-grained and essentially means any mutually-exclusive mode of input for the game, which is a fine use of the term as far as I'm concerned.

In C#, I'm not sure (the MSDN docs are unclear) if the iterator goes in a specifically defined order (top to bottom, bottom to top) as it's implemented as a circular buffer (the iterator may just start at the first valid element in the buffer, I don't know).

If the iterator doesn't do as expected, just implement stack logic on top of an ArrayList (or a proper generic in .NET 2.0). You'll probably want to implement the "pop" action on your stack so that it's deferred. After finishing the "update" phase of the stack, apply any push/pop operations that were queued during the update.
DrunkenHyena
DrunkenHyena
So if I go from the Main Menu to the SubMenu and then into the Game, every frame the Menu and SubMenu are going to be updated and drawn?

To me the UI is not the same as the game state. The UI is *part* of the game state.
Stay Casual,KenDrunken Hyena</FON
Proudest
Proudest
In this case, the main menu opens from the world map, as opposed to the title screen menu. So, when I open both menus, they are pushed onto the stack and are updated/drawn. But when I close a menu, it's popped off the stack, so they're no longer being updated/drawn.

Here's how it looks:


Anyway, I agree with you that the UI should be different than a set of game states, it's just my inexperience with either that has me grouping them together.
DrunkenHyena
DrunkenHyena
Quote:
Original post by Proudest
In this case, the main menu opens from the world map, as opposed to the title screen menu. So, when I open both menus, they are pushed onto the stack and are updated/drawn. But when I close a menu, it's popped off the stack, so they're no longer being updated/drawn.


Ah, I misunderstood what you meant by "Main Menu".

Quote:

Anyway, I agree with you that the UI should be different than a set of game states, it's just my inexperience with either that has me grouping them together.


Everyone has to start out somewhere. I've worked on games where the distinction wasn't very clear and it was always painful. Splitting the UI from the game state is an approach I use in my hobby projects and also in my professional projects and it's always seemed the best approach to me.
Stay Casual,KenDrunken Hyena</FON

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.