diff options
author | taw27 <taw27@84d2e878-0bd5-11dd-ad15-13eda11d74c5> | 2008-07-17 23:00:50 +0000 |
---|---|---|
committer | taw27 <taw27@84d2e878-0bd5-11dd-ad15-13eda11d74c5> | 2008-07-17 23:00:50 +0000 |
commit | 55b4d0487c9222dd9bdc76dda0fd990d188d7e32 (patch) | |
tree | a2c1afea093356969c49eb634631b53597d8f428 | |
parent | ea00365953dac518b388817261430d0efd451aa3 (diff) |
Restore collision detection, apparently fixing the 'drop through floors' problem
git-svn-id: svn://cook.msm.cam.ac.uk:745/thrust3d/thrust3d@138 84d2e878-0bd5-11dd-ad15-13eda11d74c5
-rw-r--r-- | src/physics.c | 101 |
1 files changed, 49 insertions, 52 deletions
diff --git a/src/physics.c b/src/physics.c index 39a3e09..c6d4dd9 100644 --- a/src/physics.c +++ b/src/physics.c @@ -89,7 +89,7 @@ int physics_point_is_inside_hull(double cx, double cy, double cz, double *fvert, int physics_will_collide_face(double sx, double sy, double sz, double vx, double vy, double vz, double nx, double ny, double nz, double *fvert, int nfvert, Uint32 dt, - ModelInstance *obj, double *ttc) { + double *ttc) { double px, py, pz; double pdotn, sdotn, vdotn; @@ -115,24 +115,8 @@ int physics_will_collide_face(double sx, double sy, double sz, double vx, double cy = sy + vy * t; cz = sz + vz * t; if ( physics_point_is_inside_hull(cx, cy, cz, fvert, nfvert, nx, ny, nz) == 1 ) { - - char *name; - - if ( obj == NULL ) { - name = "unknown"; - } else { - name = obj->model->name; - } - - // printf("Testing vertex %8f %8f %8f, velocity %8f %8f %8f against face %8f %8f %8f (%s/%p)\n", - // sx, sy, sz, vx, vy, vz, px, py, pz, name, obj); - // printf("(%f - %f) / %f\n", pdotn, sdotn, vdotn); - // printf("Collision happens at t + %f\n", t); - // exit(0); - *ttc = t; return 1; - } return 0; @@ -141,9 +125,10 @@ int physics_will_collide_face(double sx, double sy, double sz, double vx, double /* Check for collision with all faces in a primitive */ static int physics_check_collide_all_faces(ModelInstance *obj, ModelInstance *other, Uint32 dt, int a, - double sx, double sy, double sz, double vx, double vy, double vz, - CollisionSpec *coll) { + double sx, double sy, double sz, CollisionSpec *coll) { + int found = 0; + switch ( other->model->primitives[a]->type ) { case PRIMITIVE_QUADS : { @@ -162,7 +147,7 @@ static int physics_check_collide_all_faces(ModelInstance *obj, ModelInstance *ot const double nz = other->model->primitives[a]->normals[3*(4*f)+2]; /* Skip if moving from the back to the front of this quad */ - if ( nx*vx + ny*vy + nz*vz > 0.0 ) continue; + if ( nx*obj->vx + ny*obj->vy + nz*obj->vz > 0.0 ) continue; for ( q=0; q<4; q++ ) { face[3*q + 0] = other->x + other->model->primitives[a]->vertices[3*((4*f)+q) + 0]; @@ -170,14 +155,19 @@ static int physics_check_collide_all_faces(ModelInstance *obj, ModelInstance *ot face[3*q + 2] = other->z + other->model->primitives[a]->vertices[3*((4*f)+q) + 2]; } - if ( physics_will_collide_face(sx, sy, sz, vx, vy, vz, nx, ny, nz, face, 4, dt, other, &ttc) != 0 ) { + if ( physics_will_collide_face(obj->x+sx, obj->y+sy, obj->z+sz, obj->vx, obj->vy, obj->vz, + nx, ny, nz, face, 4, dt, &ttc) != 0 ) { + /* Update 'coll' if this collision happens sooner than the current best */ if ( ttc < coll->ttc ) { - printf("PH: collides with %s/%p in %5.2f ms\n", other->model->name, other, ttc); coll->ttc = ttc; coll->nx = nx; coll->ny = ny; coll->nz = nz; + coll->cx = obj->x + ttc*obj->vx; + coll->cy = obj->y + ttc*obj->vy; + coll->cz = obj->z + ttc*obj->vz; + found = 1; } } @@ -188,73 +178,61 @@ static int physics_check_collide_all_faces(ModelInstance *obj, ModelInstance *ot } - return 0; + return found; } -/* Return non-zero if 'obj' will collide with 'other' with 'dt' milliseconds */ +/* Return non-zero if 'obj' will collide with 'other' within 'dt' milliseconds */ static int physics_check_collide(ModelInstance *obj, ModelInstance *other, double dt, CollisionSpec *coll) { int i; + int found = 0; - const double vx = obj->vx; - const double vy = obj->vy; - const double vz = obj->vz; - - double ttc_lowest = +INFINITY; - - /* Consider all the primitives in 'obj' */ + /* Check all the vertices in the moving object... */ for ( i=0; i<obj->model->num_primitives; i++ ) { - int j; - - /* Consider all the vertices in this primitive */ for ( j=0; j<obj->model->primitives[i]->num_vertices; j++ ) { int a; - const double sx = obj->x + obj->model->primitives[i]->vertices[3*j+0]; - const double sy = obj->y + obj->model->primitives[i]->vertices[3*j+1]; - const double sz = obj->z + obj->model->primitives[i]->vertices[3*j+2]; + const double sx = obj->model->primitives[i]->vertices[3*j+0]; + const double sy = obj->model->primitives[i]->vertices[3*j+1]; + const double sz = obj->model->primitives[i]->vertices[3*j+2]; - /* Consider all the primitives in 'other' */ + /* ...against all primitives in the static object */ for ( a=0; a<other->model->num_primitives; a++ ) { - physics_check_collide_all_faces(obj, other, dt, a, sx, sy, sz, vx, vy, vz, coll); + if ( physics_check_collide_all_faces(obj, other, dt, a, sx, sy, sz, coll) ) { + found = 1; + } } } } - if ( ttc_lowest == +INFINITY ) return 0; - - if ( ttc_lowest > dt ) { - printf("PH: will collide with %s/%8p, but too far in the future at %5.2f ms\n", other->model->name, other, ttc_lowest); - return 0; - } - - return 1; + return found; } +/* Find the earliest collision for 'obj'. Fill out 'coll' and return 1 if any */ static int physics_find_earliest_collision(ModelInstance *obj, Game *game, double dt, CollisionSpec *coll) { Room *room; + int found = 0; /* Consider only the current room, for now */ room = game_find_room(game, game->cur_room_x, game->cur_room_y, game->cur_room_z); if ( room != NULL ) { - /* Consider all the objects in this room */ + /* Check for collision of this object with all other objects in the room */ int j; - for ( j=0; j<room->num_objects; j++ ) { if ( physics_check_collide(obj, room->objects[j], dt, coll) ) { - return 1; + found = 1; } } } - return 0; + return found; } @@ -306,19 +284,38 @@ static void physics_process(ModelInstance *obj, Uint32 dt, Game *game) { do { CollisionSpec coll; - collided = physics_find_earliest_collision(obj, game, dt, &coll); + coll.ttc = +HUGE_VAL; + coll.nx = 0.0; coll.ny = 0.0; coll.nz = 0.0; + coll.cx = 0.0; coll.cy = 0.0; coll.cz = 0.0; + collided = physics_find_earliest_collision(obj, game, dt-sttc, &coll); if ( collided ) { + /* Step forward to the point of collision */ + obj->x = coll.cx; + obj->y = coll.cy; + obj->z = coll.cz; + + sttc += coll.ttc; + + /* Can we land here? */ if ( (coll.nx==0) && (coll.ny==0) && (coll.nz==1.0) ) { + /* Yes - land (already moved to this position */ obj->landed = 1; obj->vx = 0.0; obj->vy = 0.0; obj->vz = 0.0; + } else { + /* No - bounce */ + audio_play(game->audio, "clang", 1.0, 0); + obj->vx = -obj->vx; + obj->vy = -obj->vy; + obj->vz = -obj->vz; } } else { + /* No further collision - perform the 'end step' */ obj->x += obj->vx * (dt-sttc); obj->y += obj->vy * (dt-sttc); obj->z += obj->vz * (dt-sttc); |