Edit: I was way off track and rethought my answer.
You're on the right track with each screen having a collection of components. In fact, there's a class just for that:
GameComponentCollection
Each screen can implement their own list the same as Game does. The screens shouldn't need to manipulate very much in other screens or the base game - they should be relatively confined. Things like Units, Map, Player, Lights, Cameras, Physics, Timers - they all go in the screen component collection.
Stuff in the Game.Components list are usually global functionality - ScreenManager, Input, Settings - things that get read from but not manipulated.
Wall of psuedo-ish code. I stripped down the AppHub example - figured it would be easier to add things in as I need functionality rather than start with a giant codebase - easier to learn that way for me.
class MyGame : Microsoft.Xna.Framework.Game
{
GameScreenManager _gameScreens;
// I make this static, seems easier? Mine doesn't do much
// other than provide some helpers and shortcuts
static InputManager _input;
public static InputManager Input { get { return _input } }
public void MyGame()
{
// ... graphics initialization ...
_gamescreens = new GameScreenManager();
_gameScreens.Push(new MenuScreen(_gameScreens, _graphicsDevice));
}
}
class GameScreenManager : Microsoft.Xna.Framework.DrawableGameComponent
{
LinkedList<GameScreen> _screens; // Not a 'stack', but we can use it as such
public void Push(GameScreen screen)
{
_screens.AddFirst(screen);
}
public void Pop(GameScreen screen)
{
_screens.RemoveFirst(screen);
}
// ... Update is the same as draw... just updating() ...
/// <summary>
/// Draw the stack of game states
/// </summary>
public override void Draw(GameTime time)
{
// Here we just draw the top node, then recursively step down while
// the screen is not BlockDraw. This lets a screen hide or partially
// let anything below it display (ie, a PauseScreen only partially
// hides the GamePlayScreen
_Draw(_screens.First, time);
}
/// <summary>
/// Recursively draw the game state stack
/// </summary>
private void _Draw(LinkedListNode<Screen> node, GameTime time)
{
node.Value.Draw(time);
// Only draw the screen below if the current one is not blocking
if (!node.Value.BlockDraw)
_Draw(node.Next, time);
}
}
abstract class Screen
{
// Game Screen Components (UnitManager, Lights, Sound, Cameras, Player, etc...)
// These ones can implement IUpdateable and IDrawable, and the manager here
// handles that
// This could easily be GameComponentCollection instead - I just wrote my own
// as I wanted to change a few things in it.
protected GameScreenComponentManager _components;
// Block updates to screens below. Override in child classes if different
public virtual bool BlockUpdate { get { retrun true; } }
// Block draws to screens below. Override in child classes if different
public virtual bool BlockDraw { get { retrun true; } }
// In the screen constructor create its own SpriteBatch, it's
// own SoundManager to handle playing sounds, it's own Player class, etc.
// In this way, levels get easier too - each level is it's own screen.
// OnLevelFinish just instantiates the next, pops the current from the manager,
// and pushes on the new one.
public Screen(GameScreenManager _screenManager, GraphicsDevice device, ...Other Dependancies...)
{ }
public abstract void Initialize();
public abstract void Update(GameTime time);
public abstract void Draw(GameTime time);
}
So this is a simplified outline of the key parts.
GameScreens can create and push new screens onto the stack, and also remove themselves. Ie, then Menu Screen can push on a Settings Screen or a GamePlayScreen.
As commented, screens manage their own resources and are passed the dependencies needed to create these resources (or, register some dependencies in the service locator and just pass that into each screen). You can even create a new XNA ContentManager for each screen - leave one accessible back down in the Game for shared assets (but only a few). That way, when a screen is removed, in it's Dispose it releases only that screen's loaded assets.