Draw Bug 2D player Camera
- by RedShft
I have just implemented a 2D player camera for my game, everything works properly except the player on the screen jitters when it moves between tiles. What I mean by jitter, is that if the player is moving the camera updates the tileset to be drawn and if the player steps to the right, the camera snaps that way. The movement is not smooth.
I'm guessing this is occurring because of how I implemented the function to calculate the current viewable area or how my draw function works.
I'm not entirely sure how to fix this. This camera system was entirely of my own creation and a first attempt at that, so it's very possible this is not a great way of doing things.
My camera class, pulls information from the current tileset and calculates the viewable area. Right now I am targettng a resolution of 800 by 600. So I try to fit the appropriate amount of tiles for that resolution. My camera class, after calculating the current viewable tileset relative to the players location, returns a slice of the original tileset to be drawn. This tileset slice is updated every frame according to the players position.
This slice is then passed to the map class, which draws the tile on screen.
//Map Draw Function
//This draw function currently matches the GID of the tile to it's location on the
//PNG file of the tileset and then draws this portion on the screen
void Draw(SDL_Surface* background, int[] _tileSet)
{
enforce( tilesetImage != null, "Tileset is null!");
enforce( background != null, "BackGround is null!");
int i = 0;
int j = 0;
SDL_Rect DestR, SrcR;
SrcR.x = 0;
SrcR.y = 0;
SrcR.h = 32;
SrcR.w = 32;
foreach(tile; _tileSet)
{
//This code is matching the current tiles ID to the tileset image
SrcR.x = cast(short)(tileWidth * (tile >= 11 ? (tile - ((tile / 10) * 10) - 1) : tile - 1));
SrcR.y = cast(short)(tileHeight * (tile > 10 ? (tile / 10) : 0));
//Applying the tile to the surface
SDL_BlitSurface( tilesetImage, &SrcR, background, &DestR );
//this keeps track of what column/row we are on
i++;
if ( i == mapWidth )
{
i = 0;
j++;
}
DestR.x = cast(short)(i * tileWidth);
DestR.y = cast(short)(j * tileHeight);
}
}
//Camera Class
class Camera
{
private:
//A rectangle representing the view area
SDL_Rect viewArea;
//In number of tiles
int viewAreaWidth;
int viewAreaHeight;
//This is the x and y coordinate of the camera in MAP SPACE IN PIXELS
vect2 cameraCoordinates;
//The player location in map space IN PIXELS
vect2 playerLocation;
//This is the players location in screen space;
vect2 playerScreenLoc;
int playerTileCol;
int playerTileRow;
int cameraTileCol;
int cameraTileRow;
//The map is stored in a single array with the tile ids
//this corresponds to the index of the starting and ending tile
int cameraStartTile, cameraEndTile;
//This is a slice of the current tile set
int[] tileSetCopy;
int mapWidth;
int mapHeight;
int tileWidth;
int tileHeight;
public:
this()
{
this.viewAreaWidth = 25;
this.viewAreaHeight = 19;
this.cameraCoordinates = vect2(0, 0);
this.playerLocation = vect2(0, 0);
this.viewArea = SDL_Rect (0, 0, 0, 0);
this.tileWidth = 32;
this.tileHeight = 32;
}
void Init(vect2 playerPosition, ref int[] tileSet, int mapWidth, int mapHeight )
{
playerLocation = playerPosition;
this.mapWidth = mapWidth;
this.mapHeight = mapHeight;
CalculateCurrentCameraPosition( tileSet, playerPosition );
//writeln( "Tile Set Copy: ", tileSetCopy );
//writeln( "Orginal Tile Set: ", tileSet );
}
void CalculateCurrentCameraPosition( ref int[] tileSet, vect2 playerPosition )
{
playerLocation = playerPosition;
playerTileCol = cast(int)((playerLocation.x / tileWidth) + 1);
playerTileRow = cast(int)((playerLocation.y / tileHeight) + 1);
//writeln( "Player Tile (Column, Row): ","(", playerTileCol, ", ", playerTileRow, ")");
cameraTileCol = playerTileCol - (viewAreaWidth / 2);
cameraTileRow = playerTileRow - (viewAreaHeight / 2);
CameraMapBoundsCheck();
//writeln( "Camera Tile Start (Column, Row): ","(", cameraTileCol, ", ", cameraTileRow, ")");
cameraStartTile = ( (cameraTileRow - 1) * mapWidth ) + cameraTileCol - 1;
//writeln( "Camera Start Tile: ", cameraStartTile );
cameraEndTile = cameraStartTile + ( viewAreaWidth * viewAreaHeight ) * 2;
//writeln( "Camera End Tile: ", cameraEndTile );
tileSetCopy = tileSet[cameraStartTile..cameraEndTile];
}
vect2 CalculatePlayerScreenLocation()
{
cameraCoordinates.x = cast(float)(cameraTileCol * tileWidth);
cameraCoordinates.y = cast(float)(cameraTileRow * tileHeight);
playerScreenLoc = playerLocation - cameraCoordinates + vect2(32, 32);;
//writeln( "Camera Coordinates: ", cameraCoordinates );
//writeln( "Player Location (Map Space): ", playerLocation );
//writeln( "Player Location (Screen Space): ", playerScreenLoc );
return playerScreenLoc;
}
void CameraMapBoundsCheck()
{
if( cameraTileCol < 1 )
cameraTileCol = 1;
if( cameraTileRow < 1 )
cameraTileRow = 1;
if( cameraTileCol + 24 > mapWidth )
cameraTileCol = mapWidth - 24;
if( cameraTileRow + 19 > mapHeight )
cameraTileRow = mapHeight - 19;
}
ref int[] GetTileSet()
{
return tileSetCopy;
}
int GetViewWidth()
{
return viewAreaWidth;
}
}