Let’s Talk Textures!
The subject of today’s topic is one that is quite interesting to me and something you will probably spend sometime playing around with. I want to talk about Textures, specifically Texture2D class in the framework. If we’re going to talk about Textures, then we will have to talk about SpriteBatch as well since that’s the class we use to draw textures on the screen.
First off, what is a texture? In its simplest form, a texture is an image. It is known by many different names that probably do have slightly different interpretations, but to me they are somewhat the same: Bitmap, Image, Picture, Sprite, etc. If you look at a game like Street Fighter 2 for instance, that is what is called a 2 Dimensional game (2D) and is completely made up of “Sprite graphics”. Which are…textures.
What do you use Textures for?
Well, the simplest example is in 2D games. All the graphics on the screen are images that you move around to simulate a world and gameplay. Just like in my previous post where we created an image of a ball and moved it around using the keyboard.
Textures are also used in 3D graphics all the time. The are used to cover the models with colors and detail to give that final polished look of a car or character. Things such as T-shirts and patterns on a model are textures. Terrain is another place where textures shine in 3D graphics. Things such as grass, rocks, etc that cover land in a game are textures.
Textures in their most basic form are really 2D arrays of numbers. A number at position X,Y that says the color for this pixel is Yellow for instance. So you end up seeing game developers using Textures as 2D arrays in their games. They store data in there that is not meant as a picture at all, will even look weird if rendered, but they instead read that data on the graphics card to achieve some interesting effects on the game. We’ll eventually see some of that stuff as we get more “seasoned’.
Creating Textures
So how do you create textures? It’s really pretty simple. You can create textures using any of the widely available image editing programs such as Photoshop, Gimp, Paint.Net and even the Microsoft Paint program that’s included in Windows by default. Anything that can save as one of the popular image types such as jpg, bmp, png, etc will work just fine.
You can also create images programmatically! You won’t use that very often in a 2D game, but you’ll find a few scenarios here and there that might present themselves.
Let’s Play with Textures!
Let’s fire up our Visual Studio and start getting familiar with Textures and what we can do with them. Create an new Windows Game project and start messing with textures!
Let’s start by giving our game a nice cool background or backdrop. The image I will use for my backdrop is one that is part of the SpaceWar starter kit that comes with XNA Game Studio. It looks like this:
You can use this one too if you want. Save it to your hard drive and add it to your project. Mine is already in my project:
Now we use it!
Have a variable declared for it:
Texture2D background;
Load it (line 5):
1: protected override void LoadContent()
2: {
3: // Create a new SpriteBatch, which can be used to draw textures.
4: spriteBatch = new SpriteBatch(GraphicsDevice);
5: background = Content.Load<Texture2D>(“B1_nebula01″);
6: }
Render it (lines 5,6,7):
1: protected override void Draw(GameTime gameTime)
2: {
3: graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
4:
5: spriteBatch.Begin();
6: spriteBatch.Draw(background, Vector2.Zero, Color.White);
7: spriteBatch.End();
8:
9: base.Draw(gameTime);
10: }
Tip: Did you notice the little trickery that is in line 6? I wanted to position the image at coordinates 0,0 of the game window. I could have said “new Vector2(0,0)”, but why would I do that when Vector2 class has a nice “.Zero” static method on it that returns a (0,0) Vector2. You’ll find a similar method on Vector3 and Vector4 as well.
Hit the magic F5 key and let’s have a look at the awesomeness we just created:
Oh! Come on!!! The image doesn’t fit the window size correctly. Now what? I can do one of 3 things:
- Resize the image in some image editor to make it fit
- Resize the Window to make that fit the image
- Scale the image in the Window to make it stretch out and fit any window size.
Alright, I’ll go with option #3 since it’s easy and will work with whatever size window we have from now on. So how do we do that? SpriteBatch.Draw method has a lot of overloads, so let’s see if it has something that can help. Sure enough, it has a method that can take a Rectangle that defines the destination area to draw the image in. This will work just fine! Here’s the code:
1: protected override void Draw(GameTime gameTime)
2: {
3: graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
4:
5: Rectangle rect;
6: rect.X = 0;
7: rect.Y = 0;
8: rect.Width = graphics.GraphicsDevice.Viewport.Width;
9: rect.Height = graphics.GraphicsDevice.Viewport.Height;
10:
11: spriteBatch.Begin();
12: spriteBatch.Draw(background, rect, Color.White);
13: spriteBatch.End();
14:
15: base.Draw(gameTime);
16: }
Alright, so what’s happening here?
Rectangle Struct defines a rectangle area by the X and Y coordinates on screen and a Width and Height to use. We already know that we want the image to start from (x,y) = (0,0) which is the top left corner of the screen. Now all we need to do is have it extend to the width and height of the screen and we’re golden. How do we get the Width and Height of the screen in XNA? check out lines 8 and 9. They use:
graphics.GraphicsDevice.Viewport
This class contains a lot of information regarding the details of the screen we’re drawing to right now on the graphics card. It has a Width and Height property on it which are exactly what we need. We set them on the Rectangle struct and use that in the Draw method of SpriteBatch instead of the Vector2.Zero part. Again, hit F5 and you should see:
Much nicer! Granted, the image is stretched out a bit and may not look good with other backdrops, but it looks fine with this one.
Taking it one step further
Ok, so now that we learned a bit more about textures and how we can resize them as we draw them, let’s learn about what we can do to mess with how they look a bit. And since now we know how to render textures on screen pretty easily, you can use my previous post to render the ball on top of this back drop since we’ll use it in the coming part.
So right now, my code that includes the ball looks like this:
1: protected override void Draw(GameTime gameTime)
2: {
3: graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
4:
5: Rectangle rect;
6: rect.X = 0;
7: rect.Y = 0;
8: rect.Width = graphics.GraphicsDevice.Viewport.Width;
9: rect.Height = graphics.GraphicsDevice.Viewport.Height;
10:
11: spriteBatch.Begin();
12: spriteBatch.Draw(background, rect, Color.White);
13: spriteBatch.Draw(ball, Vector2.Zero, Color.White);
14: spriteBatch.End();
15:
16: base.Draw(gameTime);
17: }
Line 13 is responsible for rendering the ball. Hit F5 and you should see something like this:![]()
Attention: Notice how the order of call between the Begin and End of SpriteBatch matters? It will draw the textures on top of each other based on that order. If you reverse the order of drawing of the backdrop and the ball, you won’t see the ball anymore.
So let’s say that this is a game that I am making, and after a while, the ball gets some damage or something and we want to change its color to indicate that something happened to it. How do we do that? We can use another texture that is of that color I guess, but there is an easier way:
1: spriteBatch.Draw(ball, Vector2.Zero, Color.Red);
This is how I am rendering the ball now. Instead of using Color.White which means “draw as is”, I am using Color.Red which means mix the colors of the texture with the color red. In this case, adding Red to White will give you Red:
There you go! We changed the color of the ball with a simple change in how we draw it. You can imagine making the Color argument of the Draw method a variable in your code. You can then change its value in the Update method of your game based on whatever criteria you come up with and the Draw call will always pick up that new value. In a simple fighting game I prototyped, I would add a red tint to my fighter’s colors for 1 second or so to indicate that he was hit by the other player.
Ok! That’s it for today! Next time I’ll talk some more about textures and get into how you can animate them! Getting closer to making games!
Thanks for reading! I'd love to hear your thoughts, feel free to leave a comment below. Don't forget to subscribe to my RSS Feed!
December 6th, 2007 at 4:09 pm
Hi Nazeeh,
Thank you for creating a new resource for XNA development. I am not sure what your plans are but I would like to suggest that you begin creating some more advanced articles. It seems that everyone who writes about XNA wants to cover the most basic aspects. 2D textures have been covered to death. How about some fundamentals of 3D or engine design?
That would keep me coming back to your site.
December 6th, 2007 at 4:29 pm
Thank you for your feedback!
So far my plans are to cater for people that have never done any game development at all. As I was learning, and still am, a lot of the basics were not fully covered. There were always gaps that frustrated me. I hope to cover that stuff as I move on to the more advanced stuff.
I really do appreciate the feedback though! For now, I leave the advanced stuff to the insanely capable hands of Shawn Hargreaves :)
March 1st, 2008 at 4:39 pm
Greaaaat tutorials!
Most tutorials on the web indeed jump too far too quick to my taste - I like to feel im grasping everything that is going on. But I have to agree with Robert, same level 3D tutorials are impossible to find :( So publishing a few of those would be extremly helpful.
Thanx a again :D