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

XNA Tile Engine Part 4

Icon Leave Comment
In today's post I will be continuing on with the tile engine series. This is the fourth part in my tile engine series. The tile engine is working fairly well but at the moment the tile engine is very inefficient. For one it is drawing all of the tiles that are in the map. It would be better to have the tile engine just draw the tiles that are visible. Also creating a new Rectangle object each time a tile is drawn is inefficient because when you create objects you are using a lot of code and are allocating memory. When the object is no longer needed the garbage collector comes and removes it. You can get around that by creating one rectangle before the rendering code and changing the X and Y properties of the rectangle as that is all that changes. That would be much more efficient.

To have the tile engine just draw the visible tiles you would need a way to find out which tile the camera is in. To do that I created a method called VectorToCell. This method will take as a parameter a Vector2 and return a Point. A Point is like a Vector2 but instead of the X and Y properties being floats they are integers. The X and Y properties of the X and Y coordinates of the tile in the map. To find out which tile the vector is in you would take the X value of the vector and divide it by the width of the tile and cast the result as an integer. For the Y value you would use the height of the tile. The width and height are of course the width and height of the tiles on the screen, not their physical width and height. This is the code for the method.

        private Point VectorToCell(Vector2 vector)
        {
            return new Point(
                        (int)(vector.X / tileWidth),
                        (int)(vector.Y / tileHeight));
        }



I will need a helper method for the rendering code. I will quite often need to know the width of the screen width plus the width of one tile and the height of the screen plus the height of one tile. I will need to know this to find out when to stop rendering the tiles. The reason I add in the width and height of a tile is if you just use the screen width and the screen height when you scroll the map the background will show through so you need to add in an extra tile. I will return a Vector2 that holds the screen width plus the tile width and the screen height and the tile height. This is the code for the helper method that I called ViewPortVector.

private Vector2 ViewPortVector()
{
    return new Vector2(
            screenWidth + tileWidth,
            screenHeight + tileHeight);
}



The code for rendering the tile map has changed a lot. I am also going to refractor things a little. I’m going to separate the code that renders the map into a method of its own called DrawMap. This is the code for the updated Draw method and the DrawMap method.

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

    DrawMap();

    base.Draw(gameTime);

}

private void DrawMap()
{
    Point cameraPoint = VectorToCell(camera.Position);
    Point viewPoint = VectorToCell(camera.Position +
                        ViewPortVector());

    Point min = new Point();
    Point max = new Point();

    min.X = cameraPoint.X;
    min.Y = cameraPoint.Y;
    max.X = (int)Math.Min(viewPoint.X, map.GetLength(1));
    max.Y = (int)Math.Min(viewPoint.Y, map.GetLength(0));

    Rectangle tileRectangle = new Rectangle(
            0,
            0,
            tileWidth,
            tileHeight);

    spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

    for (int y = min.Y; y < max.Y; y++)
    {
        for (int x = min.X; x < max.X; x++)
        {
            tileRectangle.X = x * tileWidth - (int)camera.Position.X;
            tileRectangle.Y = y * tileHeight - (int)camera.Position.Y;
            spriteBatch.Draw(tiles[map[y, x]],
                tileRectangle,
                Color.White);
        }
    }

    spriteBatch.End();
}



The Draw method now just calls the new method DrawMap. In the DrawMap method I do all of the rendering. The first thing that I do in the DrawMap method is take the camera’s position and find out what tile it is in. Next I find what tile the camera’s position plus the ViewPortVector would be. Next there are two local variables min and max of type Point. The min variable is set to be the cameraPoint and will hold the tile to start rendering with. The find the max variable I used the Math.Min method. That method will return the minimum value of the two values passed in. The reason I used the Math.Min method is because the ViewPortVector will hold the size of the screen plus one tile. If I try and render that when the camera is at its maximum position plus one tile it will cause an exception. If I get the minimum of the view point X property and the width of the map I will not try and render past the right edge of the map. To keep from trying to render past the bottom of the map I get the minimum value of the Y property of the view point and the height of the map.

Next I create a Rectangle object, tileRectangle that has as its Width and Height properties the width of the tiles on the screen and the height of the tiles on the screen. Then I call the Begin method. The for loop that loops through the Y values of the maps goes from min.Y to max.Y. The loop for the X values loops from min.X to min.Y. I find the X property of the tileRectangle just like before. I take x and multiply it by the width of the tile and subtract the X property of the camera’s position. For the Y property I take y and multiply it by the height of the tile and subtract the Y property of the camera’s position. The I call the Draw method of spriteBatch with the tileRectangle object.

0 Comments On This Entry

 

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)