Tutorial 8 

To enhance our network-game we want to select our player-racket before the game-loop begins. For the selection we create a new canvas racket.cvas.
At first an overview about modifications in the file pingpong.c.
pingpong.c: Overview about modifications /* global declarations */ [CODEBOX] /* main function */ int main(int argc, char **argv) { /* variable declaration */ [CODEBOX] /* initializing */ [...] /* opening, collision functions and tag, loading audio files */ [...] /* set keys */ [...] /* show help */ [...] /* connect to network-server */ [CODEBOX] /* select player-racket and get selections of all clients */ [CODEBOX] /* create object-instances */ [...] /* start background music */ /* game loop */ [...] /* receive input-events and check the local key-strokes */ [...] /* call f_run() of all object-instances */ [...] /* clear window, draw background, call f_draw() of all object-instances */ [...] /* flush and wait */ /* end game */ [...] /* destroy and exit */ }
The global declarations of the file pingpong.c.
We add the function for selecting a player-racket
and a boolean constant, whether selection of player-racket shall be exclusive,
whether the player-rackets must have different color.
[To Position]
pingpong.c: global declarations /* whether selection of player-racket shall be exclusive */ static const VG_BOOL sel_excl = VG_TRUE; /* object-collision functions */ extern void objcoll(void); /* connect to nw-server */ extern int connect_to_nwserver(int); /* selections */ extern VG_BOOL select_racket(struct VG_Image ***, VG_BOOL);
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 */ int clnr, clmax, cli; /* local client-number, number of clients, control variable */ VG_BOOL dowait; /* whether vg4->misc->wait_time() shall be called */ struct VG_Image **imgpp;
Now we select our player-racket
and retrieve the selections of all clients.
These selections are returned as loaded images for each client.
[To Position]
pingpong.c: select player-racket and get selections of all clients /* select player-racket and get selections of all clients */ if (!select_racket(&imgpp, sel_excl)) { VG_dest(); exit(1); }
When creating the two players we additionally pass the player-racket images,
which were returned by select_racket().
[To Position]
pingpong.c: create object-instances /* create object-instances */ for (cli = 1; cli <= clmax; cli++) { /* a player for each client */ if (imgpp[cli - 1] != NULL) { if (objnew_PLAYER(&sgame, cli, imgpp[cli - 1]) == 0) { VG_dest(); exit(1); } } } free(imgpp); /* free images */ 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); }
The object-file for the player-racket is changed as the image is passed.
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, int clnr, struct VG_Image *imgp) { 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; } if (clnr < 1) { return 0; } /* allocate private struct */ objvars = calloc(1, sizeof(*objvars)); if (objvars == NULL) { return 0; } /* set private struct */ objvars->imgp = imgp; if (objvars->imgp == NULL) { return 0; } vg4->image->getsize(objvars->imgp, NULL, &objvars->rect.w, &objvars->rect.h); /* first connected player shall be the left player, the second the right player */ if (clnr == 1) { objvars->rect.x = 0; objvars->rect.y = (sgame->winh - objvars->rect.h) / 2; if (clnr == vg4->nw->local_clnr()) { sgame->ply_local = PLY_LEFT; } } else { objvars->rect.x = sgame->winw - objvars->rect.w; objvars->rect.y = (sgame->winh - objvars->rect.h) / 2; if (clnr == vg4->nw->local_clnr()) { sgame->ply_local = PLY_RIGHT; } } objvars->clnr = clnr; /* 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() 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; }
The new file rk_select.c to select the player-racket
before the game-loop.
rk_select.c: select player-racket and get selections of all clients /* show info */ static void show_info(const char *text) { struct VG_Image *img; if (text == NULL || *text == '\0') { return; } img = vg4->font->totext(text, NULL, NULL, NULL, NULL); vg4->window->clear(); vg4->window->copy(img, NULL, NULL); vg4->window->flush(); vg4->image->destroy(img); } /* execute canvas to select player-racket * @param rkname for returning name of racket * @param rksize sizeof(rkname) * @param xdatalist exchange-data list of already received clients * @return VG_TRUE = OK or VG_FALSE = got exit-request */ static VG_BOOL exec_canvas_racket(char *rkname, size_t rksize, struct VG_NwXdataList *xdatalist) { const char *chain_name = "rk_chain"; struct VG_Canvas *cvas; const char *selname; struct VG_NwXdataList *xdptr; if (rkname == NULL || rksize == 0) { return VG_FALSE; } *rkname = '\0'; /* load canvas */ cvas = vg4->canvas->load("files/canvas/racket.cvas", NULL); if (cvas == NULL) { return VG_FALSE; } /* disable chain-elements of already set player-rackets */ for (xdptr = xdatalist; xdptr != NULL; xdptr = xdptr->next) { vg4->canvas->chain_disable(cvas, chain_name, xdptr->data, VG_TRUE); } for (;;) { /* execute canvas */ if (!vg4->canvas->exec(cvas, NULL, &selname)) { return VG_FALSE; } if (selname == NULL) { break; } /* cancelled via escape-key or cancel-button */ /* act according to selection */ if (*selname == '\0') { /* no selection, but return-key pressed */ /* no action, re-execute canvas */ ; } else if (strcmp(selname, chain_name) == 0) { /* item selected from chain */ const char *chainkey = vg4->canvas->chain_get_activated(cvas, selname); if (chainkey != NULL) { vg4->misc->strcpy(rkname, rksize, chainkey); break; } } } vg4->canvas->destroy(cvas); if (*rkname == '\0') { return VG_FALSE; } return VG_TRUE; } /* select a player-racket and receive selections of each clients * @param imgpp for returning an array of images, * the index represents the client-number (0 = client1, 1 = client2, ...), * the value is the image for its client or NULL if the client has disconnected, * the array's size is the number of clients * @param exclusive whether player-rackets must be unique * @return VG_TRUE = OK or VG_FALSE = got exit request */ VG_BOOL select_racket(struct VG_Image ***imgpp, VG_BOOL exclusive) { struct VG_NwXdataList *xdatalist, *xdptr; int idx, clnr, clmax; char rkname[32], filename[256]; VG_BOOL redo; if (imgpp == NULL) { return VG_TRUE; } *imgpp = NULL; clnr = vg4->nw->local_clnr(); clmax = vg4->nw->numberofclients(NULL); if (clnr == 0 || clmax == 0) { return VG_TRUE; } xdatalist = NULL; /* set a new tag */ vg4->nw->xdata_retag(); reselect: /* select player-racket */ if (!exec_canvas_racket(rkname, sizeof(rkname), xdatalist)) { return VG_FALSE; } /* show info */ show_info("Receiving player-rackets ..."); /* send selected player-racket to network-server */ if (!vg4->nw->xdata_send(rkname, strlen(rkname) + 1)) { return VG_FALSE; } /* receive player-rackets of each client from network-server */ if (!vg4->nw->xdata_allclients_recv(&xdatalist, exclusive, rkname, strlen(rkname) + 1, &redo)) { return VG_FALSE; } if (redo) { /* select another player-racket */ show_info("Selected racket is no more available"); sleep(3); vg4->window->clear(); goto reselect; } /* create image array and load images */ *imgpp = calloc(clmax, sizeof(**imgpp)); if (*imgpp == NULL) { fprintf(stderr, "calloc: %s\n", strerror(errno)); return VG_FALSE; } for (idx = 0; idx < clmax; idx++) { (*imgpp)[idx] = NULL; } for (xdptr = xdatalist; xdptr != NULL; xdptr = xdptr->next) { snprintf(filename, sizeof(filename), "files/player-%s.bmp", xdptr->data); (*imgpp)[xdptr->clnr - 1] = vg4->image->load(filename); } /* free exchange-data list */ vg4->nw->xdata_allclients_free(xdatalist); return VG_TRUE; }
At last the canvas-file to select the player-racket.
files/canvas/racket.cvas: canvas-file for selecting player-racket
# we don't use an image as background, but draw it ourself: a blue box with a red frame
[MAIN]
%{txt[
# red frame
boxwidth=200
boxheight=150
bgcolor=0xb10000
orientation=center
v-orientation=center
]: %{txt[
# blue box
boxwidth=180
boxheight=130
bgcolor=0x000088
utag-title=10+160,8+12
utag-rk_chain=20+140,30+80
]:%}
%}
[VAR-DEFAULT]
var.title: Select player-racket
[MOUSE]
disable: 0
[FONT]
sys:low
# the title of the canvas
[CV-TEXT]
name: title
position-itag: title
default-text: %{var: title%}
text.orientation: center+left
text.v-orientation: center
text.fgcolor: 0xffff00
text.nowrap: 1
# the selection-chain for the player-rackets
[CV-CHAIN]
name: rk_chain
position-itag: rk_chain
element.red: img:../player-red.bmp
element.yellow: img:../player-yellow.bmp
element.green: img:../player-green.bmp
element.blue: img:../player-blue.bmp
<<Previous |
Download ![]() |
Next>> |