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:
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.
player.draw()
separately fromplayer.update()
, right? \$\endgroup\$render()
and aupdate()
method in my game loop. \$\endgroup\$