VgaGames4

VgaGames4 - tutorial

# Tutorial 5

Until now we had just one file: pingpong.c. For a more complex game it is not reasonable to put all code into one file. With game objects the several objects can be put into own files. This reduces pingpong.c to the essential.

At first an overview about the file pingpong.c.

    pingpong.c: Overview

    /* global declarations */
    [CODEBOX]

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

      /* initializing */
      [CODEBOX]  /* opening, collision functions and tag, loading audio files */
      [CODEBOX]  /* set keys */
      [CODEBOX]  /* create object-instances */
      [CODEBOX]  /* show help, start background music */

      /* game loop */
      [CODEBOX]  /* receive input-events and check the local key-strokes */
      [CODEBOX]  /* call f_run() of all object-instances */
      [CODEBOX]  /* clear window, draw background, call f_draw() of all object-instances */
      [CODEBOX]  /* flush and wait */

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

In the file pingpong.h, which is included into all program files, we declare the private structure of the game.

    pingpong.h

    #ifndef PINGPONG_H_
    #define PINGPONG_H_

    #include <vgagames4.h>

    /* include export-functions to create new object-instances */
    #include "objnew.h"

    /* private structure of the game */
    struct s_game {
      int winw, winh;  /* window's width and height */
      unsigned int coll_tag;  /* collision-tag */

      struct {  /* keys */
        int k_quit_lalt;  /* part of quit: Left-ALT */
        int k_quit_q;     /* part of quit: Q */
        int k_pause;      /* pause */
        int k_up;         /* move up */
        int k_down;       /* move down */
      } kref;
    };

    #endif /* PINGPONG_H_ */

The global declarations of the file pingpong.c
[To Position]

    pingpong.c: global declarations

    /* object-collision functions */
    extern void objcoll(void);

The main function of the file pingpong.c
[To Position]

    pingpong.c: variable declaration

    struct s_game sgame;  /* private structure of the game */
    int audc_gameover, audc_bgmusic;  /* audio descriptors */

[To Position]

    pingpong.c: opening, collision functions and tag, loading audio files

    /* initialize game-structure */
    memset(&sgame, 0, sizeof(sgame));

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

    /* 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); }

    /* add object-collision functions */
    objcoll();

    /* create collision-tag */
    sgame.coll_tag = vg4->collision->create(NULL, 0, 0);

    /* load audio files */
    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);

[To Position]

    pingpong.c: set keys

    /* set keys */

    /* quit with ALT+Q, not changeable */
    if ((sgame.kref.k_quit_lalt = vg4->input->key_insert("Quit-LALT", VG_FALSE, VG_FALSE)) == 0) { VG_dest(); exit(1); }
    vg4->input->key_setkbd(sgame.kref.k_quit_lalt, VG_INPUT_KBDCODE_LALT);
    if ((sgame.kref.k_quit_q = vg4->input->key_insert("Quit-Q", VG_FALSE, VG_FALSE)) == 0) { VG_dest(); exit(1); }
    vg4->input->key_setkbd(sgame.kref.k_quit_q, VG_INPUT_KBDCODE_Q);

    /* pause with P, changeable */
    if ((sgame.kref.k_pause = vg4->input->key_insert("Pause", VG_TRUE, VG_FALSE)) == 0) { VG_dest(); exit(1); }
    vg4->input->key_setkbd(sgame.kref.k_pause, VG_INPUT_KBDCODE_P);

    /* move-up with cursor-key UP, changeable */
    if ((sgame.kref.k_up = vg4->input->key_insert("Move up", VG_TRUE, VG_FALSE)) == 0) { VG_dest(); exit(1); }
    vg4->input->key_setkbd(sgame.kref.k_up, VG_INPUT_KBDCODE_UCURS);
    vg4->input->key_setgc(sgame.kref.k_up, 0, VG_INPUT_GCAXIS_RIGHTY_UP);

    /* move-down with cursor-key DOWN, changeable */
    if ((sgame.kref.k_down = vg4->input->key_insert("Move down", VG_TRUE, VG_FALSE)) == 0) { VG_dest(); exit(1); }
    vg4->input->key_setkbd(sgame.kref.k_down, VG_INPUT_KBDCODE_DCURS);
    vg4->input->key_setgc(sgame.kref.k_down, 0, VG_INPUT_GCAXIS_RIGHTY_DOWN);

[To Position]

    pingpong.c: create object-instances

    /* create object-instances */
    if (objnew_PLAYER(&sgame) == 0) { VG_dest(); exit(1); }
    if (objnew_BALL(&sgame) == 0) { VG_dest(); exit(1); }
    if (objnew_BORDER(&sgame, "top") == 0) { VG_dest(); exit(1); }
    if (objnew_BORDER(&sgame, "bottom") == 0) { VG_dest(); exit(1); }
    if (objnew_BORDER(&sgame, "right") == 0) { VG_dest(); exit(1); }

[To Position]

    pingpong.c: show help, start background music

    /* show help */
    if (!show_help()) { VG_dest(); exit(1); }

    /* play background music looping */
    vg4->audio->play(audc_bgmusic, VG_TRUE, VG_TRUE);

[To Position]

    pingpong.c: entering game-loop: receive input-events and check the local key-strokes

    /* game loop */
    for (;;) {
      /* retrieve input-events */
      if (!vg4->input->update(VG_TRUE)) { goto endgame; }

      /* quit? */
      if (vg4->input->key_newpressed(sgame.kref.k_quit_q) && vg4->input->key_pressed(sgame.kref.k_quit_lalt)) { goto endgame; }

      /* pause? */
      if (vg4->input->key_newpressed(sgame.kref.k_pause)) {
        if (!vg4->misc->pause()) { goto endgame; }
      }

[To Position]

    pingpong.c: in game-loop: call f_run() of all object-instances

      /* call f_run() of all object-instances */

      if (!vg4->object->call_run(&sgame)) {
        /* see obj-ball.c: player missed ball */

        /* show message */
        struct VG_Image *imgp = vg4->font->totext("You loose", "[fgcolor=0xff0000]", NULL, NULL, NULL);
        vg4->window->copy(imgp, NULL, NULL);
        vg4->image->destroy(imgp);

        /* play audio */
        vg4->audio->stop(audc_bgmusic, VG_FALSE);
        vg4->audio->play(audc_gameover, VG_FALSE, VG_FALSE);

        /* wait for end of playing audio */
        while (vg4->audio->is_playing(audc_gameover, NULL)) {
          vg4->window->flush();
          vg4->misc->wait_time(40);
        }

        goto endgame;
      }

[To Position]

    pingpong.c: in game-loop: clear window, draw background, call f_draw() of all object-instances

      /* clear window and draw background */
      vg4->window->clear();
      vg4->window->fill(vg4->misc->colorbrightness(VG_COLOR_BLUE, 50));

      /* call f_draw() of all object-instances */
      vg4->object->call_draw(&sgame);

[To Position]

    pingpong.c: in game-loop: flush and wait

      /* flush contents to window and wait */
      vg4->window->flush();
      vg4->misc->wait_time(40);
    }

[To Position]

    pingpong.c: end game: destroy and exit

    endgame:
      /* destroy and exit */
      VG_dest();
      exit(0);

The files objnew.h and objcoll.c contain the exported functions for creating object-instances and checking collision between object-instances.

    objnew.h: for creating object-instances, included in pingpong.h

    #ifndef OBJNEW_H_
    #define OBJNEW_H_

    /* export-functions to create new object-instances */
    extern unsigned int objnew_PLAYER(void *);
    extern unsigned int objnew_BALL(void *);
    extern unsigned int objnew_BORDER(void *, const char *);

    #endif /* OBJNEW_H_ */

    objcoll.c: setting functions for collision-check, included in pingpong.c

    extern int objcoll_PLAYER_BALL(void *, unsigned int, struct VG_Coll *);
    extern int objcoll_PLAYER_BORDER(void *, unsigned int, struct VG_Coll *);
    extern int objcoll_BALL_BORDER(void *, unsigned int, struct VG_Coll *);

    /* add object-collision functions */
    void objcoll(void)
    {
      vg4->object->collision_add("PLAYER", "BALL", objcoll_PLAYER_BALL);
      vg4->object->collision_add("PLAYER", "BORDER", objcoll_PLAYER_BORDER);
      vg4->object->collision_add("BALL", "BORDER", objcoll_BALL_BORDER);
    }

The remaining files are the object-files and their header-files and the collision-checking-files. There are three object-files: - obj-player.c - obj-ball.c - obj-border.c They all follow the same schema: - defining the object-ID - export function for creating object-instances - free-function f_free() - run-function f_run() (not in obj-border.c as borders don't move) - draw-function f_draw() There are also three collision-checking-files: - objcoll-ball-border.c (for collision of ball and border) - objcoll-player-ball.c (for collision of player-racket and ball) - objcoll-player-border.c (for collision of player-racket and border) They all contain just the function for collision-check.
The object-file for the player-racket:

    obj-player.h

    #ifndef OBJ_PLAYER_H_
    #define OBJ_PLAYER_H_

    #include "pingpong.h"

    /* private structure for object PLAYER */
    struct sobj_player {
      struct VG_Image *imgp;  /* image */
      struct VG_Rect rect;    /* rectangle position */
    };

    #endif /* OBJ_PLAYER_H_ */

    obj-player.c: defining the object-ID

    /* Object-ID */
    #define OBJID "PLAYER"

    obj-player.c: export function for creating object-instances

    /* export-function to create a new object-instance of "PLAYER" */
    unsigned int
    objnew_PLAYER(void *vgame)
    {
      const int coll_percent = 90;
      struct s_game *sgame = (struct s_game *)vgame;
      struct VG_Object *objp;
      struct sobj_player *objvars;

      if (sgame == NULL) { return 0; }

      /* allocate private struct */
      objvars = calloc(1, sizeof(*objvars));
      if (objvars == NULL) { return 0; }

      /* set private struct */
      objvars->imgp = vg4->image->load("files/player.bmp");
      if (objvars->imgp == NULL) { return 0; }
      vg4->image->getsize(objvars->imgp, NULL, &objvars->rect.w, &objvars->rect.h);
      objvars->rect.x = 0;
      objvars->rect.y = (sgame->winh - objvars->rect.h) / 2;

      /* create object-instance */
      objp = vg4->object->create(OBJID, 0, 0, 2, objvars);

      /* set functions */
      objp->f_free = f_free;
      objp->f_run = f_run;
      objp->f_draw = f_draw;
      /* f_data(), f_childexit() and f_signal() are not needed here */

      /* insert object-instance into collision-tag */
      vg4->collision->insert(sgame->coll_tag, objp->instanceid, &objvars->rect, coll_percent);

      return objp->instanceid;
    }

    obj-player.c: free-function for the object-instances

    /* free private struct of object-instance, called from vg4->object->destroy() */
    static void
    f_free(void *vgame, void *opriv)
    {
      struct sobj_player *objvars = (struct sobj_player *)opriv;

      (void)vgame;

      /* free private struct */
      vg4->image->destroy(objvars->imgp);
      free(objvars);
    }

    obj-player.c: run-function for the object-instances

    /* move object-instance, called from vg4->object->call_run() */
    static VG_BOOL
    f_run(void *vgame, struct VG_Object *objp)
    {
      struct s_game *sgame = (struct s_game *)vgame;
      struct sobj_player *objvars = (struct sobj_player *)objp->opriv;
      int y_old;

      if (sgame == NULL) { return VG_TRUE; }

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

      y_old = objvars->rect.y;

      /* moving up */
      if (vg4->input->key_pressed(sgame->kref.k_up)) {
        objvars->rect.y -= 2;
      }

      /* moving down */
      if (vg4->input->key_pressed(sgame->kref.k_down)) {
        objvars->rect.y += 2;
      }

      /* +++ check for collisions if moved +++ */

      if (y_old != objvars->rect.y) {  /* moved */
        int canz, cret;
        struct VG_Coll *collp;

        /* update object-instance in collision-tag and check for collisions */
        canz = vg4->collision->setpos(sgame->coll_tag, objp->instanceid, &objvars->rect, &collp);

        /* call collision-functions and free collision array */
        cret = vg4->object->collision_call(sgame, objp->instanceid, collp, canz);
        if (collp != NULL) { free(collp); }

        /* check return-value */
        if (cret == VG_COLL_RETURN_STOP) {
          /* stopped, go back and update object-instance in collision-tag */
          objvars->rect.y = y_old;
          vg4->collision->setpos(sgame->coll_tag, objp->instanceid, &objvars->rect, NULL);
        }
        /* no other return-values are set in any collision-function here */
      }

      return VG_TRUE;
    }

    obj-player.c: draw-function for the object-instances

    /* draw object-instance, called from vg4->object->call_draw() */
    static void
    f_draw(void *vgame, struct VG_Object *objp)
    {
      struct sobj_player *objvars = (struct sobj_player *)objp->opriv;
      struct VG_Position posi;

      (void)vgame;

      /* draw it */
      vg4->window->copy(objvars->imgp, vg4->misc->rect2position(&posi, &objvars->rect), NULL);
    }

The other object-functions are similar.
The object-file for the ball:

    obj-ball.h

    #ifndef OBJ_BALL_H_
    #define OBJ_BALL_H_

    #include "pingpong.h"

    /* private structure for object BALL */
    struct sobj_ball {
      struct VG_Image *imgp;     /* image */
      struct VG_RectCent rectc;  /* rectangle position */
      int angle;                 /* moving direction angle */
      int factor;                /* moving velocity in 1/1000 pixels */
      int audc_hit;              /* audio-descriptor for hitting obstacle */
    };

    #endif /* OBJ_BALL_H_ */

    obj-ball.c

    /* Object-ID */
    #define OBJID "BALL"

    /* export-function to create a new object-instance of "BALL" */
    unsigned int
    objnew_BALL(void *vgame)
    {
      const int coll_percent = 90;
      struct s_game *sgame = (struct s_game *)vgame;
      struct VG_Object *objp;
      struct sobj_ball *objvars;

      if (sgame == NULL) { return 0; }

      /* allocate private struct */
      objvars = calloc(1, sizeof(*objvars));
      if (objvars == NULL) { return 0; }

      /* set private struct */
      objvars->imgp = vg4->image->load("files/ball.bmp");
      if (objvars->imgp == NULL) { return 0; }
      vg4->image->getsize(objvars->imgp, NULL, &objvars->rectc.rect.w, &objvars->rectc.rect.h);
      objvars->rectc.rect.x = (sgame->winw - objvars->rectc.rect.w) / 2;
      objvars->rectc.rect.y = (sgame->winh - objvars->rectc.rect.h) / 2;
      objvars->rectc.centx = objvars->rectc.centy = 0;
      objvars->angle = 45 + 90 * vg4->random->get("ball-angle", 0, 3);  /* randomized moving direction */
      objvars->factor = 3500;
      objvars->audc_hit = vg4->audio->load("files/hit.wav", 100, VG_AUDIO_VOLUME_SOUND);

      /* create object-instance */
      objp = vg4->object->create(OBJID, 0, 0, 3, objvars);

      /* set functions */
      objp->f_free = f_free;
      objp->f_run = f_run;
      objp->f_draw = f_draw;
      /* f_data() and f_childexit() are not needed here */

      /* insert object-instance into collision-tag */
      vg4->collision->insert(sgame->coll_tag, objp->instanceid, &objvars->rectc.rect, coll_percent);

      return objp->instanceid;
    }

    /* free private struct of object-instance, called from vg4->object->destroy() */
    static void
    f_free(void *vgame, void *opriv)
    {
      struct sobj_ball *objvars = (struct sobj_ball *)opriv;

      (void)vgame;

      /* free private struct */
      vg4->image->destroy(objvars->imgp);
      vg4->audio->unload(objvars->audc_hit);
      free(objvars);
    }

    /* move object-instance, called from vg4->object->call_run() */
    static VG_BOOL
    f_run(void *vgame, struct VG_Object *objp)
    {
      struct s_game *sgame = (struct s_game *)vgame;
      struct sobj_ball *objvars = (struct sobj_ball *)objp->opriv;
      struct VG_RectCent *rectcp;
      int rectc_nr;

      if (sgame == NULL) { return VG_TRUE; }

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

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

      /* check for collisions for each rectangle */
      if (!vg4->misc->move_and_check_collisions(vgame, objp->instanceid, &objvars->rectc, sgame->coll_tag, rectcp, rectc_nr)) {
        /* object-instance is dead (shouldn't happen!) */
        if (rectcp != NULL) { free(rectcp); }
        vg4->object->destroy(sgame, objp->instanceid);
        return VG_TRUE;
      }

      /* free moving steps */
      if (rectcp != NULL) { free(rectcp); }

      /* check if player missed ball */
      if (objvars->rectc.rect.x + objvars->rectc.rect.w <= 0) { return VG_FALSE; }

      return VG_TRUE;
    }

    /* draw object-instance, called from vg4->object->call_draw() */
    static void
    f_draw(void *vgame, struct VG_Object *objp)
    {
      struct sobj_ball *objvars = (struct sobj_ball *)objp->opriv;
      struct VG_Position posi;

      (void)vgame;

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

The object-file for the borders:

    obj-border.h

    #ifndef OBJ_BORDER_H_
    #define OBJ_BORDER_H_

    #include "pingpong.h"

    /* private structure for object BORDER */
    struct sobj_border {
      struct VG_Image *imgp;  /* image */
      struct VG_Rect rect;    /* rectangle position */
    };

    #endif /* OBJ_BORDER_H_ */

    obj-border.c

    /* Object-ID */
    #define OBJID "BORDER"

    /* export-function to create a new object-instance of "BORDER"
     * @param cposition  which border to create: "top", "bottom", "right"
     */
    unsigned int
    objnew_BORDER(void *vgame, const char *cposition)
    {
      const int coll_percent = 100;
      const int border_size = 10;  /* size of borders in pixels */
      struct s_game *sgame = (struct s_game *)vgame;
      struct VG_Object *objp;
      struct sobj_border *objvars;

      if (sgame == NULL || cposition == NULL) { return 0; }

      /* allocate private struct */
      objvars = calloc(1, sizeof(*objvars));
      if (objvars == NULL) { return 0; }

      /* set private struct */
      if (strcmp(cposition, "top") == 0) {
        objvars->rect.x = objvars->rect.y = 0;
        objvars->rect.w = sgame->winw;
        objvars->rect.h = border_size;
      } else if (strcmp(cposition, "bottom") == 0) {
        objvars->rect.x = 0;
        objvars->rect.y = sgame->winh - border_size;
        objvars->rect.w = sgame->winw;
        objvars->rect.h = border_size;
      } else if (strcmp(cposition, "right") == 0) {
        objvars->rect.x = sgame->winw - border_size;
        objvars->rect.y = 0;
        objvars->rect.w = border_size;
        objvars->rect.h = sgame->winh;
      } else {
        free(objvars);
        return 0;
      }
      objvars->imgp = vg4->image->create(objvars->rect.w, objvars->rect.h);
      vg4->image->fill(objvars->imgp, VG_COLOR_RGB(0xb1, 0, 0));

      /* create object-instance */
      objp = vg4->object->create(OBJID, 0, 0, 1, objvars);

      /* set functions */
      objp->f_free = f_free;
      objp->f_draw = f_draw;
      /* f_run(), f_data() and f_childexit() are not needed here */

      /* insert object-instance into collision-tag */
      vg4->collision->insert(sgame->coll_tag, objp->instanceid, &objvars->rect, coll_percent);

      return objp->instanceid;
    }

    /* free private struct of object-instance, called from vg4->object->destroy() */
    static void
    f_free(void *vgame, void *opriv)
    {
      struct sobj_border *objvars = (struct sobj_border *)opriv;

      (void)vgame;

      /* free private struct */
      vg4->image->destroy(objvars->imgp);
      free(objvars);
    }

    /* draw object-instance, called from vg4->object->call_draw() */
    static void
    f_draw(void *vgame, struct VG_Object *objp)
    {
      struct sobj_border *objvars = (struct sobj_border *)objp->opriv;
      struct VG_Position posi;

      (void)vgame;

      /* draw it */
      vg4->window->copy(objvars->imgp, vg4->misc->rect2position(&posi, &objvars->rect), NULL);
    }

And now the object-collision functions:

    objcoll-ball-border.c: collision of ball and border

    #include "obj-ball.h"
    #include "obj-border.h"

    int
    objcoll_BALL_BORDER(void *vgame, unsigned int instanceid, struct VG_Coll *collb)
    {
      struct VG_Object *objp;
      struct sobj_ball *objvars_ball;
      int xdelta, ydelta;
      int retw = VG_COLL_RETURN_CONTINUE;

      (void)vgame;

      /* only entering into collision is interesting here */
      if (collb->type != VG_COLL_TYPE_ENTRY) { return retw; }

      /* get private structure of moving object-instance */
      objp = vg4->object->instance_getobj(instanceid);
      { int erg = strcmp(objp->objid, "BALL"); assert(erg == 0); }  /* border doesn't move */
      objvars_ball = (struct sobj_ball *)objp->opriv;

      /* check collision sides of hit object-instance (border) */
      if (collb->side & VG_COLL_SIDE_LEFT) {
        vg4->misc->xy_from_angle(objvars_ball->angle, &xdelta, &ydelta);
        xdelta = -xdelta;
        objvars_ball->angle = vg4->misc->angle_from_xy(xdelta, ydelta, NULL);
        retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (ball) */
      }
      if (collb->side & (VG_COLL_SIDE_TOP | VG_COLL_SIDE_BOTTOM)) {
        vg4->misc->xy_from_angle(objvars_ball->angle, &xdelta, &ydelta);
        ydelta = -ydelta;
        objvars_ball->angle = vg4->misc->angle_from_xy(xdelta, ydelta, NULL);
        retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (ball) */
      }
      if (retw == VG_COLL_RETURN_STOP) { vg4->audio->play(objvars_ball->audc_hit, VG_FALSE, VG_FALSE); }

      return retw;
    }

    objcoll-player-ball.c: collision of player-racket and ball

    #include "obj-player.h"
    #include "obj-ball.h"

    int
    objcoll_PLAYER_BALL(void *vgame, unsigned int instanceid, struct VG_Coll *collb)
    {
      struct VG_Object *objp;
      struct sobj_ball *objvars_ball;
      int xdelta, ydelta;
      int retw = VG_COLL_RETURN_CONTINUE;

      (void)vgame;

      /* only entering into collision is interesting here */
      if (collb->type != VG_COLL_TYPE_ENTRY) { return retw; }

      /* act according to moving object-instance */

      objp = vg4->object->instance_getobj(instanceid);

      if (strcmp(objp->objid, "PLAYER") == 0) {
        /* PLAYER is moving, hitting BALL */
        objp = vg4->object->instance_getobj(collb->instanceid);
        objvars_ball = (struct sobj_ball *)objp->opriv;

        /* check collision sides of hit object-instance (ball) */
        if (collb->side & VG_COLL_SIDE_LEFT) {
          /* set new moving-angle of ball */
          vg4->misc->xy_from_angle(objvars_ball->angle, &xdelta, &ydelta);
          xdelta = -xdelta;
          objvars_ball->angle = vg4->misc->angle_from_xy(xdelta, ydelta, NULL);
          retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (player) */
        }
        if (collb->side & (VG_COLL_SIDE_TOP | VG_COLL_SIDE_BOTTOM)) {
          /* set new moving-angle of ball */
          vg4->misc->xy_from_angle(objvars_ball->angle, &xdelta, &ydelta);
          ydelta = -ydelta;
          objvars_ball->angle = vg4->misc->angle_from_xy(xdelta, ydelta, NULL);
          retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (player) */
        }

      } else {
        /* BALL is moving, hitting PLAYER */
        objvars_ball = (struct sobj_ball *)objp->opriv;

        /* check collision sides of hit object-instance (player) */
        if (collb->side & VG_COLL_SIDE_RIGHT) {
          /* set new moving-angle of ball */
          vg4->misc->xy_from_angle(objvars_ball->angle, &xdelta, &ydelta);
          xdelta = -xdelta;
          objvars_ball->angle = vg4->misc->angle_from_xy(xdelta, ydelta, NULL);
          retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (ball) */
        }
        if (collb->side & (VG_COLL_SIDE_TOP | VG_COLL_SIDE_BOTTOM)) {
          /* set new moving-angle of ball */
          vg4->misc->xy_from_angle(objvars_ball->angle, &xdelta, &ydelta);
          ydelta = -ydelta;
          objvars_ball->angle = vg4->misc->angle_from_xy(xdelta, ydelta, NULL);
          retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (ball) */
        }
      }

      /* play hit-sound if collision */
      if (retw == VG_COLL_RETURN_STOP) { vg4->audio->play(objvars_ball->audc_hit, VG_FALSE, VG_FALSE); }

      return retw;
    }

    objcoll-player-border.c: collision of player-racket and border

    #include "obj-player.h"
    #include "obj-border.h"

    int
    objcoll_PLAYER_BORDER(void *vgame, unsigned int instanceid, struct VG_Coll *collb)
    {
      struct VG_Object *objp;
      int retw = VG_COLL_RETURN_CONTINUE;

      (void)vgame;

      /* only entering into collision is interesting here */
      if (collb->type != VG_COLL_TYPE_ENTRY) { return retw; }

      /* get moving object-instance */
      objp = vg4->object->instance_getobj(instanceid);
      { int erg = strcmp(objp->objid, "PLAYER"); assert(erg == 0); }  /* border doesn't move */

      retw = VG_COLL_RETURN_STOP;  /* stop moving object-instance (player) */

      return retw;
    }

<<Previous | Download | Next>>