VgaGames4

VgaGames4 - tutorial

# Tutorial 3

In this tutorial-part we just add the moving ball and check for collision of it with the player-racket and the borders.

At first an overview about modifications in the file pingpong.c.

    pingpong.c: Overview about modifications

    /* global declarations */
    [...]

    /* show help-text */
    [...]

    /* check for collisions */
    [CODEBOX]

    /* main function */
    int main(int argc, char **argv) {
      /* variable declaration */
      [CODEBOX]

      /* initializing */
      [CODEBOX]  /* opening */
      [...]      /* set keys */
      [...]      /* initialize player-racket */
      [CODEBOX]  /* initialize ball */
      [...]      /* show help, start background music */

      /* game loop */
      [...]      /* receive input-events and check the local key-strokes */
      [CODEBOX]  /* check key-strokes for player-racket */
      [CODEBOX]  /* move ball */
      [CODEBOX]  /* draw out */
      [...]      /* flush and wait */

      /* end game */
      [...]      /* destroy and exit */
    }

An overview about the used variables in function main(). We add two audio descriptors and the ball structure.
[To Position]

    pingpong.c: the variables in function main()

    const int border_size = 10;  /* size of borders in pixels */

    int winw, winh;  /* window's width and height */
    int audc_hit, audc_gameover, audc_bgmusic;  /* audio descriptors */

    struct {  /* player's structure */
      struct VG_Image *imgp;  /* image */
      struct VG_Rect rect;    /* rectangle position */
    } player;

    struct {  /* ball's structure */
      struct VG_Image *imgp;     /* image */
      struct VG_RectCent rectc;  /* rectangle position */
      int angle;                 /* moving direction angle */
      int factor;                /* moving velocity in 1/1000 pixels */
    } ball;

    /* helper variables */
    struct VG_Rect rect;
    struct VG_RectCent *rectcp;
    int rectc_nr, ipos;
    struct VG_Position posi;

We open the window, deactivate mouse grabbing, open the audio system and load the audio-files, adding one for ball's collision and one for game-over.
[To Position]

    pingpong.c: function main()

    /* initialize and open window */
    if (!VG_init("VgaGames4 tutorial 3")) { exit(1); }
    if (!vg4->window->open(VG_WINDOW_SIZE_LOW, VG_WINDOW_SCALE_BEST)) { VG_dest(); exit(1); }
    vg4->window->getsize(&winw, &winh);  /* get window-size */

    /* set mouse grabbing to off */
    vg4->input->mouse_grabbing(VG_FALSE);

    /* open audio system */
    if (!vg4->audio->open(VG_AUDIO_FREQ_MEDIUM, VG_FALSE)) { VG_dest(); exit(1); }

    /* load audio files */
    audc_hit = vg4->audio->load("files/hit.wav", 100, VG_AUDIO_VOLUME_SOUND);
    audc_gameover = vg4->audio->load("files/gameover.wav", 100, VG_AUDIO_VOLUME_SOUND);
    audc_bgmusic = vg4->audio->load("files/bgmusic.wav", 50, VG_AUDIO_VOLUME_MUSIC);

We initialize the ball, using the structure-variable ball. The ball-image is loaded and the rectangle of the ball is set to the center of the window with a randomized moving angle. The velocity of the ball is set to 3.5 pixels per moving-step.
[To Position]

    pingpong.c: function main()

    /* initialize ball, put it at the center of the window */

    /* load image */
    ball.imgp = vg4->image->load("files/ball.bmp");
    if (ball.imgp == NULL) { VG_dest(); exit(1); }

    /* set rectangle */
    vg4->image->getsize(ball.imgp, NULL, &ball.rectc.rect.w, &ball.rectc.rect.h);
    ball.rectc.rect.x = (winw - ball.rectc.rect.w) / 2;
    ball.rectc.rect.y = (winh - ball.rectc.rect.h) / 2;
    ball.rectc.centx = ball.rectc.centy = 0;

    /* set moving angle and factor */
    ball.angle = 45 + 90 * vg4->random->get("ball-angle", 0, 3);  /* randomized moving direction */
    ball.factor = 3500;

Now we are in the game-loop. When moving the player-racket we also check for collision with the ball.
[To Position]

    pingpong.c: in the game-loop of the function main()

      /* +++ player: check for key-strokes +++ */

      /* moving up */
      if (vg4->input->key_pressed(kref.k_up)) {
        int y = player.rect.y;
        player.rect.y -= 2;
        if (player.rect.y < border_size) { player.rect.y = border_size; }
        /* check for collision with ball */
        if (check_for_collision(&ball.rectc.rect, &ball.angle, &player.rect)) {
          player.rect.y = y;
          vg4->audio->play(audc_hit, VG_FALSE, VG_FALSE);
        }
      }

      /* moving down */
      if (vg4->input->key_pressed(kref.k_down)) {
        int y = player.rect.y;
        player.rect.y += 2;
        if (player.rect.y > winh - border_size - player.rect.h) { player.rect.y = winh - border_size - player.rect.h; }
        /* check for collision with ball */
        if (check_for_collision(&ball.rectc.rect, &ball.angle, &player.rect)) {
          player.rect.y = y;
          vg4->audio->play(audc_hit, VG_FALSE, VG_FALSE);
        }
      }

We also have to move the ball. The function vg4->misc->moving_one_step() is used to get the moving positions. Then we iterate over these positions, checking for collisions with borders and the player-racket. If the player missed the ball (moving outside the window), the game is over.
[To Position]

    pingpong.c: in the game-loop of the function main()

      /* +++ move ball +++ */

      /* increase ball-factor for 1/1000 pixel */
      ball.factor++;

      /* get moving steps */
      rectc_nr = vg4->misc->moving_one_step(&ball.rectc, ball.angle, ball.factor / 100, &rectcp);

      /* iterate moving steps and check for collisions */
      for (ipos = 0; ipos < rectc_nr; ipos++) {
        /* player missed the ball? */
        if (rectcp[ipos].rect.x + ball.rectc.rect.w <= 0) {
          /* play audio and wait for its end */
          vg4->audio->stop(audc_bgmusic, VG_FALSE);
          vg4->audio->play(audc_gameover, VG_FALSE, VG_FALSE);
          while (vg4->audio->is_playing(audc_gameover, NULL)) {
            vg4->window->flush();
            vg4->misc->wait_time(40);
          }
          goto endgame;
        }

        /* check right border */
        if (rectcp[ipos].rect.x > winw - border_size - ball.rectc.rect.w) {
          /* change moving direction */
          ball.angle = 360 - ball.angle;
          ball.angle %= 360; ball.angle += 360; ball.angle %= 360;
          vg4->audio->play(audc_hit, VG_FALSE, VG_FALSE);
          break;
        }

        /* check top border */
        if (rectcp[ipos].rect.y < border_size) {
          /* change moving direction */
          ball.angle = 180 - ball.angle;
          ball.angle %= 360; ball.angle += 360; ball.angle %= 360;
          vg4->audio->play(audc_hit, VG_FALSE, VG_FALSE);
          break;
        }

        /* check bottom border */
        if (rectcp[ipos].rect.y > winh - border_size - ball.rectc.rect.h) {
          /* change moving direction */
          ball.angle = 180 - ball.angle;
          ball.angle %= 360; ball.angle += 360; ball.angle %= 360;
          vg4->audio->play(audc_hit, VG_FALSE, VG_FALSE);
          break;
        }

        /* check for collision with player */
        if (check_for_collision(&rectcp[ipos].rect, &ball.angle, &player.rect)) {
          vg4->audio->play(audc_hit, VG_FALSE, VG_FALSE);
          break;
        }

        /* actualize rectangle position */
        ball.rectc = rectcp[ipos];
      }

We have all moving done, now we draw out all to the window, where we just add the drawing of the ball.
[To Position]

    pingpong.c: in the game-loop of the function main()

      /* +++ draw out +++ */

      /* clear window */
      vg4->window->clear();

      /* draw background and borders */

      vg4->window->fill(vg4->misc->colorbrightness(VG_COLOR_BLUE, 50));

      /* top border */
      rect.x = rect.y = 0; rect.w = winw; rect.h = border_size;
      vg4->window->draw_rect(&rect, VG_COLOR_RGB(0xb1, 0, 0), VG_TRUE);

      /* bottom border */
      rect.x = 0; rect.y = winh - border_size; rect.w = winw; rect.h = border_size;
      vg4->window->draw_rect(&rect, VG_COLOR_RGB(0xb1, 0, 0), VG_TRUE);

      /* right border */
      rect.x = winw - border_size; rect.y = 0; rect.w = border_size; rect.h = winh;
      vg4->window->draw_rect(&rect, VG_COLOR_RGB(0xb1, 0, 0), VG_TRUE);

      /* draw player */
      vg4->window->copy(player.imgp, vg4->misc->rect2position(&posi, &player.rect), NULL);

      /* draw ball */
      vg4->window->copy(ball.imgp, vg4->misc->rect2position(&posi, &ball.rectc.rect), NULL);

At last we add the function check_for_collision(), which checks whether the ball collides with the player-racket.
[To Position]

    pingpong.c: function check_for_collision()

    /* check whether ball collides with player
     * @param ball_rect    rectangle of the ball
     * @param ball_angle   angle of the ball, will be updated
     * @param player_rect  rectangle of the player-racket
     * @return  VG_TRUE = collision or VG_FALSE = no collision
     */
    static VG_BOOL
    check_for_collision(const struct VG_Rect *ball_rect, int *ball_angle, const struct VG_Rect *player_rect)
    {
      VG_BOOL retw;

      if (ball_rect == NULL || ball_angle == NULL || player_rect == NULL) { return VG_FALSE; }

      /* check if ball touches player */
      if (ball_rect->x + ball_rect->w - 1 < player_rect->x
          || ball_rect->x > player_rect->x + player_rect->w - 1) { return VG_FALSE; }
      if (ball_rect->y + ball_rect->h - 1 < player_rect->y
          || ball_rect->y > player_rect->y + player_rect->h - 1) { return VG_FALSE; }

      /* modify ball-angle according to collision side */

      retw = VG_FALSE;

      if (ball_rect->x <= player_rect->x + player_rect->w - 1
          && ball_rect->x + ball_rect->w - 1 >= player_rect->x + player_rect->w - 1) {
        /* ball collides with player on the right */
        *ball_angle = 360 - (*ball_angle);
        *ball_angle %= 360; *ball_angle += 360; *ball_angle %= 360;
        retw = VG_TRUE;
      }

      if (ball_rect->y + ball_rect->h - 1 >= player_rect->y
          && ball_rect->y <= player_rect->y) {
        /* ball collides with player on the top */
        *ball_angle = 180 - (*ball_angle);
        *ball_angle %= 360; *ball_angle += 360; *ball_angle %= 360;
        retw = VG_TRUE;
      }

      if (ball_rect->y <= player_rect->y + player_rect->h - 1
          && ball_rect->y + ball_rect->h - 1 >= player_rect->y + player_rect->h - 1) {
        /* ball collides with player on the bottom */
        *ball_angle = 180 - (*ball_angle);
        *ball_angle %= 360; *ball_angle += 360; *ball_angle %= 360;
        retw = VG_TRUE;
      }

      return retw;
    }

<<Previous | Download | Next>>