0
\$\begingroup\$

In my 2D tile based side scroller, I want a camera that scrolls in the x direction, but not in the y direction. The world is separated into three zones; one on the left and one on the right where the camera doesn't move, and one in the middle where the camera should move left and right and centered on the player.

The world is a 2D int array where each tile has it's own ID (number). The player's position is in pixel coordinates.

My problem is that when the player moves outside the left zone (and into the middle), the camera always move slower than the player, which means the player disappears of the screen. Since I calculate the camera's position from the player position when the player is in the middle zone, I don't understand why the camera isn't always centered around the player.

My code for calculating the camera's position and drawing the background is as follows (in C#):

int worldWidth = world.GetLength(0) * _TILE_WIDTH;
int resX = camera.Width / TILE_WIDTH;
int resY = camera.Height / TILE_HEIGHT;

Bitmap screenBmp = new Bitmap(camera.Width, camera.Height);
Graphics g = Graphics.FromImage(screenBmp);

// upper left corner of the camera in the world
Vector2D pCamera = new Vector2D(p.X + (p.PlayerSize.Width / 2) - (screenBmp.Width / 2), 0);


int oneMoreX_tile = 0;  // draw one more tile off the screen?

if (p.X + (p.PlayerSize.Width / 2) < 0 + screenBmp.Width / 2) // past the left zone
{
    pCamera.X = 0;
}
else if (p.X + (p.PlayerSize.Width / 2) >= worldWidth - screenBmp.Width / 2) // past the right zone
{
    pCamera.X = worldWidth - screenBmp.Width;
}
else  // between the zones
{
    oneMoreX_tile = 1;
}

int xOffset = (int)pCamera.X % TILE_WIDTH;
int yOffset = (int)pCamera.Y % TILE_HEIGHT;

int startX_tile = (int)pCamera.X / TILE_WIDTH;
int startY_tile = (int)pCamera.Y / TILE_HEIGHT;


for (int i = 0; i < resX + oneMoreX_tile; i++)
{
    for (int j = 0; j < resY; j++)
    {
        int tileValue = world[startX_tile + i, startY_tile + j];

        // tile coord in tileset
        int x = tileValue % tilesetWidth_tile;
        int y = tileValue / tilesetWidth_tile;

        // pixel coord in tileset (top left)
        int x_px = x * TILE_WIDTH;
        int y_px = y * TILE_HEIGHT;


        g.DrawImage(tileset,
            new Rectangle(i * TILE_WIDTH - xOffset, j * TILE_HEIGHT - yOffset, TILE_WIDTH, TILE_HEIGHT),
            new Rectangle(x_px, y_px, TILE_WIDTH, TILE_HEIGHT),
            GraphicsUnit.Pixel);
    }
}

This code runs every time the graphics timer ticks. (I'm using Windows Forms..) I have two timers set at the same interval; one graphics timer and one physics timer. The physics timer just updates the player's position.

Regardless of world length, the player always disappears of the screen at 640 pixels (which is also the width of the screen), and the camera's position is 336 pixels from the left. I have also tried with lower speeds with no success.

Please ask if there's anything more you need to know. Any help would be appreciated.

\$\endgroup\$

closed as off-topic by bummzack, Anko, congusbongus, MichaelHouse Mar 25 '15 at 21:35

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions about debugging a problem in your project must present a concise selection of code and context so as to allow a reader to diagnose the issue without needing to read all of your code or to engage in extensive back-and-forth dialog. For more information, see this meta thread." – bummzack, Anko, congusbongus, MichaelHouse
If this question can be reworded to fit the rules in the help center, please edit the question.

0
\$\begingroup\$

I figured out what the problem was. It was not a problem with the camera calculation, but rather with drawing the player.

The player's coordinates is in pixels in the works ( between 0 and world.GetLength(0) * tile_width). So when I drew the player, I forgot to subtract the camera position so the player world stay inside the camera view.

This is what my code to draw the player looks like now:

g.DrawImage(p.PlayerSpriteCharSet,
            new RectangleF(p.X - (float)pCamera.X, p.Y - (float)pCamera.Y,     p.PlayerSize.Width, p.PlayerSize.Height),
            new Rectangle(new Point(tilesetX_px, tilesetY_px), p.PlayerSpriteSize),
            GraphicsUnit.Pixel);
\$\endgroup\$

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