Friday, September 07, 2007

Advanced Sprite Drawing

In this tutorial, I will talk about how you can draw a sprite with more effects applied to the sprite than just a color to taint the sprite with.

What we need to do is call the draw method of the our SpriteBatch variable, but just fill in a few more parameters.

You may ask, "But how can a method have different amounts of parameters and still be the same method?". This is possible with a thing called overloading. If you overload a method, you create a method with the same name as the method you are overloading, but you create the method so that it takes a different amount of parameters. Method overloading is useful for making it easier for the user to use the method.

Example: Pretend you have a method that explodes a ship called Explode. This method needs a Ship class as a parameter so that it can explode that ship and an intensity for the ship to explode at.

//This is the original method
private void Explode(Ship shipVariable, int explosionIntensity)
{
//Code that explodes the ship.
}

For your game, 99/100 explosions occur with a 100/1000 intensity. Method overloading comes in here. For that 1 ship that needs a 200/1000 intensity explosion, you have the orginal Explode method which allows you to pass in the ship to explode, and the intensity of the explosion. But now you want an easier way to explode you 99 ships that all have a 100/1000 intensity explosion. You can create an overload of the Explode method that only takes one parameter, the ship to explode, and then passes in 100 as a default value for the intensity:

//Overload of original Explode method
private void Explode(Ship shipVariable)
{
//Call the other Explode method and pass in the
//shipVariable it got as a parameter, and then 100 as the
//
default explosion intensity
Explode(shipVariable, 100);
}

You can see how method overloading makes it easier for the user to use the method because now, since 99/100 of your ships use the default explosion intensity which is 100/1000, instead of always calling Explode(shipVariable, 100);, you can just call Explode(shipVariable);

I hope that made sense to you but if you don't get it you may get it more along the tutorial or sometime later.

Now, since I explained all that to you, I am going to show you where it is actually used.

In the mySpriteBatch.Draw call we passed in three parameters, a Texture2D to draw, a Vector2 position, and a Color to taint the sprite with. This was good for our purpose because we didn't really want to change anything on the sprite. Well, now we do want to change the attributes of the sprite. The Draw method of the SpriteBatch class has several overloads. In fact, you can see all the overloads by typing or re-typing the first parenthesis of the Draw method call. A tan box should appear(we used this in the second tutorial), but this time we will use this to find how many overloads the method has. In the top right corner you can see 1 of 7. This shows that you are on method overload one out of seven different method overloads. If you push the up or down arrow keys you can see what parameters are needed for this method overload. If you haven't found for yourself by now, we are currently using method overload two. This takes a Texture2D, a Vector2, and a Color.

Figure 1-1 The Tan Box Showing the Current Method Overload and Parameters Needed

For what we want to do we will use overload number six which is one of the overloads that allows the most options to change the way the sprite is drawn. I will explain what all of the overloads we are using mean, and then I will get along with the code.

Texture2D texture
This parameter is asking for the texture to draw on the screen.

Default value: There is no default, you have to give the texture in all overloads.

Vector2 position
This parameter is asking for the position to draw the sprite on the screen at.

Default value: There is no default, you have to give the position in all overloads. In some cases you may use a rectangle that holds the position instead though.

Rectangle sourceRectangle
This parameter is asking for the rectangle out of the texture you want to draw. For example. pretend you have a texture that has all the button images in the game on it. If you wanted to draw only one part of that image, you would specify the size and position for that rectangle to be at on the texture. If you want to use the whole image, you can pass in null instead which means nothing so the whole image whill be drawn.

Default value: null

Color color
This parameter specifies what color to taint the sprite with, i.e. orange maybe if the sprite is the player and blue if the sprite is any enemy.

Default value: There is no default, you have to give the color in all overloads. If you don't want any color to be applied to your sprite though, then just use Color.White.

float rotation
This parameter specifies how much you want the sprite to be rotated by.

Default value: 0.0f

Vector2 origin
This parameter specifies the main point for the sprite. If the origin is the center of the sprite, when you draw the sprite, the sprite will be drawn around the center point which means the position you specify for the sprite to be drawn at will refer to the center of the sprite.

Default value: 0, 0 (the top left corner)

float scale
This parameter sets how much you want the sprite to be scaled by.

Default value: 1 (if you put 0 the sprite will end up as small as nothing because you are multiplying your sprites original size by zero which always gives zero.)

SpriteEffects effects
This parameter specifies which type of sprite effects you want applied to your image. You can flip horizontally, vertically, or just do nothing.

Default value: SpriteEffects.None

float layerDepth
This parameter specifies the depth position of your sprite. This is useful for making certain sprites appear on top of eachother.

Default value: It depends on which order your sprite is drawn at out of all the other sprites. Sometimes the last sprite drawn appears on top of the others and sometimes the sprite drawn first appears on top. It depends on which sort mode you pass into the second or third overload of spriteBatchVariable.Begin. We are not using the second or third overload so the default value is SpriteSortMode.BackToFront.

That was the last parameter for the overload of Draw that we are using. Now we can get to some code. You can mostly test the different parameters on your own, I don't have to explain what they do because you can probably figure out, but, I will show you a few things.

First run your project. Now click the mouse and the sprite should move to that position. If you look closely though, you will see that the top left corner of the sprite is going to the position where you clicked. That is because we are not specifying an origin for the sprite. If we want to change where the sprite goes to, you must change the origin for that sprite.

Change the call to draw the second texture to look like this:

mySpriteBatch.Draw(myTexture2, spritePosition2, null, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0);

This code draws the exact same thing we had before. All the parameter values we have now are the default values they would been. This is not so useful to us now, until we want to change anything.

Note: In the code above, we used Vector2.Zero which is accesssing a value that the Vector2 class has in it. This is the same as using new Vector2(0, 0);

Now we can actually do something. Since our origin is still 0, 0, the sprite will still be drawn with the top-left corner of the sprite drawn at spritePosition2. Instead of using Vector2.Zero for our origin parameter, we will use this: new Vector2(myTexture2.Width / 2, myTexture2.Height / 2);

This gives our sprite an origin that refers to the center of the sprite.

Now run the project. If you press the left mouse button, the sprite will be moved to where you clicked but the center of the sprite will be moved to the position of the mouse.

For the next test, I will show you how to use the source rectangle. For this rectangle, you are specifying what part of the texture you want to be drawn. For an example, just put this line instead of null: new Rectangle(0, 0, 50, 50);

This is creating a rectangle that starts from the top left corner of your texture, and has a width and height of 50 pixels. Run the project now. You should see only a 50 pixel square of the texture.

Figure 1-2 The Source Rectangle Example

That was just an example, so change the source rectangle parameter back to null.

For the last example, I will show you how to rotate the sprite correctly. You may think, "Well all I have to do is type in a number and the sprite will rotate by that many degrees."

This is incorrect thinking. When you type in a number, the sprite is not rotated in degrees. Type in, 45, for the rotation value. You should see that the sprite is not rotated by 45 degrees, but in radians. Now type in this instead: MathHelper.ToRadians(45); This draws your sprite at a rotation relative to the number you put in. Now run the project. You should see the sprite is rotated exactly by 45 degrees.

Note: When you put in, 45, as a parameter for the ToRadians method, you are not actually drawing the sprite in degrees. Whats happening is, you are converting a value that is in degrees, into a value in radians. You can also use MathHelper.ToDegrees(MathHelper.ToRadians(45)) which converts a radian value into a degree again.

Figure 1-3 The Correctly Rotated Sprite

Again, erase the value for rotation and put 0.

Now you know a little more about how sprites are drawn. You also know about method overloading.

Figure 1-4 The Code That Draws the Second Texture

Figure 1-5 The Complete Tutorial. Nothing Much Different That You Can See

Note: If you want you can change the values of other parameters to see what they do. Make sure to change everything back to the way it is now though, when you are done testing.

If you have any questions or requests, please post a comment and I will try to answer.

Thanks for reading the tutorial.

Be a hero: Don't conform; Be selfless; Make a difference

No comments: