Viewport / Camera Calculation in 2D Game
- by Dave
we have a 2D game with some sprites and tiles and some kind of camera/viewport, that "moves" around the scene. so far so good, if we wouldn't had some special behaviour for your camera/viewport translation.
normally you could stick the camera to your player figure and center it, resulting in a very cheap, undergraduate, translation equation, like :
vec_translation -/+= speed (depending in what keys are pressed. WASD as default.)
buuuuuuuuuut, we want our player figure be able to actually reach the bounds, when the viewport/camera has reached a maximum translation.
we came up with the following solution (only keys a and d are the shown here, the rest is just adaption of calculation or maybe YOUR super-cool and elegant solution :) ):
if(keys[A])
{
playerX -= speed;
if(playerScreenX <= width / 2 && tx < 0)
{
playerScreenX = width / 2;
tx += speed;
}
else if(playerScreenX <= width / 2 && (tx) >= 0)
{
playerScreenX -= speed;
tx = 0;
if(playerScreenX < 0) playerScreenX = 0;
}
else if(playerScreenX >= width / 2 && (tx) < 0)
{
playerScreenX -= speed;
}
}
if(keys[D])
{
playerX += speed;
if(playerScreenX >= width / 2 && (-tx + width) < sceneWidth)
{
playerScreenX = width / 2;
tx -= speed;
}
if(playerScreenX >= width / 2 && (-tx + width) >= sceneWidth)
{
playerScreenX += speed;
tx = -(sceneWidth - width);
if(playerScreenX >= width - player.width) playerScreenX = width - player.width;
}
if(playerScreenX <= width / 2 && (-tx + width) < sceneWidth)
{
playerScreenX += speed;
}
}
i think the code is rather self explaining:
keys is a flag container for currently active keys, playerX/-Y is the position of the player according to world origin, tx/ty are the translation components vital to background / npc / item offset calculation, playerOnScreenX/-Y is the actual position of the player figure (sprite) on screen and width/height are the dimensions of the camera/viewport.
this all looks quite nice and works well, but there is a very small and nasty calculation error, which in turn sums up to some visible effect.
let's consider following piece of code:
if(playerScreenX <= width / 2 && tx < 0)
{
playerScreenX = width / 2;
tx += speed;
}
it can be translated into plain english as : if the x position of your player figure on screen is less or equal the half of your display / camera / viewport size AND there is enough space left LEFT of your viewport/camera then set players x position on screen to width half, increase translation (because we subtract the translation from something we want to move). easy, right?! doing this will create a small delta between playerX and playerScreenX.
after so much talking, my question appears now here at the bottom of this document:
how do I stick the calculation of my player-on-screen to the actual position of the player AND having a viewport that is not always centered aroung the players figure?
here is a small test-case in processing:
http://pastebin.com/bFaTauaa
thank you for reading until now and thank you in advance for probably answering my question.