authoreyes
Member
Hey all,
Was fixin' to get back to coding my pandora game, and I figured I'd throw the rendering portion to the mercy of the dev community.
See, I am only a C++/game programmer hobbyist (career is more java stuff), so I figured I'd see if anyone with some time could point out any inefficiencies here. Basically, this is doing a foreground/background 16x16 tile mapped scrolling engine. It runs fine, but a bit slow. I am sure there is room to optimize, so maybe someone has a few tips...Worst comes to worst, I can render a smaller area and scale up (but loose the high res look it has now)...
I know it may be hard to follow some of this as my commenting is lacking, so if something seems stupid, feel free to shout...
EDIT: added some optimizations.
Was fixin' to get back to coding my pandora game, and I figured I'd throw the rendering portion to the mercy of the dev community.
See, I am only a C++/game programmer hobbyist (career is more java stuff), so I figured I'd see if anyone with some time could point out any inefficiencies here. Basically, this is doing a foreground/background 16x16 tile mapped scrolling engine. It runs fine, but a bit slow. I am sure there is room to optimize, so maybe someone has a few tips...Worst comes to worst, I can render a smaller area and scale up (but loose the high res look it has now)...
I know it may be hard to follow some of this as my commenting is lacking, so if something seems stupid, feel free to shout...
EDIT: added some optimizations.
Code:
class RenderUtils {
public :
//TODO: this needs to be pulled out into a main cycle loop
//class since artificial intelligence and such is going in here now
static void render(SDL_Surface *screen, GameState *state) {
clear_screen(screen);
pre_process_events(state);
GameLifeManager::move_baddies(state);
procedural_render(screen, state);
post_process_events(state);
SDL_Flip(screen);
}
static void procedural_render(SDL_Surface *screen, GameState *state) {
//render_sprite_vector(screen, state, state->parallax_objs);
render_backgrounds(screen, state);
render_sprite_vector(screen, state, state->screen_stats);
//TODO: attachedsprites needs to be below and check z depth
render_sprite_vector(screen, state, state->player.attached_sprites);
render_sprite(screen, state, state->player);
render_sprite_vector(screen, state, state->sprites);
render_sprite_vector(screen, state, state->baddies);
}
static void render_backgrounds(SDL_Surface *screen, GameState *state) {
unsigned int x = (int)state->camera_x / LEVEL_TILE_WIDTH;
unsigned int x_mod_tilewidth = (((int)state->camera_x) % LEVEL_TILE_WIDTH);
render_parallax(screen, state, x, x_mod_tilewidth, true);
render_parallax(screen, state, x, x_mod_tilewidth, false);
}
static void render_parallax(SDL_Surface *screen, GameState *state, unsigned int x, unsigned int x_mod_tilewidth, bool background) {
DecoratedSurface *parallax_surface = (background == true ? &(state->background_surface) : &(state->foreground_surface));
std::vector<std::vector<Tile*> > *grid = (background == true ? &(state->back_grid) : &(state->fore_grid));
if (background) {
calculate_background_parallax_offsets(state, &x, &x_mod_tilewidth, background);
}
unsigned int total_distance = x + (GAME_WINDOW_WIDTH / LEVEL_TILE_WIDTH) + 1;
unsigned int scrolled_tile_width = LEVEL_TILE_WIDTH;
//screen_x represents the absolute position of the start of the display tiles,
//so we always repaint starting at 0,0
unsigned int screen_x = 0;
SDL_Rect tile_pos;
tile_pos.y = 0;
tile_pos.h = LEVEL_TILE_HEIGHT;
//first x pass will be a shaved tile (possibly < 16 pixels on the left of screen)
if ((int)state->camera_x >> 4 != 0) {
scrolled_tile_width = LEVEL_TILE_WIDTH - x_mod_tilewidth;
render_screen_y_tiles(screen, parallax_surface, grid, state, tile_pos, screen_x, x, scrolled_tile_width, x_mod_tilewidth, background);
screen_x += scrolled_tile_width;
x++;
}
for (x;x<total_distance; ++x) {
scrolled_tile_width = LEVEL_TILE_WIDTH;
render_screen_y_tiles(screen, parallax_surface, grid, state, tile_pos, screen_x, x, scrolled_tile_width, 0, background);
screen_x += scrolled_tile_width;
}
}
static void render_screen_y_tiles(SDL_Surface *screen, DecoratedSurface *parallax_surface, std::vector<std::vector<Tile*> > *grid, GameState *state,
SDL_Rect tile_pos, unsigned int screen_x, unsigned int x, unsigned int scrolled_tile_width, unsigned int x_mod_tilewidth, bool background) {
std::vector<Tile*> y_vector = (*grid)[x];
for (unsigned int y=0;y<y_vector.size();++y) {
unsigned int tile_id = y_vector[y]->id;
unsigned int transparent_tile = (background ? state->transparent_tile_f : state->transparent_tile_B);
if (tile_id != transparent_tile) {
//calc tile rip from tile strip
tile_pos.x = (tile_id << 4) + x_mod_tilewidth;
tile_pos.w = scrolled_tile_width;
unsigned int screen_y = (y << 4);
blit_tile(screen, state, parallax_surface, &tile_pos, screen_x, screen_y, false);
}
}
}
static void calculate_background_parallax_offsets(GameState *state, unsigned int *x, unsigned *x_mod, bool background) {
if (state->background_scroll_offset == 0) {
state->background_parallax_camera_x = ++state->background_parallax_camera_x;
//TODO: this should not use the default, but the specific level impl
state->background_scroll_offset = GameState::default_background_scroll_offset;
}
*x = state->background_parallax_camera_x / LEVEL_TILE_WIDTH;
*x_mod = (((int)state->background_parallax_camera_x) % LEVEL_TILE_WIDTH);
}
static void render_sprite_vector(SDL_Surface *screen, GameState *state, std::vector<Sprite*> sprites) {
for (std::vector<Sprite*>::iterator it = sprites.begin();it != sprites.end(); ++it) {
render_sprite(screen, state, *(*it));
}
}
static void render_sprite_vector(SDL_Surface *screen, GameState *state, std::vector<Sprite> sprites) {
for (std::vector<Sprite>::iterator it = sprites.begin();it != sprites.end(); ++it) {
render_sprite(screen, state, (*it));
}
}
static void render_sprite(SDL_Surface *screen, GameState *state, Sprite sprite) {
SDL_Rect tile_pos;
if (sprite.descriptor->num_frames == 1) {
tile_pos.x = tile_pos.y = 0;
tile_pos.w = sprite.descriptor->width;
tile_pos.h = sprite.descriptor->height;
} else {
tile_pos.x = sprite.get_current_frame() * sprite.descriptor->width;
tile_pos.y = 0;
}
tile_pos.w = sprite.descriptor->width;
tile_pos.h = sprite.descriptor->height;
blit_tile(screen, state, sprite.descriptor->sprite_sheet, &tile_pos, sprite.x, sprite.y, sprite.heading == W);
}
static void blit_tile(SDL_Surface *screen, GameState *state, DecoratedSurface *surface, SDL_Rect *tile_pos, unsigned int x, unsigned int y, bool flip) {
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(surface->surface, tile_pos, screen, &offset);
}
static void pre_process_events(GameState *state) {
for (std::vector<TriggeredEvent*>::iterator it = state->level->pre_process_triggered_events.begin();it != state->level->pre_process_triggered_events.end(); ++it) {
if ((*it)->status == EXECUTING) {
(*it)->next_cycle(state);
}
}
}
static void post_process_events(GameState *state) {
for (std::vector<TriggeredEvent*>::iterator it = state->level->post_process_triggered_events.begin();it != state->level->post_process_triggered_events.end(); ++it) {
if ((*it)->status == EXECUTING) {
(*it)->next_cycle(state);
}
}
}
static void clear_screen(SDL_Surface *screen) {
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0, 0, 0));
}
};
#endif