Subscribe to Six's Game Programming Adventures        RSS Feed
-----

XNA Tile Engine Part 2

Icon 1 Comments
In today’s entry I will get started with scrolling a tile map in just cardinal directions. What I mean by cardinal directions is that the map will only scroll left, right, up or down and not on diagonals. So you will want to go a head and load your previous project to continue.

To scroll the map you will have to be able to get input from the user. I will just be using keyboard input at the moment. So you will need a variable in the game to detect key presses. If you have been following along with my blog you will know that is done using a KeyboardState object. So go a head and add this class level variable.

        KeyboardState currentState;



To control the scrolling I will use a 2D camera system. Today I will just introduce the idea but in another post I will make a class for the camera as I’m a firm believer in object-oriented programming. For now you will need three variables. One for the X position of the camera, measured in pixels, the Y position of the camera, again measured in pixels and finally the speed at which the map will scroll. Add the following three variables to the class.

        int cameraPositionX;
        int cameraPositionY;
        int cameraSpeed = 4;


Processing the keyboard input is done in the Update method. What I will be doing is checking to see if just the Up, Left, Down or Right arrow keys are being pressed. I will be doing this using if-else ifs. This is the code for the Update method. I will explain it in a moment.

        protected override void Update(GameTime gameTime)
        {
            currentState = Keyboard.GetState();

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (currentState.IsKeyDown(Keys.Up))
                ScrollUp();
            else if (currentState.IsKeyDown(Keys.Left))
                ScrollLeft();
            else if (currentState.IsKeyDown(Keys.Down))
                ScrollDown();
            else if (currentState.IsKeyDown(Keys.Right))
                ScrollRight();
            
            base.Update(gameTime);
        }



The first thing you need to do is get the current state of the keyboard. You do that using a static method of the Keyboard class called GetState. After I have the state of the keyboard I use the IsKeyDown method of the KeyboardState class to check if one of the keys I’m interested in is down. The if-esle-if statements will first call a method ScrollUp, that I will write in a moment, if the Up key has being pressed. If the Up key is not being pressed and the Left key is I call the method ScrollLeft. Nect if the Up key and the Left key are not currently being pressed but the Down key is I call ScrollDown. Finally if none of the arrow keys but the Right key are being pressed I call ScrollRight.

All of the methods for scrolling the map are basically the same. They change the cameraPosition variable that is appropritate to move the camera. To move the camera up you need to subtract a value from the cameraPositionY variable because the Y axis grows bigger as you move down the screen from the top of the screen. That means to move the camera down the screen you add a value to the cameraPositionY variable. You do the same sort of thing for moving the camera left and right. To move the camera left you need to subtract a value from the cameraPositionX variable because the X axis grows bigger as you move from left to right. To move the camera right you need to add a value to the cameraPositionX variable. This is the code for the Scroll methods.

        private void ScrollRight()
        {
            cameraPositionX += cameraSpeed;
        }

        private void ScrollDown()
        {
            cameraPositionY += cameraSpeed;
        }

        private void ScrollLeft()
        {
            cameraPositionX -= cameraSpeed;
        }

        private void ScrollUp()
        {
            cameraPositionY -= cameraSpeed;
        }



Now that we have the camera moving we need to Draw the map related to the position of the camera. This is a little counter intuitive to tell the truth. You would think that you would add the position of the camera to the X and Y values of the destination rectangle to find out where to draw the tile. It is, in fact, reversed. You need to subtract the position of the camera to find out where to draw the tile. This is the updated Draw method that will show your map scrolling.

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

            for (int y = 0; y < map.GetLength(0); y++)
            {
                for (int x = 0; x < map.GetLength(1); x++)
                {
                    spriteBatch.Draw(tiles[map[y, x]],
                        new Rectangle(
                            x * tileWidht - cameraPositionX,
                            y * tileHeight - cameraPositionY,
                            tileWidht,
                            tileHeight),
                        Color.White);
                }
            }

            base.Draw(gameTime);

            spriteBatch.End();
        }



Go a head and run the program. You will notice that you can scroll off the edges of the map, as shown in this screen shot. (Again, sorry if the image loads slowly.)

Posted Image

To fix this problem I will write a method called LockCamera that will keep the player from being able to scroll the map off the edges. I will give you the code for the method and then explain it.

    private void LockCamera()
    {
        cameraPositionX = (int)MathHelper.Clamp(
            cameraPositionX, 0,
            tileWidth * map.GetLength(1) - GraphicsDevice.Viewport.Width);
        cameraPositionY = (int)MathHelper.Clamp(
            cameraPositionY, 0,
            tileHeight * map.GetLength(0) - GraphicsDevice.Viewport.Height);
    }



I used the MathHelper.Clamp method. If you are unfamiliar with that method it will take a value and make sure that it is not greater than the minimum value and not greater than the maximum value.

So for the cameraPositionX value I pass cameraPositionX to MatherHelper.Clamp. The minimum X value for the camera is of course 0. To restrict the camera from going off the right edge of the map is a little trickier. First you will need the width of the map in pixels. To find the width of the map in pixels I take the tile width and multiply it by the length of the array passing in 1 to the Length method. Since you subtract the position of the camera to find out the coordinates of where to draw the tile you subtract the width of what you are drawing. I used the Viewport property of the GraphicsDevice class to find the width of the window. Since MathHelper.Clamp returns a float I needed to cast it into and integer.

For the cameraPositionY value I pass cameraPositionY to MathHelper.Clamp. Again the minimum value is 0. I use a similar procedure to find out where to keep the map from scrolling off the screen. I need to find the height of the map in pixels. I do that by multiplying the tile height by the number of tiles high the map is. I use the Viewport property of the GraphicsDecvice class to find the height of the screen. To keep the screen from scrolling off the bottom of the screen I subtract the height of the screen.

That is it for this entry. In the next entry I will make a class for the camera and have the map scroll smoothly and uniformaly in all directions.

~Six

1 Comments On This Entry

Page 1 of 1

Hellbroth 

11 November 2009 - 09:46 AM
Everything perfect :D

I thought it wasn't working but i forgot to call the Lockcamera() function in the draw method.
My fault.

It should look like this :

protected override void Draw(GameTime gameTime)
		{
			GraphicsDevice.Clear(Color.CornflowerBlue);
			spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
			// TODO: Add your drawing code here
			LockCamera();
			for (int y = 0; y < map.GetLength(0); y++)
			{
				for (int x = 0; x < map.GetLength(1); x++)
				{
					spriteBatch.Draw(tiles[map[y, x]],
						new Rectangle(
							x * tileWidth -cameraPositionX,
							y * tileHeight - cameraPositionY,
							tileWidth,
							tileHeight),
						Color.White);
				}
			}
			spriteBatch.End();

			base.Draw(gameTime);
		}

0
Page 1 of 1

February 2022

S M T W T F S
  12345
6 7 89101112
13141516171819
20212223242526
2728     

Recent Entries

Recent Comments

Search My Blog

0 user(s) viewing

0 Guests
0 member(s)
0 anonymous member(s)