Moving Stuff Around in XNA!
In my last post, we created a very simple “Hello World” game in XNA. It wasn’t anything fancy, but it served the purpose of introducing XNA project template and getting us familiar with what’s in the code. But let’s face it, it wasn’t a game… not even close to being one. Putting text on the screen that doesn’t move is quite boring. Time to spice things up a bit and get to learn about user input while we’re at it.
You can reuse the project we created from last post if you want, or create a new one. Whichever is fine by me! Instead of boring text, we’ll use some “graphics” this time. I use the term “graphics” very loosely since the best I could come up with was this little image:
Yes, not very exciting eh? It’s just a ball. You can use any image you want, you can even right click on this one and save it to your PC and use it. It’s all good. Just get an image, one that is not too big though, this one is 200×200 pixels. I saved this one as ball.png.
Tip: The reason why I saved this as a .png file is to preserve transparency. The image is actually square in shape. But the area around the circle is transparent, hence why you can’t see it. I used Paint.Net to create the image and save it as a png. We’ll learn more about images and transparency later. So don’t worry too much about it now. Make a quick stop at my “Preparing your toolbox!” post to get a list of the tools I use, including Paint.Net.
Ok, so now you should have your image file ready to use. As I said, mine is called ball.png. Once I have the project created, I went ahead and added the image to my Content folder:
This time, we’re adding an Existing Item vs a New Item. You’ll get a regular “Add Existing Item” dialog, find your image file and click on the Add button to add it to your Content project.
Tip: If you take a closer look at the Add button, you’ll notice a little arrow on it. Clicking that arrow will expand the button to show a menu:
Picking “Add” will add a COPY of the file to your project. Picking “Add As Link” will add a LINK to the file in your project. Why do you care? well, if you use Add as Link option, you can still make changes to the image and not have to worry about either recopying it to your Content folder or modifying the now newly copied version instead. The bad thing though is that if you forget and then send the source code to someone else, they won’t have the linked image and will fail building the game.
I use Add most of the time to avoid that, just need to remember to re-open the new copy in my editing program if I need to modify it.
Ok, so now you should have the new file in your Content folder. Mine looks like this:
Now let’s add the required code to load it up. All code is in Game1.cs.
First thing you want to do is add a Texture2D that we will use to load the image into. While you’re at it, add a Vector2 variable that we can use to track where to place the ball on the screen. My code looks like this: (see lines 3 & 4)
1: GraphicsDeviceManager graphics;
2: SpriteBatch spriteBatch;
3: Texture2D ball;
4: Vector2 ballPosition;
In the Initialize method, I will instantiate ballPosition and give it an initial value: (line 3)
1: protected override void Initialize()
2: {
3: ballPosition = new Vector2(20, 20);
4: base.Initialize();
5: }
Nice! Now let’s load the image in the Texture2D we created: (line 7)
1: protected override void LoadContent()
2: {
3: // Create a new SpriteBatch, which can be used to draw textures.
4: spriteBatch = new SpriteBatch(GraphicsDevice);
5:
6: // load our image
7: ball = Content.Load<Texture2D>(“ball”);
8: }
And finally, let’s render it just like we did for the “Hello World” example:
1: protected override void Draw(GameTime gameTime)
2: {
3: graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
4:
5: spriteBatch.Begin();
6: spriteBatch.Draw(ball, ballPosition, Color.White);
7: spriteBatch.End();
8:
9: base.Draw(gameTime);
10: }
Few things to note here: (line 6)
- See how we’re using spriteBatch.Draw this time vs DrawString? That’s because we’re Drawing an image.
- We are using ballPosition as the position on the screen to draw the ball at. We are not creating a new Vector2 everytime. Much cleaner and will be useful in the coming part.
- We use Color.White as the Color to use to draw the image with. That means “Draw the image as is, don’t mess with the colors at all!”. If you specify something like Color.Yellow, the image will have a Yellow-ish tint to it. Using Color.White is what you want unless you want to mess with the colors.
Alright! There you go! Hit F5 and you will see your image rendered as expected! Neat eh?
Moving the Image Around
While rendering an image is cool and all, let’s take it a step further and let the game allow the user to move that ball around! Time to add some user input!
So how do we do that? I would like to use the keyboard arrow keys to move the ball up, down, left and right. So we will need to somehow read what keys the user is pressing now and then change the position of the ball to match the direction they are pressing. This turns out to be super easy to do!
First though, we need to figure out where we’ll put this code in our project. This is something we want to do on a regular basis. Something that will update the position of the ball on the screen. So we’ll put the code in the Update method of course!
1: protected override void Update(GameTime gameTime)
2: {
3: // Allows the game to exit
4: if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
5: this.Exit();
6:
7: KeyboardState keyboardState = Keyboard.GetState();
8:
9: if (keyboardState.IsKeyDown(Keys.Up))
10: {
11: ballPosition.Y -= 5;
12: }
13:
14: if (keyboardState.IsKeyDown(Keys.Down))
15: {
16: ballPosition.Y += 5;
17: }
18:
19: if (keyboardState.IsKeyDown(Keys.Left))
20: {
21: ballPosition.X -= 5;
22: }
23:
24: if (keyboardState.IsKeyDown(Keys.Right))
25: {
26: ballPosition.X += 5;
27: }
28:
29:
30: // TODO: Add your update logic here
31:
32: base.Update(gameTime);
33: }
This is it! Let’s have a closer look, shall we?
- For now, ignore lines 4 & 5 which are the default code in that method. They just let you press the Back button on a Xbox 360 gamepad that is connected to your PC to exit the game.
- Line 7: To get information on what keys are pressed, you want to talk to the Keyboard. To do that you use the Keyboard class from the framework. You ask it to return to you a snapshot of the state of the keyboard at the time you made the call. So you use Keyboard.GetState() which returns a KeyboardState object. This object has all the information about which keys are currently pressed, released, etc at the time of the call. Hence the “snapshot”.
- I assigned keyboardState to hold the return value from Keyboard.GetState()
- Lines 9 - 27: Now we start to see what keys are pressed. The basic idea is to see which key is pressed and update the X or Y of ballPosition to match that direction.
- Remember, incrementing the Y value means move position downward and incrementing the X means go right.
- Should be clear now what we’re doing. We are checking which key is pressed and moving the ball in the corresponding direction (for instance, left arrow means move to the left which means decrement the X) and we change the value by adding or subtracting 5 pixels.
That’s it! You’re done! Hit F5 and when the game comes up, move your image around using the up/down/left/right arrow keys on your keyboard! See? things are starting to look like a game…kinda. We’ll get there!
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 27th, 2007 at 6:09 pm
When the ball moves, I feel like its motion judder from time to time. I can fix this quickly by
this.IsFixedTimeStep = false;
but just wondering if I would like to run it with this.IsFixedTimeStep = true, how to make it less judder.
December 29th, 2007 at 3:33 pm
How many pixels are you moving it by every frame? It would jitter if the value it too big. The effect goes away when you put isfixedTimeStep = false since update will be called way more and will eat up the effect of the large value.