Looping ONLY through visible tiles in a 2D engine?

Started by
1 comment, last by Rectangle 11 years ago

I'm using HGE to render a one-dimensional array of tiles. Each tile in this array stores vertex, color and texture information, which is pre-calculated (only once, before the first render cycle) and does NOT change. Instead, I have implemented a virtual camera system, storing an X/Y pixel offset + view width/height information, allowing a tilemap to be rendered at any given offset without actually changing the vertices of any tiles. This means that tilemaps are always located at 0,0 world-space coordinates, but the user is allowed to scroll through the map using the camera system.

I had this system working rather nicely for a while, until it was time to apply a few optimizations... One of which included calculating which tiles are within range of the camera view, and only rendering these tiles. This optimization nearly doubled my rendering speeds, but I realized the downfall is that I am still looping through each & every tile in the array. For smaler maps, this wasn't a big deal. But for larger maps, the performance hit is almost unbearable... And this is only for a single layer of tiles!

So, given the following variables:

  • One-dimensional Tile Array (stores vertex info)
  • Camera X Offset (pixel, world-space)
  • Camera Y Offset (pixel, world-space)
  • Camera View Width (pixel, screen-space)
  • Camera View Height (pixel, screen-space)
  • Tilemap Size (logical # of columns & rows)
  • Tile Dimensions (logical width & height, in pixels)

How could I create a loop which ONLY iterates through tiles within range of the camera's current view?

Advertisement

the left edge of the camera is at: camera_offset_x - camera-view-width / 2 and the right edge at camera_offset_x + camera_view-width / 2 right ?

(and similarily for the top and bottom edges)

If so then:

Edit: This assumes the camera position is the center of the screen (skip the -cam_width|cam_height /2 and change +width|height / 2 to just +width|height if the camera position is the top left)

firstcolumn = floor((camera_offset_x - camera_view_width / 2) / tile_width)

lastcolumn = ceil((camera_offset_x + camera_view_width / 2) / tile_width)

firstrow = floor((camera_offset_y - camera_view_height / 2) / tile_height)

lastrow = ceil((camera_offset_y + camera_view_height / 2) / tile_height)

Now, assuming there are no gaps in your tile array and it is layed out row by row (so the first row comes before the 2nd row in the array etc)

If your tiles are stored in a random order you should change how they are stored.

firsttile = firstrow*tilemap_columncount + firstcolumn

lasttile = lastrow*tilemap_columncount + lastcolumn

iterate over that range

[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

Thanks! With a couple of minor tweaks, I was able to get this algorithm to work:


void Render(HGE* hge, float cameraX, float cameraY, float cameraWidth, float cameraHeight) {
	int firstcolumn = int( floor(cameraX / m_tileWidth) );
	int firstrow = int( floor(cameraY / m_tileHeight) );
	int lastcolumn = int( ceil((cameraX + cameraWidth) / m_tileWidth) );
	int lastrow = int( ceil((cameraY + cameraHeight) / m_tileHeight) );

	for(int r = firstrow; r < lastrow; r++)
	{
		for(int c = firstcolumn; c < lastcolumn; c++)
		{
			hge->Gfx_RenderQuad(&m_tiles[r * m_nColumns + c].quad);
		}
	}
}

This topic is closed to new replies.

Advertisement