VgaGames 3 - Miscellaneous man-pages

[.. upper level ..]

VG3_move_object_check_collision()

Simplifying function to move an object-instance and check for collision while moving.
SYNTAX
int VG3_move_object_check_collision(void *vgame, struct vg3_ofunc *ofstruct, struct vg3_quadtree *qdtr, struct vg3_ofunc_object *objp, struct vg3_rect *opos, int factor, int *xdelta, int *ydelta, int *xremainder, int *yremainder)

FUNCTION PARAMETERS
vgame Individual game structure
ofstruct Common VgaGames3-object structure
qdtr Quadtree containing all object-instances
objp Object-instance
opos Position of object-instance (including width and height),
when returning the position will be updated,
but width and height will not be changed
factor Factor in 1/10 to multiply xdelta and ydelta for each step.
This will usually be a constant value for each object
xdelta Address to x-direction step size in 1/100 pixels for each step,
This address must be the same the function f_collision() eventually uses.
The value must be in the range between -100 and 100.
ydelta Address to y-direction step size in 1/100 pixels for each step,
This address must be the same the function f_collision() eventually uses.
The value must be in the range between -100 and 100.
xremainder Contains and returns remainders of x-direction, which still could not be moved
yremainder Contains and returns remainders of y-direction, which still could not be moved

RETURN VALUE
Returns one value of VGAG3_COLL_RETURNS, but not VGAG3_COLL_RETURN_CONTINUE, or -1 on failure

ERRORS
On error VG3_errmsg() returns: EINVAL - error in argument ENOMEM - cannot get memory or any return value of function f_collision()

DESCRIPTION
Function to move an object-instance from the actual position to the target position, checking at each step for collisions. For each found collision the function f_collision(), which must be set for each object indivdually in the struct vg3_ofunc_objobjfunc will be called. The first object (objp1) is always the function-calling one (the moving and hitting), the second object (objp2) is the object being hit. This f_collision() should check the collision according to both passed object-instances and decide which has to be happened: - no collision: return VGAG3_COLL_RETURN_NOOP - hit: do actions with both objects, if not needed any more, free them, return VGAG3_COLL_RETURN_DEAD if the first object (the calling one) has been freed, return VGAG3_COLL_RETURN_HIT if the first object (the calling one) is still existing - no hit but stop moving: return VGAG3_COLL_RETURN_FULLSTOP or VGAG3_COLL_RETURN_HALFSTOP - collision but continue moving, perhaps changing direction: eventually correct the element side of the parameter collret of the function f_collision() to a set of VGAG3_COLLSIDES, or change side to 0 if this collision shall not to be counted, and return VGAG3_COLL_RETURN_CONTINUE - error: set error number and text with VG3_seterror() and return -1 At last this function VG3_move_object_check_collision() returns - VGAG3_COLL_RETURN_NOOP: if no collision occurred - VGAG3_COLL_RETURN_HIT: if collision has been occurred - VGAG3_COLL_RETURN_DEAD: if collision destroys the calling object-instance - VGAG3_COLL_RETURN_HALFSTOP: if collision stopped object-instance at one direction - VGAG3_COLL_RETURN_FULLSTOP: if collision stopped object-instance - VGAG3_COLL_RETURN_CATCHED: if object-instance is badly catched in collision and cannot move anymore - kill it - -1: failure Normally just the following return-values have to be checked: -1: return with error VGAG3_COLL_RETURN_DEAD: return immediatelly without freeing VGAG3_COLL_RETURN_CATCHED: free and return

EXAMPLE
Excerpt showing collision-functions of sunnyboy with a shot and a wall:
  

game.h

#ifndef GAME_H_ #define GAME_H_ #include <vgagames3.h> struct game { /* individual game structure */ struct vg3_quadtree *qdtr; /* Quadtree */ struct vg3_ofunc *ofstruct; /* common VgaGames3-object structure */ [...] }; #endif

sunnyboy.h

#ifndef SUNNYBOY_H_ #define SUNNYBOY_H_ struct sboy { /* private structure for sunnyboy object */ struct vg3_rect rect; /* position of sunnyboy (and also collision rectangle) */ int xdelta, ydelta; /* moving sunnyboy in x- and y-direction */ int xremainder, yremainder; /* remainders of sunnyboy-moving */ [...] }; #endif

sunnyboy.c

/* sunnyboy object */ #include "game.h" #include "sunnyboy.h" [...] /* create a new sunnyboy-instance */ static struct vg3_ofunc_object * f_new(void *vgame, unsigned int parent_objid, ...) { struct vg3_ofunc_object *objp = calloc(1, sizeof(*objp)); /* create VgaGames3-object structure */ struct sboy *gobj = calloc(1, sizeof(*gobj)); /* create private structure */ [...] gobj->xdelta = 100; /* in f_run() move sunnyboy 1 pixel to the right */ gobj->ydelta = 0; gobj->xremainder = 0; gobj->yremainder = 0; [...] return objp; } [...] /* move a sunnyboy-instance */ static void f_run(void *vgame, struct vg3_ofunc_object *objp) { const int factor = 10; /* multiply xdelta and ydelta with 1 (=10/10) */ struct game *gstruct = (struct game *)vgame; struct sboy *gobj; struct vg3_coll coll; int erg; gobj = (struct sboy *)objp->ostruct; /* remove sunnyboy-instance from quadtree */ VG3_coll_q_remove(gmain->qdtr, objp); /* move sunnyboy according to gobj->xdelta/gobj->ydelta and factor and check for collisions, * at return this function will have modified: * - the position: gobj->rect * - perhaps the movement: gobj->xdelta, gobj->ydelta * - perhaps the remainders: gobj->xremainder, gobj->yremainder */ erg = VG3_move_object_check_collision( gstruct, gstruct->ofstruct, gstruct->qdtr, objp, &gobj->rect, factor, &gobj->xdelta, &gobj->ydelta, &gobj->xremainder, &gobj->yremainder); /* now act according to the return value */ if (erg < 0) { /* error: destroy sunnyboy-instance */ f_free(gstruct, objp); return; } if (erg == VGAG3_COLL_RETURN_DEAD) { /* sunnyboy-instance collides and has been freed */ return; } if (erg == VGAG3_COLL_RETURN_CATCHED) { /* unmovable: destroy sunnyboy-instance */ f_free(gmain, objp); return; } /* VGAG3_COLL_RETURN_HALFSTOP or VGAG3_COLL_RETURN_FULLSTOP or VGAG3_COLL_RETURN_NOOP: ok */ [...] /* now insert sunnyboy-instance into quadtree again */ memset(&coll, 0, sizeof(coll)); coll.rect = gobj->rect; /* we use gobj->rect for position and collision */ snprintf(coll.oid, sizeof(coll.oid), "Sunnyboy"); coll.optr = objp; VG3_coll_q_insert(gmain->qdtr, &coll); }

objobj-sunnyboy-shot.c

/* object-to-object code for sunnyboy and shot */ #include <vgagames3.h> #include "game.h" #include "sunnyboy.h" #include "shot.h" void getoofc_sunnyboy_shot(struct vg3_ofunc_objobjfunc *oofc) { snprintf(oofc->oid1, sizeof(oofc->oid1), "sunnyboy"); snprintf(oofc->oid2, sizeof(oofc->oid2), "shot"); oofc->f_collision = f_collision; } /* collision-function between sunnyboy and shot: destroys both */ static int f_collision(void *vgame, struct vg3_ofunc_object *objp1, struct vg3_ofunc_object *objp2, struct vg3_coll_ret *collret) { struct game *gstruct = (struct game *)vgame; struct sboy *sunnyboy; /* sunnyboy object-instance */ struct shot *shot; /* shot object-instance */ const struct vg3_ofunc_objfunc *ofc_sunnyboy, *ofc_shot; struct vg3_ofunc_object *objp_sunnyboy, *objp_shot; /* get private structs of both */ if (strcmp(objp1->oid, "shot") == 0) { /* objp1 = shot and objp2 = sunnyboy */ objp_shot = objp1; objp_sunnyboy = objp2; shot = (struct shot *)objp1->ostruct; sunnyboy = (struct sboy *)objp2->ostruct; ofc_shot = VG3_ofunc_get_objfunc(gstruct->ofstruct, objp1->oid); ofc_sunnyboy = VG3_ofunc_get_objfunc(gstruct->ofstruct, objp2->oid); } else { /* objp1 = sunnyboy and objp2 = shot */ objp_shot = objp2; objp_sunnyboy = objp1; shot = (struct shot *)objp2->ostruct; sunnyboy = (struct sboy *)objp1->ostruct; ofc_shot = VG3_ofunc_get_objfunc(gstruct->ofstruct, objp2->oid); ofc_sunnyboy = VG3_ofunc_get_objfunc(gstruct->ofstruct, objp1->oid); } /* destroy both object-instance */ if (ofc_shot != NULL && ofc_shot->f_free != NULL) { ofc_shot->f_free(gstruct, objp_shot); } if (ofc_sunnyboy != NULL && ofc_sunnyboy->f_free != NULL) { ofc_sunnyboy->f_free(gstruct, objp_sunnyboy); } /* return DEAD-HIT of own object-instance (this is always objp1) */ return VGAG3_COLL_RETURN_DEAD; }

objobj-sunnyboy-wall.c

/* object-to-object code for sunnyboy and wall */ #include <vgagames3.h> #include "game.h" #include "sunnyboy.h" #include "wall.h" void getoofc_sunnyboy_wall(struct vg3_ofunc_objobjfunc *oofc) { snprintf(oofc->oid1, sizeof(oofc->oid1), "sunnyboy"); snprintf(oofc->oid2, sizeof(oofc->oid2), "wall"); oofc->f_collision = f_collision; } /* collision-function between sunnyboy and wall: invert moving-direction of sunnyboy */ static int f_collision(void *vgame, struct vg3_ofunc_object *objp1, struct vg3_ofunc_object *objp2, struct vg3_coll_ret *collret) { struct game *gstruct = (struct game *)vgame; struct sboy *sunnyboy; /* sunnyboy object-instance */ struct wall *wall; /* wall object-instance */ const struct vg3_ofunc_objfunc *ofc; /* get private structs of both */ if (strcmp(objp1->oid, "wall") == 0) { /* objp1 = wall and objp2 = sunnyboy */ wall = (struct wall *)objp1->ostruct; sunnyboy = (struct sboy *)objp2->ostruct; } else { /* objp1 = sunnyboy and objp2 = wall */ wall = (struct wall *)objp2->ostruct; sunnyboy = (struct sboy *)objp1->ostruct; } /* correct moving-direction of sunnyboy according to collision-side of wall; * there is no need to change collret->side */ if (collret->side & (VGAG3_COLLSIDE_LEFT | VGAG3_COLLSIDE_RIGHT)) { sunnyboy->xdelta = -sunnyboy->xdelta; } if (collret->side & (VGAG3_COLLSIDE_TOP | VGAG3_COLLSIDE_BOTTOM)) { sunnyboy->ydelta = -sunnyboy->ydelta; } /* continue with new moving-direction */ return VGAG3_COLL_RETURN_CONTINUE; }

SEE ALSO
Collision functions VgaGames3-object functions