// Collision detection of two boxs with arbitrary angles. // Does only one side (a->b) of the collision. // -- If no collision, then no collision.. // -- If returns collision, check the other side (b<-a) // -- A vector will be returned to displace 'a' so that there is no // no collision anymore. The vector returned is one of the normals of 'b'. static vec_t box_o_o_collision(box_t a, box_t b) { // We will perform the collision using b's point of view and axes because // those will be consided the surface normals, and we want to return 'a's' // displacement in terms of 'a's' orientation vectors. -- So this may at times look reveresed. vec_t dist = vec_diff(b.pos, a.pos); // Normalized axis of box b. One of those axes will be the surface normal. vec_t axn[2]; // = { b.axis0, b.axis1 }; float axl[2]; // Half axis length. // Half axis. vec_t ahx0 = vec_scale(a.axis0, a.size.x); vec_t ahx1 = vec_scale(a.axis1, a.size.y); // Distance we need to displace 'a' to remove the collision. // -- (0, 0) => no collision. float col_vec[2] = { 0.0, 0.0 }; int i = 2; axn[0] = b.axis0; axn[1] = b.axis1; axl[0] = b.size.x; axl[1] = b.size.y; while(i--) { float a1, a2, d; // We check if the distance from center to center is smaller // than the sum of the distance from center to box edge // and that projection along each vector normal. // If it is false for one normal, we have no collision. // Otherwise we have the displacement distance to remove the collision. a1 = vec_absdot(axn[i], ahx0); a2 = vec_absdot(axn[i], ahx1); d = vec_absdot(axn[i], dist); col_vec[i] = a1 + a2 + axl[i] - d; if(col_vec[i] <= 0) { // Then there was no intersection. return vec_new(0, 0); } } if(col_vec[0] < col_vec[1]) { if(vec_dot(dist, axn[0]) > 0) { return vec_scale(axn[0], col_vec[0]); } else { return vec_scale(axn[0], -col_vec[0]); } } else { if(vec_dot(dist, axn[1]) > 0) { return vec_scale(axn[1], col_vec[1]); } else { return vec_scale(axn[1], -col_vec[1]); } } }
/** * Collision detection of two box with arbitrary angles. Does * only one side (a->b) of the collision. * if it returns no collision -> no collision * if it returns a collision -> check the other side (b<-a) * It will return a vector to displace a so that there is no collision * anymore. the vector returned is one of the normals of b. */ static vec_t box_o_o_collision(box_t a, box_t b){ /* we will perform the collision using b point of view and axis * because those will be considered the surface normals, and we * want to return 'a' displacement in terms of 'b' surface normals * and not in terms of 'a' orientation vectors. * that's why the logic looks reverse at times * */ vec_t dist = vec_diff(b.pos,a.pos); /* normalized axis of the box b. One of those axis will be the * surface normal. */ vec_t axn[2]; /* = {b.axis0, b.axis1}; */ float axl[2]; /* half axis length */ /* a half axis */ vec_t ahx0 = vec_scale(a.axis0,a.size.x); vec_t ahx1 = vec_scale(a.axis1,a.size.y); /*distance we need to displace a to remove the collision. * (0,0) => no collision*/ float col_vec[2] = { 0.0, 0.0 }; int i = 2; axn[0] = b.axis0; axn[1] = b.axis1; axl[0] = b.size.x; axl[1] = b.size.y; while(i--){ float a1,a2,d; /* we check if the distance from center to center is smaller * than the sum of the distance from center to box edges. * and that projected along each vector normal. * If it is false for one normal, we have no collision. * otherwise we have the displacement distance to remove * the collision. */ a1 = vec_absdot(axn[i],ahx0); a2 = vec_absdot(axn[i],ahx1); d = vec_absdot(axn[i],dist); col_vec[i] = a1 + a2 + axl[i] - d; if(col_vec[i] <= 0){ /* No intersection ! */ return vec_new(0,0); } /*printf("a1:%f\t,a2:%f\t,b1:%f\t,d:%f\tr:%f\n", a1,a2,axl[i],d,col_vec[i] );*/ } /* col_vec has the distance we need to displace 'a' along axn[0],axn[1] * to remove the collision. We now need to pick the shortest * distance and the right direction. * This is just choosing smallest dist and flipping normals if * necessary. */ if(col_vec[0] < col_vec[1]){ if(vec_dot(dist,axn[0]) > 0 ){ return vec_scale(axn[0], col_vec[0]); }else{ return vec_scale(axn[0],-col_vec[0]); } }else{ if(vec_dot(dist,axn[1]) > 0){ return vec_scale(axn[1], col_vec[1]); }else{ return vec_scale(axn[1],-col_vec[1]); } } }