11
\$\begingroup\$

I'm making a little dungeon crawler in space, and I'd like to hear some advice on how to make the backend of the engine nicer. Basically, currently everything is based on a crapload of managers:

  • BackgroundManager: has AddBackground(image, parallax) method for making cool background effects.
  • ConfigManager: reads/makes the config file and also holds the data read from that config file.
  • DrawManager: has Draw(sprite) method to draw stuff to the screen, and things like SetView(view), GetView() etc.
  • EntityManager: holds all active entities and has methods for adding, removing and finding entities.
  • DungeonManager (actually called a GridManager, but this is for simplicity): has methods like GenerateDungeon(), PlaceEnemies(), PlaceFinish() etc.

Now I'm not even halfway there listing all my managers, so I think this has got to change. My game is also based on Screens, which makes it more annoying because I don't need half of the stuff my managers are managing in, for example, the main menu (I don't need physics/entities/dungeons in my main menu!)

Now I thought about making the managers not static, and giving my ScreenMainGame an instance of all game-specific managers. But that makes calling/getting anything related to the managers a huge mess... for example, if I wanted to draw my dungeon from any place that's not in ScreenMainGame.Draw(), I'd have to do this...

((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()

That's really ugly.

So, fellow game developers, does any of you have an idea how to solve this mess? I'd be appreciated!

\$\endgroup\$
4
  • \$\begingroup\$ I'm not sure exactly how to help you, but I would recommend reading a good book on design patterns. I've been reading Head First Design Patterns and it's very easy to understand. The examples are in Java, but I think that would be close enough to C# to help you. Sorry if my suggestion is too novice. \$\endgroup\$
    – Amplify91
    Commented Jul 29, 2011 at 13:12
  • \$\begingroup\$ What are you using to interface with the graphics card? XNA? SlimDX? \$\endgroup\$ Commented Jul 29, 2011 at 15:36
  • \$\begingroup\$ @BlueRaja: I'm using SFML.NET. \$\endgroup\$
    – Dlaor
    Commented Jul 29, 2011 at 16:09
  • \$\begingroup\$ In that case, you should simply use the normal methods of dealing with these problems in C#: See my last link below, as well as What is dependency injection? \$\endgroup\$ Commented Jul 29, 2011 at 16:44

3 Answers 3

10
\$\begingroup\$

What about a component-based engine?

You would have a main class named Engine, which would keep a list of GameScreens, which would themselves hold a list of Components.

The engine has an Update and a Draw method and both call the GameScreen's Update and Draw methods, which themselves go through every component and call Update and Draw.

Presented like that, I agree that it sounds like a poor and repetitive design. But believe me, my code became much cleaner by using a component-based approach than it did with all my old manager classes.

It's much simpler to maintain such code too, since you're just going through a big class hierarchy and not having to search through BackgroundManager for all the specific different backgrounds. You just have a ScrollingBackground, ParallaxBackground, StaticBackground, etc. which all derive from a Background class.

You'll eventually build up a pretty solid engine that you can reuse over all your projects with a lot of frequently used components and helper methods (e.g. a FrameRateDisplayer as a debugging utility, a Sprite class as a basic sprite with a texture and extension methods for vectors and random number generation).

You would no longer have a BackgroundManager class, but a Background class which would manage itself instead.

When your game starts, all you have to do is this basically:

// when declaring variables:
Engine engine;

// when initializing:
engine = new Engine();
engine.Initialize();
engine.LoadContent();
engine.AddGameScreen(new MainMenuScreen());

// when updating:
engine.Update();

// when drawing:
engine.Draw();

And that's it for your game start code.

Then, for the main menu screen:

class MainMenuScreen : MenuScreen // where MenuScreen derives from the GameScreen class
{
    const int ENEMY_COUNT = 10;

    StaticBackground background;
    Player player;
    List<Enemy> enemies;

    public override void Initialize()
    {
        background = new StaticBackground();
        player = new Player();
        enemies = new List<Enemy>();

        base.AddComponent(background); // defined within the GameScreen class
        base.AddComponent(player);
        for (int i = 0; i < ENEMY_COUNT; ++i)
        {
            Enemy newEnemy = new Enemy();
            enemies.Add(newEnemy);
            base.AddComponent(newEnemy);
        }
    }
}

You get the general idea.

You would also keep the reference of the Engine within all your GameScreen classes, to be able to add new screens even within a GameScreen class (e.g. when the user clicks on the StartGame button while within your MainMenuScreen, you can transition to the GameplayScreen).

The same goes for the Component class: it should hold the reference of its parent GameScreen, to have both access to the Engine class and its parent GameScreen to add new components (e.g. you can make a HUD-related class called DrawableButton which holds a DrawableText component and a StaticBackground component).

You can even apply other design patterns after that, like the "service design pattern"(not sure about the exact name) where you can keep different useful services within your Engine class(you simply keep a list of IServices and let other classes add services themselves). e.g. I would keep a Camera2D component over all my project as a service to apply its transformation when drawing other components. This avoids having to pass it as a parameter everywhere.

In conclusion, there certainly may be other better designs for an engine, but I found the engine proposed by this link very elegant, extremely easily maintainable and reusable. I would personally recommend at least trying it.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ XNA supports all of this out-of-the-box via GameComponents and services. No need for a separate Engine class. \$\endgroup\$ Commented Jul 29, 2011 at 15:02
  • \$\begingroup\$ +1 for this answer. Also, would it make sense to put drawing in a separate thread from game update thread? \$\endgroup\$
    – f20k
    Commented Jul 29, 2011 at 15:11
  • 1
    \$\begingroup\$ @BlueRaja - DannyPflughoeft: Indeed but I assumed XNA was not used so I explained a little bit more about how to do it. \$\endgroup\$ Commented Jul 29, 2011 at 15:28
  • \$\begingroup\$ @f20k: Yes, pretty much the same way XNA does it. I don't know how it is implemented though. =/ There must be an article somewhere on the internet about how to do it. :) \$\endgroup\$ Commented Jul 29, 2011 at 15:29
  • \$\begingroup\$ Yeah, I'm not using XNA but this seems like a nice alternative to what I'm doing. I'm currently reading the book "Head First Design Patterns" to see if there are any more alternatives. Cheers! \$\endgroup\$
    – Dlaor
    Commented Jul 29, 2011 at 16:08
1
\$\begingroup\$

What you want to do is separate your code into components and services. XNA has built-in support for these already.

See this article on GameComponents and services. Then see this answer on using services in XNA, and this more general answer on services in any language.

\$\endgroup\$
-3
\$\begingroup\$

Just because they are static or global doesn't mean they have to always be loaded/initialized. Use a Singleton pattern and allow the managers to be freeable and loaded again on demand.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ A singleton is just a facade for the underlying problem the OP is trying to solve here. \$\endgroup\$
    – user1430
    Commented Jul 29, 2011 at 15:29

You must log in to answer this question.

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