Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a Screen class that encapsulates the updating and rendering of several distinct states, such as the menu, gameplay, and credits. A stack of screens exists on which the screens themselves need to be able to push new, and pop screens (imagine selecting "Start game" from the main menu, pushing the gameplay screen and popping the main menu screen).

I could have a ScreenManager class to babysit my screens but this would basically just be a wrapper around a list. I am therefore considering to pass each screen the std::list<Screen*> _screens and have them push and remove as they see fit. What I am worried about is overhead of copying this list around. If I recall correctly, since the list contains pointers to screens, the only thing I would be copying are the list of pointers, correct? And not the actual screens themselves.

Would this be an advisable way to go, or would you recommend creating a "wrapper class", such as a ScreenManager in any case?

share|improve this question
    
The Gamebryo Textbook Chapter 1 describes a really nice screen manager architecture (based on an article from Game Programming Gems 5). Unfortunately the link seems to be broken at the moment, but I found a mirror here and source code here. Worth a read. –  David Gouveia Dec 27 '11 at 18:01
    
That was a great resource David, thanks! –  Laurens Dec 27 '11 at 18:27

3 Answers 3

up vote 6 down vote accepted

If you are copying that list around (i.e. passing in the list by value) then the overhead of copying a list of pointers is the least of your concerns - it probably won't even work as you expect. Each Screen will have its own separate list, and modifications won't propagate to other screens. You would need to share the same list between all screens. There are two simple ways to solve this:

  • You could make the list static inside the Screen class so that only one instance will be created and shared by all Screens.

  • Or you could pass the list itself as a reference or a pointer so that all Screen's have access to the same list and no copying is performed. I.e:

// Inside the Screen class you would store the screen as a...
// Pointer
std::list<Screen*>* _screens;
// or
// Reference, must assign in constructor/initialization list
std::list<Screen*>& _screens;

Careful with scope too. You must keep the list alive throughout the duration of the application.

But still, I'd really recommend creating a ScreenManager class and I see no benefit from doing the list handling like this. Even if it's just a simple wrapper, it's going to be easier to understand (and extend if needed).

And by the way, a ScreenManager class is not necessarily just a wrapper around a list. There can be many different features added to it. For example, my ScreenManager is also responsible for:

  • Keeping a dictionary/map registry of screens and their ids which allows me to do everything by id: screenManager.PushScreen("PauseScreen")
  • Handling "smooth" transitions between screens, such as fades or slides. Basically, each screen has a fade out and fade in time and a float fade value between 0 and 1. The screen manager takes care of handling these transitions and interpolating the fade value. The screen decides what to do with this value (i.e. darken the screen, offset sprites, etc).

And I've seen screen managers supporting other operations such as:

  • Add delays between switch/push/pop screen operations.
  • Popping several screens at once.

I think it's neat to have all of this encapsulated in its own class, rather than polluting the Screen class. So, it depends a bit on what you need, but I still think creating a simple ScreenManager class would be better than passing that list around.

share|improve this answer
1  
Thanks for the insightful answers everyone! I had indeed not considered it might not even work as expected and decided to drop simply passing the list, opting for a ScreenManager. Perhaps I have been developing an unhealthy skepticism towards any class with "Manager" in it even though the answers have demonstrated it is a better solution in this case! –  Laurens Dec 27 '11 at 18:29

Since pointers act only as references to addresses you would only be copying those addresses and not the screens themselves.

Personally, I prefer to have a ScreenManager merely because the manager can be used for more than just holding the screens. For example, what if I wanted to find all of the Enemies being drawn to a given Screen? Rather than do some fancy checking inline, I could just create a function which returns all of the objects of a certain type from some Screen inside of the ScreenManager. In the end, the choice between a simple list and a manager depends on how complicated of a game you're making.

share|improve this answer

As my previous speaker noted, I'd also prefer the ScreenManager of the same reasons.

If you really want to follow through with adding the list to your Screen class, I'd use a pointer to the list since there should be only one instance of it (like singleton pattern, which is another argument for a ScreenManager class)

Concurrency is another issue you should be aware of when building this logic into Screen class. E.g. the ScreenManager of my engine loops over all Screens and calls the Update method of every Screen. It is possible that a Screen pops itself off the stack in Update which breaks the iterator logic in the ScreenManager class. Pretty easy to fix if there is just one place to look at...

share|improve this answer
    
Allow me to toss in a tip here. As for the problem you mention in your last paragraph, this is another problem that is easy to address with a ScreenManager. When one of my Screens issues a Push or Pop action inside the Update method, the action is not executed immediatly. Instead the ScreenManager batches the operation (e.g. I have a private struct called ScreenManagerAction which can be of type Switch, Push, Pop + parameters and I store these actions in a list) and the actions are only applied after the Update loop ends. This way the iteration of the screens does not break. –  David Gouveia Dec 27 '11 at 17:52
    
Interesting approach, thanks for sharing! Since I am currently using XNA/C# I simply copy my list of Screens in the ScreenManager class to an array using ToArray() before iterating. Different approach, basically same result ;-) –  PrinceCharles Dec 27 '11 at 23:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.