It is completely a matter of taste.
You could pass your Game
class instance into the constructor of your Sprite
and access its public Services
property. This is what DrawableGameComponent
and GraphicsDeviceManager
do.
You could pass Game.Services
as an IServiceProvider
into the constructor of your Sprite
class. This is what the ContentManager
class does. This has the advantage of not depending on an actual instance of Game
(which you might not have if, say, you end up making a form-based level editor).
You could just pass an instance of SpriteBatch
in the constructor of your Sprite
class, but you can then only create Sprite
objects after you create your SpriteBatch
, which you can only do during and after LoadContent
.
You could get especially lazy and create a globally accessible Game
or IServiceProvider
or SpriteBatch
object and just use that (make it a static property on your game class). Advantage: quick and easy; Disadvantage: ugly!
You could pass a SpriteBatch
instance into your Sprite.Draw
method. This is pretty easy to do, and is the method I use for my gameplay classes - things that might have a Draw
and an Update
function (eg: a Player, or an Enemy, etc). One advantage is that it makes it both locally explicit and easy to modify the shared resources that the Draw
function depends on.
But if your Sprite
class is simply visual data for SpriteBatch
(texture, position, etc), which is managed externally (having public setters for these properties, in your example, indicates that it might be), then I would recommend creating an extension method for SpriteBatch
that does the drawing. This allows you to maintain the "feel" of the SpriteBatch
object. Your extension method might look like:
public static void Draw(this SpriteBatch sb, Sprite sprite)
{
sb.Draw(sprite.Texture, sprite.Position, Color.White);
}
Allowing you to draw it with: sb.Draw(sprite);
. This method is preferable if you are not doing SpriteBatch.Begin
and .End
calls in your Draw
method - as this allows it to work the same as SpriteBatch
.
Those last two methods are the ones that I use and recommend myself.
But you have done something that strikes me as pretty unusual by making your Sprite.Draw
method virtual
- indicating that you will be inheriting from Sprite
and using it virtually. But combining this with public setters, and not calling Begin
and End
, makes for a pretty confused design.
If this is really the design you intend to use, then passing an IServiceProvider
to the Sprite
constructor is probably the best method to use as it allows for better encapsulation. (Just fix up those other things, which don't ;)
Begin()
/End()
? It makes sense to me - he wants the drawing code in the sprite class, but doesn't want every sprite to be in its own batch. He presumably has a sprite-managerDrawableGameComponent
which loops over all the sprites and callsDraw()
on them individually, within a single sprite-batch. This is exactly how I'd do it. – BlueRaja - Danny Pflughoeft Jul 11 '11 at 08:10SpriteBatch
object, but leave it in its base (not-in-batch) state when you're done". It's also reasonably nice to say "my draw function takes aSpriteBatch
parameter that is already in-batch with the correct settings". It is not so nice to say "share thisSpriteBatch
object, and trust us that we'll put it in the right state before calling yourDraw
method". – Andrew Russell Jul 11 '11 at 13:35{ End; Begin(my settings); DrawMyStuff; End; Begin(try to reset); }
- and that is very much un-nice. And, again, architecture is a matter of taste - these are not hard-and-fast rules. You might recall that I don't likeDrawableGameComponent
, and one reason is that it can force you to use this less-nice architecture (which works, it's just not nice). – Andrew Russell Jul 11 '11 at 13:39SpriteBatch
settings, they can create their own instance - there's nothing wrong with multiple overlapping sprite-batches. Otherwise, not forcing every class to call Begin/End is more convenient and (as I understand it; I've never profiled it) more performant. The same argument applies whether or not he's actually usingGameComponent
s. – BlueRaja - Danny Pflughoeft Jul 11 '11 at 16:10