What is an efficient way to draw sprites in my 2D XNA game? To be more concrete, I have split this question up into 4 questions.
I used to declare Game1's spriteBatch static, and called SpriteBatch.Begin
and .Close
in every IDrawable.Draw
. That didn't work well. Giving each drawable it's own SpriteBatch also didn't work well.
Q1: I assume it's best to have one SpriteBatch instance, and only call begin/close once. Is this correct?
Currently, my Game1.Draw
looks something like this:
spriteBatch.Begin();
base.Draw(gameTime); // draws elements of Game.Components
// ...
spriteBatch.End();
Q2: This way, Begin
is called only once. Is this the way to go? How did you guys solve this?
Q3: Also, every component has it's own IGameComponent.LoadContent
method. Am I supposed to load my content there? Or is it better to load content at a parent class, such as Game1.LoadContent
?
I realise that I should never load the same content twice, so I have given my drawable components both a static and a non-static Texture2D
, and gave them 2 constructors:
static Texture2D defaultTexture;
public Texture2D MyTexture;
public Enemy()
: this(defaultTexture) { }
public Enemy(Texture2D texture)
{
MyTexture = texture;
}
protected override void LoadContent()
{
if (MyTexture == null)
{
if (defaultTexture == null)
{
defaultTexture = Content.Load<Texture2D>("enemy");
}
MyTexture = defaultTexture;
}
}
This way, the default textures of a class are only loaded the first time LoadContent
is called on that class. However, when the parameter texture
is specified in the constructor, I'll have to load that texture beforehand.
Q4: I think there should be better ways to do this. I'm thinking of creating a texture dictionary with their asset names as string. What would you suggest?
I used to declare Game1's spriteBatch static
You don't have to have it static. Just make a singleton. Inside Draw
method
SpriteBatch spriteBatch = ScreenManager.SpriteBatch; // singletion SpriteBatch
spriteBatch.Begin();
// Draw the background
spriteBatch.Draw(background, ...
foreach (var enemy in enemys)
{
enemy.Draw(gameTime);
}
// etc.
spriteBatch.End(); // call here end
base.Draw(gameTime); // and then call the base class
I assume it's best to have one SpriteBatch instance, and only call begin/close once. Is this correct?
I advice you to open and end the SpriteBatch
within one method. It will help you avoid conflicts with SpriteBatch
that started drawing, but didn't finish.
Are you adding your elements to the global collection of components? This is a bad idea to add drawable to this collection. You cannot control the order of drawing, the components are global. See this answer.
Implement in your components IUpdatable and IDrawable and call them in your code where you need it. Get rid of the static stuff and use Dependency Injection istead.
Also, every component has it's own IGameComponent.LoadContent method. Am I supposed to load my content there? Or is it better to load content at a parent class, such as Game1.LoadContent?
You should load assets when you need it and you are responsible for it. You don'y have to load all 30 levels when user just started the game, do you? For example, when your game starts you load all assets that you need for your start screen and main menu. If you load just what you need the player is happy that game starts fast. Then player wants to start the gameplay. Here you can load the assets on a separate thread to keep the app responsive.
I think there should be better ways to do this. I'm thinking of creating a texture dictionary with their asset names as string. What would you suggest?
Content.Load
is cached already, so you don't have to do it.
as far as can be gleaned from tutorials around
calling begin and end only once is the preferred method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With