views:

511

answers:

2

I have just recently begun playing around with XNA and couldn’t find anything on the web regarding this question. Is there a way to tell if SpriteBatch.Begin (and conversely End) has been called on a particular SpriteBatch object?

At the moment, I am using only one essentially global SpriteBatch object for the system, mainly because that seems to be the preferred method from the articles I have been reading. I’m assuming that creating a SpriteBatch instance for each object would cause too much overhead. Anyways, I am having problems with keeping SpriteBatch.Begin/End synchronized. In particular when drawing objects can contain other drawing objects. If I could test whether Begin/End has been called then my problems go away. I suppose I could try something like subclassing the SpriteBatch class but it seems to me like this operation is so basic that there has to be a built in way to tell. I just haven’t been able to figure out how.

Thanks for any insight you can provide!

+1  A: 

If you take a look at this link i think it will answer your question, sorry if the link is a different version than what you're using:

http://www.ziggyware.com/forum/viewthread.php?forum_id=12&thread_id=12996

It's kind of up to the developer to figure out if the code they are writing will be within the begin and end. You want to make sure you are "holding" everything you need draw until you do call that "begin" and then draw after that.

Additionally you might want to take a look at some articles on "game loops" and how they operate it will help you get a good understanding of how to code in such a way that you shouldn't have this problem.

Hope this helps! :-)

For instance make an interface, which you can inherit from that has a Draw() method. Then back in the game loop, make sure you cycle through all objects to be drawn (which inherit from that interface) and call their draw method within the begin end lines. The code inside each object can have the drawing specifics, but you KNOW that will be called when its suppose to. Maybe that will clarify a little.

Wade
Thanks for finding that site, I don't know why it didn't show up when I google'd every variation I could think of. I guess, I am still confused by the comment "if you setup your code properly...you shouldn't need to know". My intent was to have every object draw itself, so each object would call its' own Begin/End. The problem arises when objects contain other objects that need to be drawn, so they call Draw on the contained objects. That seems like a very easy to understand and flexible way of organizing things. Is it true that this is not the correct way of thinking in the XNA world?
Dunk
Yes and no, sorry that comment was vague on my part.You're right but the drawing shouldn't actually happen within the object itself. So for instance you create a lot of objects, each does all the logic it possibly can to set it up to be drawn to the screen. For isntance position, color, size etc. Then when you call the draw method on that object from the inital single draw method in the game loop, it just has to print itself out. You know it's been called from within those two tags, and its doing exectutions when i can. Clear anything up?
Wade
I sort of asked this in a comment below: The SpriteBatch.Begin statement has overloads allowing you to set the SpriteBlendMode and global transformation matrix. I have no idea why I would want or need these, but I don't want to write a bunch of code and discover that I do need to mess with these parameters. Are these parameters set to the same value for all sprites drawn between the Begin/End pair or can they be changed on a sprite by sprite basis within the Begin/End call. If all sprites are drawn with the same value then calling at the higher level does not seem like the proper design.
Dunk
If i remember properly these are things that will be the same for all sprites drawn within the begin and end. You would have to have a separate begin end to change those around.If you want to do that, you may want to create a separate class that will mange that even. This is why XNA can get jumbled sometimes, its classes to do stuff that more classes manage, which are all managed by one class ;-)
Wade
+1  A: 

I’m assuming that creating a SpriteBatch instance for each object would cause too much overhead.

As the name imply, the SpriteBatch is used to organize a batch of sprites and draw them in a particular way in a buffer. When you call SpriteBatch.End(), the sprites added in the SpriteBatch are sorted (or not) and written in a buffer (ex: the screen) using a particular blend mode and other options specified before SpriteBatch.End().

When you call SpriteBatch.Begin(), you have to call SpriteBatch.End() before calling SpriteBatch.Begin() again (using the same SpriteBatch object).

So this code is wrong :

class Main
{
    private Ship ship;
    private SpriteBatch spriteBatch;

    //logic to create the ship/spriteBatch

    public override void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Begin();
        ship.Draw(spriteBatch);
        spriteBatch.End();
    }
}

class Ship
{
    private Texture2D image;

    //logic to create the image

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Begin();
        spriteBatch.Draw(image, Vector2.Zero, Color.White);
        spriteBatch.End();
    }
}

because spriteBatch.Begin is called twice. The right way to do it :

class Main
{
    private Ship ship;
    private SpriteBatch spriteBatch;

    //logic to create the ship/spriteBatch

    public override void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Begin();
        ship.Draw(spriteBatch);
        spriteBatch.End();
    }
}

class Ship
{
    private Texture2D image;

    //logic to create the image

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(image, Vector2.Zero, Color.White);
    }
}
Jodi
OK, you are recommending one top-level call to SpriteBatch.Begin and End. Is that a problem if you potentially have a LOT of objects to draw or is it not an issue?
Dunk
Also, will calling SpriteBatch.Begin at a high-level require all objects to use the same SpriteBlendMode and Transformation Matrix or can that be changed for each Draw statement.
Dunk
There is no performance hit to use only one spriteBatch to draw a lot of sprites. There is one when you use a lot of different textures (it's faster to have one texture with different images on it and use rectangles to specify which part you want to draw).Indeed, using only one spriteBatch constrains you to one transformation matrix and one blend mode. You can, however, modify the blend mode on-the-fly (http://blogs.msdn.com/shawnhar/archive/2007/01/02/spritebatch-and-custom-blend-modes.aspx) but it will still be applied to all the sprites in your spriteBatch.
Jodi
So even if I could tell if I was in the SpriteBatch.Begin and End pair, I still shouldn't use my original plan of having the containing objects call Draw on the contained objects as that will result in a lot of texture switches. Thanks for your help, I think I know what to do now that you and Wade have got me thinking in a slightly different way.
Dunk