0
\$\begingroup\$

I am trying to change the way I scroll through a level. Currently I have a static camera class which stores a direction enum and a vector 2 position. This class then has a method to move the position of the camera (vecotr2) based on the direction value. This is called in the update method. Then when drawing my tile grid I loop through the number of visible tiles in the viewport and add the position of the camera to the counters to get the texture of the tile in question to draw. (note the main game class calls the level draw class passing it the sprite batch after starting it)

This seems like a pretty bad approach. I have seen in a few place that I should be using a matrix transformation to move the camera and then pass this as part of the draw method. However, I have absolutely no idea how to achieve this, I am literally lost.

I have attached my code below, and would greatly appreciate any advice you could provide.

Camera:

// Stores the position and scroll direction of the camera. static class Camera {

static public Vector2 Position;

static public ScrollDirection Direction;

public static void MoveCamera(Level level) {
    Vector2 scrollSpeed = new Vector2(20, 18);
    if (Camera.Direction == ScrollDirection.Up)
    {
        Camera.Position.Y = MathHelper.Clamp(Camera.Position.Y - scrollSpeed.Y, 0, (level.Height * 50 - level.mViewport.Height));
    }
    else if (Camera.Direction == ScrollDirection.Down)
    {
        Camera.Position.Y = MathHelper.Clamp(Camera.Position.Y + scrollSpeed.Y, 0, (level.Height * 50 - level.mViewport.Height));
    }
    else if (Camera.Direction == ScrollDirection.Right)
    {
        Camera.Position.X = MathHelper.Clamp(Camera.Position.X + scrollSpeed.X, 0, (level.Width * 50 - level.mViewport.Width));
    }
    else if (Camera.Direction == ScrollDirection.Left)
    {
        Camera.Position.X = MathHelper.Clamp(Camera.Position.X - scrollSpeed.X, 0, (level.Width * 50 - level.mViewport.Width));
    }
}

}

Level:

public void DrawTiles(SpriteBatch spriteBatch) {
    // Calculate the position of the camera in terms of tiles. 
    Vector2 cameraPosition = new Vector2(Camera.Position.X / Tile.Width, Camera.Position.Y / Tile.Height);
    // Calculate the offset of the camera position for when it is part way through a tile.
    Vector2 cameraOffset = new Vector2(Camera.Position.X % Tile.Width, Camera.Position.Y % Tile.Height);

    // Loop through the number of visible tiles.
    for (int y = 0; y <= mViewportTiles.Y; y++) {
        for (int x = 0; x <= mViewportTiles.X; x++) {
            // Check that we have not exceeded the dimensions of the level.
            if (x + cameraPosition.X < Width && y + cameraPosition.Y < Height) {
                // If the tile is not an empty space.
                if (tiles[x + (int)cameraPosition.X, y + (int)cameraPosition.Y].Texture != null) {
                    // Get the position of the visible tile within the viewport by multiplying the counters by the tile dimensions
                    // and subtracting the camera offset values incase the position of the camera means only part of a tile is visible.
                    Vector2 tilePosition = new Vector2(x * Tile.Width - cameraOffset.X, y * Tile.Height - cameraOffset.Y);
                    // Draw the correct tile based on the position of the camera in the appropriate position within the viewport.
                    spriteBatch.Draw(tiles[x + (int)cameraPosition.X, y + (int)cameraPosition.Y].Texture, tilePosition, Color.White);
                }
            }
        }
    }
}


public void Update(GameTime gameTime) {            
   Camera.MoveCamera(this);
}

Thanks in advance

\$\endgroup\$
3
\$\begingroup\$

The code to set up your matrix should go something like this:

Viewport vp = GraphicsDevice.Viewport;

Vector2 cameraWorldPosition = (whatever);
Vector2 screenCentre = new Vector2(vp.Width / 2, vp.Height / 2);

// This first translates the camera target back to the origin (0,0).
// In SpriteBatch the origin normally appears in the top left of the screen
// and generally you want to centre it. So this then translates from the
// origin to the centre.
Vector2 translation = -cameraWorldPosition + screenCentre;

Matrix cameraMatrix = Matrix.CreateTranslation(translation .X, translation .Y, 0);

Then pass it to this overload of SpriteBatch.Begin, like so:

spriteBatch.Begin(0, null, null, null, null, null, cameraMatrix);

Then just Draw your sprites in their "world space" positions.

\$\endgroup\$
  • \$\begingroup\$ when you say worls space do you mean the position within the viewport or the position within the array of tiles? \$\endgroup\$ – Pectus Excavatum Jul 16 '13 at 14:43
  • \$\begingroup\$ "World Space" is the position within your game world, independent of the camera and of the display. (So, if I understand you correctly, then yes - the position in the array of tiles.) \$\endgroup\$ – Andrew Russell Jul 19 '13 at 10:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.