3
\$\begingroup\$

I'm trying to make a Game State Manager and I'm using the Microsoft Game State Management Sample as guidance. However, I want a more simplistic design (no transitions, reflection, or support for 360/Phone). Now, I am diverging a bit in to my own design.

I figure every single game screen is going to need access to the SpriteBatch, ContentManager, and Input. Input is a class I defined to detect key and mouse presses/releases/etc.

Currently I'm just using regular old dependency injection and just passing those three references in to the constructor of all newly created screens, but the code repetition is bugging me slightly.

Since all screens in my game are going to need to detect input, load content, and draw to the screen, I'd prefer a solution where I wouldn't have to cumbersomely pass and include these three objects in all new game screens. However, I'm not sure how exactly to do this.

I suppose the Game Screen Manager could maintain a reference to all of these objects, but then each game screen would have to maintain a reference to the game screen manager, which just sounds wrong. Also, they would have to be public properties on the game screen manager and I'm not sure I want to expose that much information to potential clients. Ideally, each game screen would not have to know about the game screen manager and would somehow have access to these three essential objects without requiring them in all of their constructors.

Any ideas? Thanks.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ John Williams? I'm a big fan of your work on Hook and various other films! \$\endgroup\$
    – user12197
    Commented Feb 22, 2012 at 1:46
  • \$\begingroup\$ Input is accessible from anywhere, you just do something like MouseState.GetState(). SpriteBatch is part of your instance of XNA.Game, and so is ContentManager. All you need access to is Game to have access to all three things you're looking for. \$\endgroup\$
    – Nic Foster
    Commented Feb 22, 2012 at 4:21

3 Answers 3

3
\$\begingroup\$

Well, to begin with, passing required objects into a constructor is a fine solution.

One alternative would be to use the Services architecture, which allows you to simply pass that around. It has some nice properties, but also makes things more complex. Take a look at this discussion.

It is still passing stuff into a constructor - but at least there is less typing.

You could also consider making a custom "Game Screen Resources" class and pass that around. I think this is perhaps more appropriate than services, if you want to continue down this route.

But do not dismiss the idea of just making everything global. It's a game. It doesn't have to be an architectural delight.

Of particular note is Input - where the source data is already global (see XNA's Mouse, Keyboard, etc). Unless you are actually doing automated unit testing and actually need the ability to swap out implementations now, just go ahead and make your Input class a static class.

By the same token, you could make your SpriteBatch instance public (Content already is) and make your game class instance statically available (ie: global).

This is very good from a DTTSTCPW perspective. It's extremely easy, and can easily be modified later (with no more additional effort than implementing something more complicated in the first place).

(My answer here similar to this one and probably also worth reading.)

\$\endgroup\$
0
\$\begingroup\$

I use a variant of what they use in Flat Red Ball in my own framework, Radiant Wrench. Basically:

  • The Game class is like the controller, it has an instance of the current screen
  • The Screen class has Sprites, Texts, etc.

Each of the drawable classes (Sprite, etc.) have a Draw method, which takes a SpriteBatch as a parameter. The game class then passes the sprite batch to the screen, which passes it to the dra method.

This served me pretty well. The separation of concerns is pretty good (from my perspective -- I like to hide anything platform-specific, like XNA-specific, from the actual game logic and classes as much as possible). Not sure if it's exactly what you want, though.

\$\endgroup\$
0
\$\begingroup\$

My solution goes against every programming rule in the book. It is very simple though. :P

I made a static global.cs class. I added a public static variable of type Main (my main class) called mainClassInstance.

Then in the initialiser for Main I say global.mainClassInstance = this.

From there any other classes can access spriteBatch using global.mainClassInstance.spriteBatch or whatever. (spriteBatch needs to be public)

Loading assets is slightly more tricky. We can't just set Content to be public. So I created the following function in Main.cs:

public Texture2D loadTexture(string fileName)
{
    return this.Content.Load<Texture2D>(fileName);
}

It can then be called with Texture2D asset = global.mainScript.loadTexture("asset") Note that this only works for Texture2Ds, you'll need more functions for other assets.

Now I know that global variables are messy, but this seems to me less messy than passing three arguments to EVERY class.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ You could make your method more generic by, well, using generics: public T loadContent<T>(string fileName) { return this.Content.Load<T>(fileName); } \$\endgroup\$ Commented Feb 23, 2012 at 15:45
  • \$\begingroup\$ @RichardMarskell-Drackir, good idea, I'll definitely do this (right after I read up on generics) \$\endgroup\$ Commented Feb 23, 2012 at 22:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .