From 9012cd408e240d6039120e56fdd47a0983890993 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 13 Jan 2015 21:19:11 -0300 Subject: -Add support for one-way collision in 2D (only works for kinematic body so far) -Solve drawing order bug introduced in previous commit: solves #1214 --- servers/physics_2d/space_2d_sw.cpp | 81 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) (limited to 'servers/physics_2d/space_2d_sw.cpp') diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 76069de9a0..f2ed74ffbf 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -98,7 +98,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vec if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) { - //print_line("inters sgment!"); + Matrix32 xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); shape_point=xform.xform(shape_point); @@ -217,6 +217,16 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32 int shape_idx=space->intersection_query_subindex_results[i]; + /*if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) { + + const Body2DSW *body=static_cast(col_obj); + if (body->get_one_way_collision_direction()!=Vector2() && p_motion.dot(body->get_one_way_collision_direction())<=CMP_EPSILON) { + print_line("failed in motion dir"); + continue; + } + }*/ + + Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) { @@ -227,6 +237,14 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32 //test initial overlap if (CollisionSolver2DSW::solve(shape,p_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) { + if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) { + //if one way collision direction ignore initial overlap + const Body2DSW *body=static_cast(col_obj); + if (body->get_one_way_collision_direction()!=Vector2()) { + continue; + } + } + return false; } @@ -253,6 +271,29 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32 } } + if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) { + + const Body2DSW *body=static_cast(col_obj); + if (body->get_one_way_collision_direction()!=Vector2()) { + + Vector2 cd[2]; + Physics2DServerSW::CollCbkData cbk; + cbk.max=1; + cbk.amount=0; + cbk.ptr=cd; + cbk.valid_dir=body->get_one_way_collision_direction(); + cbk.valid_depth=body->get_one_way_collision_max_depth(); + + Vector2 sep=mnormal; //important optimization for this to work fast enough + bool collided = CollisionSolver2DSW::solve(shape,p_xform,p_motion*(hi+space->contact_max_allowed_penetration),col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),Physics2DServerSW::_shape_col_cbk,&cbk,&sep,p_margin); + if (!collided || cbk.amount==0) { + continue; + } + + } + } + + if (lowget_self() )) continue; - + if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) { + + const Body2DSW *body=static_cast(col_obj); + cbk.valid_dir=body->get_one_way_collision_direction(); + cbk.valid_depth=body->get_one_way_collision_max_depth(); + } else { + cbk.valid_dir=Vector2(); + cbk.valid_depth=0; + } if (CollisionSolver2DSW::solve(shape,p_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) { - collided=true; + collided=p_result_max==0 || cbk.amount>0; } } + r_result_count=cbk.amount; return collided; @@ -334,6 +384,8 @@ struct _RestCallbackData2D { Vector2 best_contact; Vector2 best_normal; float best_len; + Vector2 valid_dir; + float valid_depth; }; static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata) { @@ -341,11 +393,23 @@ static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,v _RestCallbackData2D *rd=(_RestCallbackData2D*)p_userdata; + if (rd->valid_dir!=Vector2()) { + + if (rd->valid_dir!=Vector2()) { + if (p_point_A.distance_squared_to(p_point_B)>rd->valid_depth*rd->valid_depth) + return; + if (rd->valid_dir.dot((p_point_A-p_point_B).normalized())best_len) return; + rd->best_len=len; rd->best_contact=p_point_B; rd->best_normal=contact_rel/len; @@ -385,6 +449,17 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape if (p_exclude.has( col_obj->get_self() )) continue; + if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) { + + const Body2DSW *body=static_cast(col_obj); + rcd.valid_dir=body->get_one_way_collision_direction(); + rcd.valid_depth=body->get_one_way_collision_max_depth(); + } else { + rcd.valid_dir=Vector2(); + rcd.valid_depth=0; + } + + rcd.object=col_obj; rcd.shape=shape_idx; bool sc = CollisionSolver2DSW::solve(shape,p_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_rest_cbk_result,&rcd,NULL,p_margin); -- cgit v1.2.3