5
\$\begingroup\$

Assuming you have classes like Player, Enemy, Map and Tile.

The first approach to structuring rendering code would be to give each a render() method and let it draw itself:

void render(){
   player.draw();
   enemy.draw();
   // etc.
}

But considering the Model-View-Controller perspective, that feels wrong... Another idea would be to make a Renderer class, but then I wonder how you give the Renderer information what to draw.

Which one should I choose and why?

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Doesn't feel right? Explain further. \$\endgroup\$
    – user15805
    Feb 10, 2014 at 13:27
  • \$\begingroup\$ I just think that game logic and visual representation should be seperated, that's why it doesn't feel right. \$\endgroup\$
    – user42030
    Feb 10, 2014 at 13:36
  • \$\begingroup\$ But they are separated. You have a player.draw() separately from player.update(), right? \$\endgroup\$ Feb 10, 2014 at 14:18
  • \$\begingroup\$ I have a render() and a update() method in my game loop. \$\endgroup\$
    – user42030
    Feb 10, 2014 at 14:22
  • \$\begingroup\$ I don't think this is a duplicate, my question wasn't if a game object should draw itself, it was, how to approach rendering. \$\endgroup\$
    – user42030
    Feb 10, 2014 at 14:44

2 Answers 2

4
\$\begingroup\$

Let's boil this down to dependencies.

Now the first thing is first, how do you render something? Well the logical manner tells us that we need some asset which will be loaded and then displayed.

Assets:

  • Sprite
  • Sound
  • Music

Now how to you get these assets into your program? You typically will have some sort of Asset Manager who's responsibility is to load them for you. Now you have a bunch of Sprites/Sounds/etc... who are owned by who?

Well the player is made up of several assets, and these assets are used exclusively by the player. It then makes sense to have the player directly manage its own assets. So you might have:

class Player
{
    Sprite _playerMain;
    Sprite _playerSword;
    Sound _aughghghghgh;
};

Now how do you draw these? You've already mentioned two possible approaches, both are good approaches.

Let the player draw itself: Each object in the game will have a Draw(); function, and would call Draw(); on each Sprite object it owns.

Pros:

  • Used by half-life 2 and several other games
  • Very simple to implement
  • Fine control over render order

Cons:

  • Plenty of duplicate code
  • Unable to take advantage of batching or other rendering tricks
  • Must pre-sort your sprite layers

Use a rendering manager: A rendering manager will typically have a render priority (layers), with each object assigned to a given layer. The manager then batches and renders sprites from layer to layer. Your sprites will essentially add/remove them to/from the rendering manager.

Pros:

  • Separation of data and logic
  • Sprite layering is built-in, no need to pre-sort
  • Able to batch sprites efficiently
  • Player, Enemy, and other objects no longer need to encapsulate rendering code

Cons:

  • Additional infrastructure to write

Now each approach is just fine. My current project is almost a hybrid of the two due to special requirements. Now you aren't going to be writing a AAA game, so work with whichever approach you prefer.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Is it good design to take the Sprite into the Player class? Shouldn't the Player class just contain data like e.g. HP, Strength, etc.? \$\endgroup\$
    – user42030
    Feb 10, 2014 at 13:31
  • \$\begingroup\$ Your player should contain every bit of data that it needs to function. If the player uses a sprite to make itself visible, then it should own that sprite. \$\endgroup\$
    – user39686
    Feb 10, 2014 at 13:45
  • \$\begingroup\$ @user42030 I agree, the Player class shouldn't need to know anything about its sprite(s) which are observing the player object and could be drawing it in potentially multiple different views in many different ways (minimap for example). \$\endgroup\$
    – MasterHD
    Apr 4, 2021 at 18:05
2
\$\begingroup\$

It's a bad idea if you are talking about 3D / GPU rendering.

It's fine if you're rendering 2D / non-GPU, as it may make more sense to you organisationally.

The reason is that GPU rendering, for optimal (or even reasonable) performance, requires individual render passes that render groups of game objects with similar properties i.e. materials, since each material uses different shaders and sometimes, different textures... switching between different textures and shaders can cost considerable time on the GPU, hence this is best avoided.

Allowing each object to render itself (rather than being observed and rendered by a single monolithic renderer) breaks this grouping which would allow the GPU to perform optimally. Some game objects can consist of multiple different materials, which would also break this grouping.

Even so, for small numbers of objects and low-cost shaders, this doesn't really matter much running on modern GPUs. But as soon as you have complex materials and many game objects, it is a far better idea to render from a single class / function, by inspecting game object properties.

\$\endgroup\$

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