Making an efficient tiling engine
I don't usually like to post questions about my game for competition, but I haven't been able to think about a way to render tiles efficiently. Currently, I have a system set up where I parse digits from a file, store them in a 2-D integer array, and then use hardware acceleration to fill rectangles on the screen( clipping when necessary ). It greatly reduces the maximum frame rate of my game, which is what I'm measuring efficiency by, with a decrease of ~70 frames to a total of ~210 frames. This concerns me, since I will need to render actual images and more detailed tiles later on.
This is what my tiling engine looks like currently :
Code:
static void draw_game_background( game_data * game )
{
if ( game->camera.x < 0 || game->camera.y < 0 )
return;
/* Get the block location of the camera */
const int MIN_X = game->camera.x / BLOCK_WIDTH;
const int MIN_Y = game->camera.y / BLOCK_HEIGHT;
int x = 0;
int y = 0;
/* Predefine the invariants to prevent unessecary computation of values */
const int STARTING_WIDTH = BLOCK_WIDTH - ( game->camera.x % BLOCK_WIDTH );
const int STARTING_HEIGHT = BLOCK_HEIGHT - ( game->camera.y % BLOCK_HEIGHT );
const int ENDING_WIDTH = ( ( game->viewport.w - STARTING_WIDTH ) % BLOCK_WIDTH );
const int ENDING_HEIGHT = ( ( game->viewport.h - STARTING_HEIGHT ) % BLOCK_HEIGHT );
const int BLOCK_AMOUNT_ACROSS = ( ( game->viewport.w - STARTING_WIDTH ) - ENDING_WIDTH ) / BLOCK_WIDTH;
const int BLOCK_AMOUNT_DOWN = ( ( game->viewport.h - STARTING_HEIGHT ) - ENDING_HEIGHT ) / BLOCK_HEIGHT;
/* Initialize the strucuture we will use to fill in the game map on the screen */
SDL_Rect box = { 0, 0, BLOCK_WIDTH, BLOCK_HEIGHT };
for ( y = MIN_Y; y < game->current_level->height; y++, box.y = ( BLOCK_HEIGHT * ( ( y - MIN_Y ) - 1 ) ) + STARTING_HEIGHT )
{
if ( y - MIN_Y > BLOCK_AMOUNT_DOWN + 1 )
break; /* Exit the loop completely */
for ( x = MIN_X, box.x = 0; x < game->current_level->width; x++, box.x = ( BLOCK_WIDTH * ( ( x - MIN_X ) - 1 ) ) + STARTING_WIDTH )
{
if ( !( x - MIN_X ) )
box.w = STARTING_WIDTH;
else
box.w = BLOCK_WIDTH;
if ( !( y - MIN_Y ) )
box.h = STARTING_HEIGHT;
else
box.h = BLOCK_HEIGHT;
if ( x - MIN_X == BLOCK_AMOUNT_ACROSS + 1 )
box.w = ENDING_WIDTH;
if ( y - MIN_Y == BLOCK_AMOUNT_DOWN + 1 )
box.h = ENDING_HEIGHT;
if ( x - MIN_X > BLOCK_AMOUNT_ACROSS + 1 )
break; /* Exit out of the nested loop */
switch ( game->current_level->level_data[y][x] )
{
/* Fills in the color or object for each type */
case WHITE_BOX :
SDL_SetRenderDrawColor( game->renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderFillRect( game->renderer, &box );
break;
case BLACK_BOX :
SDL_SetRenderDrawColor( game->renderer, 0x00, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( game->renderer, &box );
break;
case STARTING_BOX :
SDL_SetRenderDrawColor( game->renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( game->renderer, &box );
break;
case ENDING_BOX :
SDL_SetRenderDrawColor( game->renderer, 0xFF, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( game->renderer, &box );
break;
default :
SDL_SetRenderDrawColor( game->renderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( game->renderer, &box );
break;
}
}
}
return;
}
I would think there is a more efficient way to do that than how I did it, but I couldn't find any sample code online for ideas. The code works well for handling different viewport sizes and clipping everything properly, but it's pretty expensive to call. Any suggestions are appreciated.
If you need a small program to test my code, I can make one. Just notify me( I may not respond soon ).
Edit :
I probably need to define the constant values better for you guys.
A BLOCK is just my word I used for a tile.
The BLOCK_WIDTH and BLOCK_HEIGHT is the same as 300x325.