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 */ [...] }; #endifsunnyboy.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 */ [...] }; #endifsunnyboy.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