Moving Veiwport for SDL tile game.

Started by
4 comments, last by Phex 17 years, 10 months ago
Hi, Im just started making a Tile based SDL game(C++). It's a 2D RPG and the player should be moving in fairly big worlds. I have no real problem drawing the map, but i dont know how i shall move the viewport so the world moves width the player. I dont wanna limit my world to 1 screen! So please any suggestions?
Advertisement
To move a tilemap, it is usually enough to add an offset to the index of the tile you are drawing.

For example:
You usually start drawing you map at the tile (0, 0). If your player moves one tile up, start drawing your map at the tile (0, 1), leaving the first row out. If your player moves one tile to the right afterwards, start drawing your map at the tile (1, 1), leaving the first row and the first column out - etc.

This would allow a tile-perfect scrolling, which might look a bit ugly. It is used in a lot of oldschool tile based games where it always looked as if you character was jumping from tile to another.
If you got this to work and dont like the look of it, you can try to improve it to pixel-perfect, smooth scrolling. How you can implement this depends on how your character is able to move in the world (only from one tile to another tile or also in-between tiles).

Dont forget that if your world is "really big", you should only draw the visible part of the world!

There are quite a few helpful articles here.
Thanks you so much for the reply, but im pretty stuck again.
Ok, i wernt really sure how i was going to solve this so i did this:

void DrawMap(SDL_Surface *screen){  int tile;  int xpos;  int ypos;  int XX = pPlayer->GetpositionX() - 10;  int YY = pPlayer->GetpositionY() - 10;    for (int y = 0 + YY; y < MAP_SIZEY; y++)    {    for (int x = 0 + XX; x < MAP_SIZEX; x++)    {         tile = map[y][x];         //calc position         xpos = x * 25;         ypos = y * 25;         DrawIMG(Tile[tile], xpos, ypos, screen);           }    }}


Now the problem is that fucked the program up. Now it crashes when i move the player. You dont have solution again do you ? :)
You're also going to have to shift all the tiles over by -1*WidthOfOneTile*XX and -1*HeightOfOneTile*YY.

But, you might want to tell us more. What happened to the program? What type of crash?

Your indexes are probably out of bounds. If player->GetPositionX() is less than 10, it will be out of bounds. Same with GetPositionY().
Well , ok.

1. The program crashed (simply shout down) when i were moving up in the area where the indexes got out of bounds. I could go downhill. So you were right :) But the player were always in the corner and the stuff "behind" him weren't drawn. I need to have an area around the player were the game always draw.

2. I dont really get what you mean by shift tile's over?

And sorry if this is unclear!
Quote:1. The program crashed (simply shout down) when i were moving up in the area where the indexes got out of bounds
There you got the bug.

I will post an excerpt of my tile draw routine (simplified, of course).

This is by far not the best way to handle tile map drawing, but a rather comfortable way. I first determine the map draw boundings, the area of the map which is on the screen, then I loop through my tiles and check which I have to draw. I draw them from the left bottom corner to the upper right corner. It works quite well and can be easily extended to pixel perfect scrolling. :-)

//Get the Map Draw Boundings (the map excerpt we want to draw)int x_min = ( pPlayer->GetpositionX() * tilesize - SCREEN.resolution.x / 2.0f ) / float( tilesize );int y_min = ( pPlayer->GetpositionY() * tilesize - SCREEN.resolution.y / 2.0f ) / float( tilesize );int x_max = x_min + float( SCREEN.resolution.x ) / float( tilesize );int y_max = y_min + float( SCREEN.resolution.y ) / float( tilesize );//The following 2 variables determine the position on the screen (in pixels) //where we want the current tile image to be drawn.int draw_position_x = 0;	//Start to draw at pixel 0 (left bottom corner)int draw_position_y = 0;	//Start to draw at pixel 0 (left bottom corner)//Go through all neccessary rowsfor( int yi = y_min; yi <= y_max; yi++ ){	//Jump to beginning of the new line (pixel 0)	draw_position_x = 0;	//Go through all neccessary columns	for( int xi = x_min; xi <= x_max; xi++ )	{		//Try to get the current tile		int *Tile = GetTile( xi, yi );					//Look if the current tile is valid (VERY IMPORTANT!)		if( Tile )			DrawIMG( Tile[tile], draw_position_x, draw_position_y, screen);			//(I dont know if I am using DrawIMG correctly)			//Shift x-Position		draw_position_x += tilesize;	}	//Jump to the next line	draw_position_y += tilesize;}


The most important part of this code are the map draw boundings, I will explain them further:

x_min =
( pPlayer->GetpositionX() * tilesize - SCREEN.resolution.x / 2.0f ) / float( tilesize );
The current position of the player (which we assume is always in the middle of the screen!) multiplied with the tilesize is the position of the player measured in pixels. This value minus the half screen resolution is the point in the lower left corner of the screen, the x-ID of the first tile we want to draw.

y_min =
( pPlayer->GetpositionY() * tilesize - SCREEN.resolution.y / 2.0f ) / float( tilesize );
Works exaktly in the same way as x_min.

x_max = x_min + float( SCREEN.resolution.x ) / float( tilesize );
The screen resolution divided through the tilesize is the screen resolution measured in tiles. This value plus the x-ID of the first tile we want to draw is the x-ID of the last tile we want to draw.

y_min = y_min + float( SCREEN.resolution.y ) / float( tilesize );
Works exaktly in the same way as x_max.

I hope this makes things a bit clearer for you.

EDIT: fixed code.
EDIT: just noticed, but is is only important if you got the rest working: you have to add x_min -= tilesize / 2 etc. if your character should be centered in the middle of the tile. Otherwise the map draw boundings will be cut as if he was standing at the upper right corner of each tile.

This topic is closed to new replies.

Advertisement