3
\$\begingroup\$

I am creating a simple 2D game using XNA.

The elements that make up the game world are what i refer to as the "model".

For instance, in a board game, i would have a GameBoard class that stores information about the board.

This information could be things such as:

  • Location
  • Size
  • Details about cells on the board (occupied/not occupied)
  • etc

This object should either know how to draw itself, or describe how to draw itself to some other entity (renderer) in order to be displayed.

I believe that since the board only contains the data+logic for things regarding it or cells on it, it should not provide the logic of how to draw things (separation of concerns).

How can i achieve a good partitioning and easily allow some other entity to draw it properly?

My motivations for doing so are:

  • Allow multiple "implementations" of presentation for a single game entity
  • Easier porting to other environments where the presentation code is not available (for example - porting my code to Unity or other game technology that does not rely on XNA).
\$\endgroup\$

1 Answer 1

6
\$\begingroup\$

I find that I can create more separation between objects with the least amount of code possible by letting objects draw themselves. However, when I say that, I mean that while render-able objects have a Draw() method, they certainly don't know a single thing about drawing vertices or textures. Instead, they are passed an instance of an object that does all the drawing for them.

This object can be considered a Renderer object. What does Renderer do? It renders stuff, and it's the only class that knows the ins-and-outs of rendering vertices and textures. Now your gameObjects can just tell the renderer, "Hey, draw me. Here's my data.".

For 2D games in XNA, this is already done for you with SpriteBatch.

You may want some sort of an interface, for example, IDrawable, that each of your render-able objects will inherit from. This is a guarantee being made to all of your calling code that your render-able objects will contain a specific method signature. It also helps when iterating over a list of objects as you'll see in a bit.

public interface IDrawable {
    void Draw( SpriteBatch batch );
}

In this case, we're saying that all objects of type IDrawable will contain a Draw method that takes in a SpriteBatch object. Make sure all of your render-able objects inherit this interface, and implement that method. Your typical Draw method might look something like:

public Draw( SpriteBatch spriteBatch ) {
    spriteBatch.Draw( myTexture2D, myDestRect, Color.White );
}

I don't know how you keep a list of all your game-objects, but I tend to have some sort of base class. GameObject tends to be the typical base that most people use. In C#, the foreach statement makes rendering all of our render-able objects within our List<GameObject> really simple:

List<GameObject> gameObjects;   // list of all game objects in play
SpriteBatch batch;              // our spritebatch instance

public void Draw() {
    this.batch.Begin();
    foreach( IDrawable gameObject in this.gameObjects ) {
        gameObject.Draw( renderer );
    }
    this.batch.End();
}

If you don't want your gameObjects to have a Draw() method at all, you can simply move the calling code back to the game state to achieve the same effect:

List<GameObject> gameObjects;   // list of all game objects in play
SpriteBatch batch;              // our spritebatch instance

public void Draw() {
    this.batch.Begin();
    foreach( IDrawable gameObject in this.gameObjects ) {
        this.batch.Draw(
            gameObject.Texture2D,
            gameObject.DestRect,
            Color.White );
    }
    this.batch.End();
}

There are more extreme methods of separation out there (read up on Entity Component Systems), but I find them a bit too convoluted for my tastes. Game development entails a lot of coupling between data and presentation. That's just the way it is, and sometimes keeping it simple works best in the long run.

\$\endgroup\$

You must log in to answer this question.

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