Fixed incorrect/missing calculation of collision point in check_vector_to_sphere_1 and added special check in check_vector_to_object to only apply for certain objects; Removed extrapolation of physics as it would unintentionally cause premature collisions (requires further fixing of do_physics_sim and do_physics_sim_rot to properly scale to FrameTime)

This commit is contained in:
zico 2014-08-17 23:56:08 +02:00
parent 3ea6b0eb18
commit d2b0a4d02d
2 changed files with 43 additions and 34 deletions

View file

@ -414,7 +414,7 @@ static int special_check_line_to_face(vms_vector *newp,const vms_vector *p0,cons
//vector defined by p0,p1
//returns dist if intersects, and fills in intp
//else returns 0
static int check_vector_to_sphere_1(vms_vector *intp,const vms_vector *p0,const vms_vector *p1,const vms_vector *sphere_pos,fix sphere_rad)
static int check_vector_to_sphere_1(vms_vector *intp,const vms_vector *p0,const vms_vector *p1,const vms_vector *sphere_pos,fix sphere_rad,sbyte haveignoreobj)
{
vms_vector d,dn,w,closest_point;
fix mag_d,dist,w_dist,int_dist;
@ -454,11 +454,25 @@ static int check_vector_to_sphere_1(vms_vector *intp,const vms_vector *p0,const
int_dist = w_dist-shorten;
if (int_dist > mag_d || int_dist < 0) {
//past one or the other end of vector, which means we're inside
*intp = *p0; //don't move at all
return 1;
if (int_dist > mag_d || int_dist < 0) //past one or the other end of vector, which means we're inside
{
if (haveignoreobj) // see comment in check_vector_to_object on why we do this...
{
*intp = *p0; //don't move at all
return 1;
}
else
{
//past one or the other end of vector, which means we're inside? WRONG! Either you're inside OR you didn't quite make it!
if(vm_vec_dist(p0, sphere_pos) < sphere_rad)
{
*intp = *p0; //don't move at all
vm_vec_scale_add(intp,p0,&dn,int_dist); //calc intersection point
return int_dist;
} else {
return 0;
}
}
}
vm_vec_scale_add(intp,p0,&dn,int_dist); //calc intersection point
@ -578,11 +592,21 @@ static int check_vector_to_sphere_1(vms_vector *intp,const vms_vector *p0,const
//$$}
*/
//determine if a vector intersects with an object
//if no intersects, returns 0, else fills in intp and returns dist
static fix check_vector_to_object(vms_vector *intp,const vms_vector *p0,const vms_vector *p1,fix rad,const object *obj,const object *otherobj)
{
fix size = obj->size;
sbyte i = 0, haveignoreobj = 0;
#if defined(DXX_BUILD_DESCENT_I)
const static int numignore = 10;
static const ubyte ignoreobjs[numignore] = { OBJ_NONE, OBJ_FIREBALL, OBJ_HOSTAGE, OBJ_CAMERA, OBJ_POWERUP, OBJ_DEBRIS, OBJ_CLUTTER, OBJ_GHOST, OBJ_LIGHT, OBJ_COOP };
#elif defined(DXX_BUILD_DESCENT_II)
const static int numignore = 11;
static const ubyte ignoreobjs[numignore] = { OBJ_NONE, OBJ_FIREBALL, OBJ_HOSTAGE, OBJ_CAMERA, OBJ_POWERUP, OBJ_DEBRIS, OBJ_CLUTTER, OBJ_GHOST, OBJ_LIGHT, OBJ_COOP, OBJ_MARKER };
#endif
if (obj->type == OBJ_ROBOT && Robot_info[get_robot_id(obj)].attack_type)
size = (size*3)/4;
@ -592,8 +616,19 @@ static fix check_vector_to_object(vms_vector *intp,const vms_vector *p0,const vm
((otherobj->type == OBJ_PLAYER) ||
((Game_mode&GM_MULTI_COOP) && otherobj->type == OBJ_WEAPON && otherobj->ctype.laser_info.parent_type == OBJ_PLAYER)))
size = size/2;
/*
* Okay, look, I know this is stupid but hear me out:
* The original version of check_vector_to_sphere_1 contains a bug that messes up the collision point of two objects under certain conditions.
* This breaks several things, most notably splash damage of projectiles which may very well explode out of range of the target.
* However, fixing this bug breaks how non-solid objects are supposed to be handled (collide but don't stop moving). So maybe this bug was just a misconception. Who knows?
* Since this function here addresses how different object types are handled, I use it to determine which objects the fix of check_vector_to_sphere_1 will NOT apply to.
* If you have a better idea, let me know.
*/
for (i = 0; i < numignore; i++)
if (obj->type == ignoreobjs[i] || otherobj->type == ignoreobjs[i])
haveignoreobj = 1;
return check_vector_to_sphere_1(intp,p0,p1,&obj->pos,size+rad);
return check_vector_to_sphere_1(intp,p0,p1,&obj->pos,size+rad,haveignoreobj);
}

View file

@ -317,7 +317,6 @@ void do_physics_sim(vobjptridx_t obj)
physics_info *pi;
segnum_t orig_segnum = obj->segnum;
int bounced=0;
fix PhysTime = (FrameTime<DESIGNATED_GAME_FRAMETIME?DESIGNATED_GAME_FRAMETIME:FrameTime);
Assert(obj->movement_type == MT_PHYSICS);
@ -336,12 +335,7 @@ void do_physics_sim(vobjptridx_t obj)
n_phys_segs = 0;
/* As this engine was not designed for that high FPS as we intend, we use DESIGNATED_GAME_FRAMETIME max. for sim_time to ensure
scaling and dot products stay accurate and reliable. The object position intended for this frame will be scaled down later,
after the main collision-loop is done.
This won't make collision results be equal in all FPS settings, but hopefully more accurate, the higher our FPS are.
*/
sim_time = PhysTime; //FrameTime;
sim_time = FrameTime;
//debug_obj = obj;
@ -366,7 +360,6 @@ void do_physics_sim(vobjptridx_t obj)
Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);
//do thrust & drag
// NOTE: this always must be dependent on FrameTime, if sim_time differs!
if ((drag = obj->mtype.phys_info.drag) != 0) {
int count;
@ -717,25 +710,6 @@ void do_physics_sim(vobjptridx_t obj)
}
}
// As sim_time may not base on FrameTime, scale actual object position to get accurate movement
if (PhysTime/FrameTime > 0)
{
vms_vector md;
vm_vec_sub(&md, &obj->pos, &start_pos);
vm_vec_scale(&md, F1_0/((float)PhysTime/FrameTime));
vm_vec_add(&obj->pos,&start_pos, &md);
//check for and update correct object segment
if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0)
{
if (!update_object_seg(obj)) {
if (!(Game_mode & GM_MULTI))
Int3();
compute_segment_center(&obj->pos,&Segments[obj->segnum]);
obj->pos.x += obj;
}
}
}
// After collision with objects and walls, set velocity from actual movement
if (!obj_stopped && !bounced
&& ((obj->type == OBJ_PLAYER) || (obj->type == OBJ_ROBOT) || (obj->type == OBJ_DEBRIS))