GameStates and GuiManager

Nov 27, 2010 at 1:46 AM
Edited Nov 27, 2010 at 2:10 AM

Hi,

 

On some of my game states, I want to use the user interface controls provided in Nuclex.UserInterface.

I add a GuiManager etc to my game services in my Game class.

 

Is there a "best way" to access these from within a game state?

Dec 8, 2010 at 10:35 PM
Edited Dec 8, 2010 at 10:35 PM

I know exactly what you mean, I had exactly the same issue in that you can't access the GuiManager from any of your game states as whilst a game state takes over the role of the Game class it doesn't expose access to the Games services.

I worked around it by changing the following in GameStateManager to be public.

/// 
///   Service container used to access services provided by external components
/// 
internal GameServiceContainer InternalGameServices {
    get { return this.gameServices; }
}

That lets me get hold of any services, including the GuiManager, from any GameState.

It seems dirty but it seemed simplest until Cygon comes in with the intended method of managing a GUI from inside a GameState. I suspect we shouldn't be using the GuiManager in this situation as he does mention in the documentation that you can handle the management of the GUI yourself outside of the GuiManager. I just found it very useful to keep a GUI screen inside each GameState and to make that the active screen for the GuiManager when the GameState was entered.

Coordinator
Dec 12, 2010 at 6:37 PM

Sorry for the late answer, sometimes I'm just being lazy :)

Personally, I prefer to pass references to game states (and anywhere else) explicitly, as in, using constructor parameters. The reasons being:

  • The class doesn't go "shopping for references" in the game service container, thus it's much more obvious which services a class consumes.
  • This design also works much better in projects doing dependency injection through an inversion of control container.
  • It's easier to provide mocks instead of the real implementations to the class in your unit tests.
  • Classes consuming too many references (likely SRP violation) stand out

But depending on which programming methodology you subscribe to, you may prefer to just pass the game service container along, use static properties or anything else that's convenient. I'm trying to support choice by leaving references up to the programmer and not forcing anyone to pass along the game services container.

The way I envision it, you would gain access to the IGuiService in whatever way you prefer (as states, mine would be to pass it through the constructor of the concrete game state) and manage the GUI from there (meaning the concrete game state doesn't own the entire GUI system but only the dialog it is displaying). There are several options to this: each GameState can manage its own Screen (which is useful if you have different "rooms" in a complex interface - you could even keep the dialogs open on the detached Screen while the player is in another room) or each GameState can just add the dialogs it wants to display to the default Screen and remove them again when the game leaves that state.

Dec 16, 2010 at 12:09 PM

Thanks for the reply.

 

After further research into game arcitecture and so on, I have decided to go for the constructor parameter style you mention -

  • Every class recieves all of the other objects it needs to function when it is instantiated via contrsructor parameters
  • Normally I use an interface so that the implementation of the object being passed does not matter, and can be swapped out easily
  • I'm using events to notify objects of changes within an object it references
  • I'm currently plugging in these parameter objects manually, but this may change as my project grows

I've extended this to the point where there is no "GameEntity" class:

For example -

  • An IHealth has a "Died" event
  • An IRenderer takes an IHealth, so that it can hook into the Died event, so that it knows when to destroy itself

This all works very well...

... but leads me into another question: Sometimes a component needs to grab all components of a certain type, and check their values.

For example -

  • An ITargeter needs to look through all ITargets in the component manager...
  • It accesses each ITarget's IPosition provider, and decides on a target accordingly

Clearly my current solution doesn't support this, but its unclear on what a good way to support this would be. I don't really want to grant all components access to all other components, as this could result in the "hidden dependancy hell" I am trying to avoid!

 

Any thoughts would be much appreciated

Feb 4, 2011 at 8:30 AM

My thought would be create a dedicated TargetContainer service to hold all your ITarget refs, and pass that around as needed.