0

I got an assignment in my class to develop a simple game in C with the Allegro5 library.

In class we developed tetris together. The approach was to implement a while(true) loop within our main.c with a switch case to listen for events. We registered a timer for a our refresh_rate to update and redraw the game like so:

#define WIDTH 1440
#define HEIGHT 810
#define REFRESH_RATE (1.0 / 60)
#define OBSTACLE_CREATE_RATE (1.0)

void init_assets(void) {
  timer = assert_not_null(al_create_timer(REFRESH_RATE), "timer");
  queue = assert_not_null(al_create_event_queue(), "event queue");
  disp = assert_not_null(al_create_display(WIDTH, HEIGHT), "display");
  font = assert_not_null(al_create_builtin_font(), "built-in font");
}
static void main_event_loop(void) {
  ALLEGRO_EVENT event;
  al_start_timer(timer);
  while (true) {
    al_wait_for_event(queue, &event);

    switch(event.type) {
    case ALLEGRO_EVENT_TIMER:
      game_update(event.timer);
      redraw = true;
      break;

    case ALLEGRO_EVENT_MOUSE_AXES: mouse_move(event.mouse); break;
    case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: mouse_down(event.mouse); break;
    case ALLEGRO_EVENT_MOUSE_BUTTON_UP: mouse_up(event.mouse); break;

    case ALLEGRO_EVENT_KEY_DOWN: key_down(event.keyboard); break;
    case ALLEGRO_EVENT_KEY_UP: key_up(event.keyboard); break;
    case ALLEGRO_EVENT_KEY_CHAR: key_char(event.keyboard); break;

    case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break;
    }

    if (done) break;

    if (redraw && al_is_event_queue_empty(queue)) {
      game_redraw();
      redraw = false;
    }
  }
}

I wanted to implement Flappy Bird and I am really struggling with either Input Lag or Stuttering because my event queue gets filled up:

The following produces stuttering because the queue is not always empty in 1/60 of a second:

    if (redraw && al_is_event_queue_empty(queue)) {
      game_redraw();
      redraw = false;
    }

Changing it like so makes the game unresponsive because input is not processed in time because an older event is still being processed and clogs up the queue.

    if (redraw) {
      game_redraw();
      redraw = false;
    }

I suspect the redrawing of my display is what clogs up the queue. I do not do a lot of calculation; only that the 1 bird drops and a maximum of 10 obstacles are beeing shifted to the left. I have not even implemented any sort of collision detection. The redrawing is done by a bunch of al_draw_filled_rectangle(x, y, x + BLOCK_WIDTH, y + BLOCK_HEIGHT, color); calls.

In hindsight it would have been better to implement the bird and obstacles as images and built a hitbox around them but what I do at the moment is basically split the window (1440 * 810) in rows and columns and draw 5 x 5 rectangles like so:

void game_redraw(void) {
    al_clear_to_color(BACKGROUND);
    bird_draw();
    queue_obstacles_draw(obstacles);
    al_flip_display();
}

So the function al_draw_filled_rectangle(x, y, x + BLOCK_WIDTH, y + BLOCK_HEIGHT, color); gets called approximately 200 times for the bird and a maximum of 10 * 3000 = 30.000 times for the obstacles 60 times a second. So this might be too much for my PC to handle, but when inspecting the resources via Task Manager the GPU is at roughly 40% and the CPU at 65% (in Visual Studio it sits at 40-45%).

My GPU: NVIDIA GeForce GTX 1060 6GB
My CPU: Intel Core i5-4460 CPU@ 3.20 GHz

Now the assignment is due within the next week and I will most likely submit it with stuttering but out of curiosity I would love to know what I am doing wrong here.

Am I drawing my display incorrectly?
Are there ways to better utilize GPU/CPU?
What is best practise to make the game more fluid?
How does a FPS Shooter like CS:GO accomplish frame rates between 100-200 on my machine while I am struggling to draw a "few" rectangles for a 60 fps framerate?

MichaelS
  • 171
  • 11

0 Answers0