Make sure rotated shapes with one way direction collisions work, fixes #12791

This commit is contained in:
Juan Linietsky 2018-11-10 10:12:35 -03:00
parent eb2d7228cd
commit 3226b44f79
2 changed files with 22 additions and 13 deletions

View File

@ -169,7 +169,9 @@ void Physics2DServerSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &
cbk->invalid_by_dir++; cbk->invalid_by_dir++;
return; return;
} }
if (cbk->valid_dir.dot((p_point_A - p_point_B).normalized()) < 0.7071) { //sqrt(2)/2.0 Vector2 rel_dir = (p_point_A - p_point_B).normalized();
if (cbk->valid_dir.dot(rel_dir) < 0.7071) { //sqrt(2)/2.0 - 45 degrees
cbk->invalid_by_dir++; cbk->invalid_by_dir++;
/* /*

View File

@ -579,9 +579,11 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
} }
} }
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
cbk.valid_depth = p_margin; //only valid depth is the collision margin cbk.valid_depth = p_margin; //only valid depth is the collision margin
cbk.invalid_by_dir = 0; cbk.invalid_by_dir = 0;
@ -592,7 +594,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
} }
Shape2DSW *against_shape = col_obj->get_shape(shape_idx); Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) { if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) {
if (cbk.amount > 0) { if (cbk.amount > 0) {
collided = true; collided = true;
} }
@ -745,9 +747,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
} }
} }
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
cbk.valid_depth = p_margin; //only valid depth is the collision margin cbk.valid_depth = p_margin; //only valid depth is the collision margin
cbk.invalid_by_dir = 0; cbk.invalid_by_dir = 0;
@ -773,7 +778,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
bool did_collide = false; bool did_collide = false;
Shape2DSW *against_shape = col_obj->get_shape(shape_idx); Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) { if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) {
did_collide = cbk.amount > current_collisions; did_collide = cbk.amount > current_collisions;
} }
@ -878,14 +883,14 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
continue; continue;
} }
Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx); Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
//test initial overlap, does it collide if going all the way? //test initial overlap, does it collide if going all the way?
if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) { if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) {
continue; continue;
} }
//test initial overlap //test initial overlap
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) { if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) {
if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) { if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
continue; continue;
@ -905,7 +910,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
real_t ofs = (low + hi) * 0.5; real_t ofs = (low + hi) * 0.5;
Vector2 sep = mnormal; //important optimization for this to work fast enough Vector2 sep = mnormal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_xform, Vector2(), NULL, NULL, &sep, 0); bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, &sep, 0);
if (collided) { if (collided) {
@ -923,12 +928,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.max = 1; cbk.max = 1;
cbk.amount = 0; cbk.amount = 0;
cbk.ptr = cd; cbk.ptr = cd;
cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
cbk.valid_depth = 10e20; cbk.valid_depth = 10e20;
Vector2 sep = mnormal; //important optimization for this to work fast enough Vector2 sep = mnormal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0); bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
if (!collided || cbk.amount == 0) { if (!collided || cbk.amount == 0) {
continue; continue;
} }
@ -1013,9 +1018,11 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (excluded) if (excluded)
continue; continue;
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
rcd.valid_dir = body_shape_xform.get_axis(1).normalized(); rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
rcd.valid_depth = 10e20; rcd.valid_depth = 10e20;
} else { } else {
rcd.valid_dir = Vector2(); rcd.valid_dir = Vector2();
@ -1024,7 +1031,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.object = col_obj; rcd.object = col_obj;
rcd.shape = shape_idx; rcd.shape = shape_idx;
bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin); bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, NULL, p_margin);
if (!sc) if (!sc)
continue; continue;
} }