9
\$\begingroup\$

Is it a really bad idea to have my Game1 class as static? As at the moment in my Game1 class I have a class called TileHandler which handles everything to do with my current set of tiles, and AnimalHandler which handles all my animals (surprisingly).

Now if I am in AnimalHandler and want to check if a tile is walkable from TileHandler then that causes problems or I have to pass a list of walkable tiles into AnimalHandler, which I'd rather not do.

What would be easier would be to make Game1 static and then in AnimalHandler just go Game1._tileHandler.WalkableTile(position).

Now I can't see anything immediately wrong with this or anything that'd cause any problems but I've only just started using static classes, so does anyone more knowledgeable see any giant reason why that's a bad idea?

\$\endgroup\$

6 Answers 6

8
\$\begingroup\$

Now I can't see anything immediately wrong with this or anything that'd cause any problems but I've only just started using static classes, so does anyone more knowledgeable see any giant reason why that's a bad idea?

When you have a shiny new hammer, every problem looks like a nail.

In general there is nothing wrong with static classes and/or methods, if used properly (for things that do not have or depend on per-instance state). However, in your case you are misusing them to hide a dependency on per-instance, confusing this with removing the dependency. It also appears that you are exposing implementation detail of the Game1 class, which is also generally bad.

Here is the crux of your issue:

...if I am in AnimalHandler and want to check if a tile is walkable from TileHandler then that causes problems or I have to pass a list of walkable tiles into AnimalHandler, which I'd rather not do.

Ignoring the possibility that AnimalHandler needing these tiles may itself be a bad design (with the names you have chosen it's hard to tell the details of these classes) for the moment...if AnimalHandler needs a list of walkable tiles, then it needs a list of walkable tiles. It is generally better to make dependencies more explicit than less so, as it makes code more self-documenting. By passing the list directly to AnimalHandler, you explicit call out the fact that it needs such a list. If you instead make everything static and public so you can just access the static list held elsewhere in the code, all you do is hide the dependency without actually solving or removing it.

For a small game that doesn't need to scale this won't be a problem, per se, but it may lead you down the path of a bad habit so you may want to consider not doing it. At the very least keep this in mind for the next project you work on.

\$\endgroup\$
2
  • \$\begingroup\$ Amen! You touch on a great point I didn't really talk about in my answer. \$\endgroup\$
    – Nate
    Apr 5, 2011 at 15:32
  • \$\begingroup\$ +1 hiding dependencies and introducing global state is really the issue here \$\endgroup\$
    – ashes999
    Dec 15, 2012 at 15:07
4
\$\begingroup\$

The reason that calling TileHandler in a static context is not the best possible design, is that it couples components of your design that could otherwise be decoupled.

If you choose to have more than one TileHandler in the future, you'll have to do a lot of work to accommodate this change.

If you choose to remove TileHandler, you'll have to do a lot of work to accommodate this change.

Suppose you build a different level/zone in the future, that handles tiles in a different way from your current TileHandler. Then you either need to have a way to specify the method of tilehandling to use, or you need to call a different handler.

If the TileHandler was passed as a parameter to objects that use it, then you can simply pass a different one next time, or set a different tile handler on objects that use it later.

Personally, I access many things in my XNA games from a static context, and assume that I'll never have more than one of them.

If you want to be able to reuse your game engine code in your next game, you're likely going to have to rewrite much of the stuff that you currently have written as static.

In short:

In favor of not using static context:

Passing objects as parameters as much as possible decouples game elements, and allows you to modify/reuse them for the current or future projects more easily. It also allows you to manage the complexity of large amounts of code a little easier (think of having hundreds of static managers in your game class, in a big game).

In favor of static context:

Declaring and accessing objects from a static context makes it easier to write small games that don't require hundreds of static managers. Simplifies many methods and constructors by not requiring one or more extra parameters that are instead accessed statically.

\$\endgroup\$
2
\$\begingroup\$

I do not think it's a super bad idea for a simple game, but you could also have a look at http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services for a better idea on how to build intercommunicating game components

\$\endgroup\$
2
  • \$\begingroup\$ Could you think of any problems for if it wasn't just a simple game? \$\endgroup\$
    – Harold
    Apr 5, 2011 at 12:35
  • \$\begingroup\$ Code readability, testability and good architecture practices would suggest to avoid it. \$\endgroup\$
    – smnbss
    May 4, 2011 at 13:04
2
\$\begingroup\$

Things like TileHandler and AnimalHandler I'd put a level higher into a game screen. Does your title screen need access to the TileHandler and is it initialized when the game is first loaded? Probably not.

Check out the XNA State Management sample. It has a lot of code in there, but basically the base game just initializes a stack of game states (or screens). Each screen is fairly independent of the others and runs as a simplified version of the Game itself. Your PlayScreen could have static members so they're accessible to PlayScreen components.

In the base Game, I do use a few statics, but they're very low level things like InputHelper, Log, or Config readers. They are pretty standard across all games so the base engine can be quickly and easily ported. The screens are where the actual game logic happens. So long answer short - no, I don't think it's a bad idea in theory, just be careful what you do make static. Once you go ahead and make something static, it's a tremendous amount of work if you change your mind.

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

The points raised here are all good. In my experience (which admitedly is weighted more toward business apps than games), there are great uses for static classes and members and I've used them many times. I have found, that as requirements and complexity grow, I end up recycling those static classes and converting them to instance classes and start passing them around.

The point I'd like to make is that, if using a static class helps you get this game out, go for it, but still do the right things: implement an interface or base class so it is easier to rip it out and convert it to an instance class later on.

An ounce of prevention is worth a pound of cure, so make sure your static class doesn't tie you down in away that makes it hard to change. It is pretty easy to refactor a method using a static class that implements an interface so it accepts a new interface parameter and uses that interface instead of the static class reference.

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

Yes, it is generally always a bad idea.

Turning objects containing changing data (i.e. anything but read-only constants and lookup tables) into static classes is where good design takes a dive.

  1. It promotes haphazard dependencies that kill modularity and get in the way of code reuse. Assume you wanted to write an editor for your game - you'd suddenly have lots of classes crying for a Game1 that you cannot easily move into a shared library.

  2. Your code becomes untestable. Unit testing works by isolating individual classes from the rest by mocking or simulating their dependencies (which should be kept as minimal as possible). Any static class is a liability because it could be accessed at any time, carry state over multiple tests or require to be initialized before the tests can succeed.

  3. It hides dependencies. Much like the service provider anti-pattern (also employed by XNA, Game.Services), your classes can pick dependencies which you don't see on the outside.

This approach becomes especially poisonous if one combines static classes with freight train calls (thingsl ike Game.Instance.ActorManager.Enemies.FindInRange(10) - so called because of the train car-like chained symbols), where components suddenly not only require a Game class, but one with a static Instance property that returns something with an ActorManager property that has an Enemies property that returns an object with a FindInRange() method.

The only excuse I would accept for writing mutable static classes would be the one is still learning and doesn't have the ability to consistently apply good design and a trained eye for spotting bad choices yet.

\$\endgroup\$

You must log in to answer this question.

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