From 28c4afeb5733f9ca9725ab2a5f4066af8e02b2a6 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 19 Apr 2015 20:50:55 -0300 Subject: [PATCH] -Rewritten KinematicBody2D::move to MUCH more efficient code. -KinematicBody2D::move now properly recognizes collision exceptions and masks, fixes #1649 -Removed object type masking for KinematicBody2D -Added a test_motion() function to RigidBody2D, allowing simlar behavior to KinematicBody2D::move there. --- demos/2d/kinematic_char/colworld.gd | 3 +- demos/2d/kinematic_char/colworld.scn | Bin 6367 -> 6596 bytes scene/2d/physics_body_2d.cpp | 152 ++---- scene/2d/physics_body_2d.h | 22 +- servers/physics_2d/physics_2d_server_sw.cpp | 12 + servers/physics_2d/physics_2d_server_sw.h | 3 + servers/physics_2d/space_2d_sw.cpp | 504 ++++++++++++++++++++ servers/physics_2d/space_2d_sw.h | 2 + servers/physics_2d_server.cpp | 75 +++ servers/physics_2d_server.h | 50 ++ servers/register_server_types.cpp | 1 + 11 files changed, 692 insertions(+), 132 deletions(-) diff --git a/demos/2d/kinematic_char/colworld.gd b/demos/2d/kinematic_char/colworld.gd index d13ff9236b..fe2dc30bb6 100644 --- a/demos/2d/kinematic_char/colworld.gd +++ b/demos/2d/kinematic_char/colworld.gd @@ -14,4 +14,5 @@ func _ready(): func _on_princess_body_enter( body ): #the name of this editor-generated callback is unfortunate - get_node("youwin").show() + if (body.get_name()=="player"): + get_node("youwin").show() diff --git a/demos/2d/kinematic_char/colworld.scn b/demos/2d/kinematic_char/colworld.scn index 7b79a1d887e07370da20522a537ba5b6be161e11..6c73e8b126807ba64f335e95095e3922e0e00719 100644 GIT binary patch delta 4330 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 delta 4139 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 p_result) { + + Physics2DServer::MotionResult *r=NULL; + if (p_result.is_valid()) + r=p_result->get_result_ptr(); + return Physics2DServer::get_singleton()->body_test_motion(get_rid(),p_motion,p_margin,r); + +} + void RigidBody2D::_direct_state_changed(Object *p_state) { //eh.. fuck @@ -791,6 +801,8 @@ void RigidBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_can_sleep","able_to_sleep"),&RigidBody2D::set_can_sleep); ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody2D::is_able_to_sleep); + ObjectTypeDB::bind_method(_MD("test_motion","motion","margin","result:Physics2DTestMotionResult"),&RigidBody2D::_test_motion,DEFVAL(0.08),DEFVAL(Variant())); + ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody2D::_direct_state_changed); ObjectTypeDB::bind_method(_MD("_body_enter_tree"),&RigidBody2D::_body_enter_tree); ObjectTypeDB::bind_method(_MD("_body_exit_tree"),&RigidBody2D::_body_exit_tree); @@ -888,20 +900,25 @@ Variant KinematicBody2D::_get_collider() const { } -bool KinematicBody2D::_ignores_mode(Physics2DServer::BodyMode p_mode) const { - - switch(p_mode) { - case Physics2DServer::BODY_MODE_STATIC: return !collide_static; - case Physics2DServer::BODY_MODE_KINEMATIC: return !collide_kinematic; - case Physics2DServer::BODY_MODE_RIGID: return !collide_rigid; - case Physics2DServer::BODY_MODE_CHARACTER: return !collide_character; - } - - return true; -} - Vector2 KinematicBody2D::move(const Vector2& p_motion) { +#if 1 + Physics2DServer::MotionResult result; + colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(),p_motion,margin,&result); + + collider_metadata=result.collider_metadata; + collider_shape=result.collider_shape; + collider_vel=result.collider_velocity; + collision=result.collision_point; + normal=result.collision_normal; + collider=result.collider_id; + + Matrix32 gt = get_global_transform(); + gt.elements[2]+=result.motion; + set_global_transform(gt); + return result.remainder; + +#else //give me back regular physics engine logic //this is madness //and most people using this function will think @@ -1051,7 +1068,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { set_global_transform(gt); return p_motion-motion; - +#endif } Vector2 KinematicBody2D::move_to(const Vector2& p_position) { @@ -1059,58 +1076,22 @@ Vector2 KinematicBody2D::move_to(const Vector2& p_position) { return move(p_position-get_global_pos()); } -bool KinematicBody2D::can_move_to(const Vector2& p_position, bool p_discrete) { - - ERR_FAIL_COND_V(!is_inside_tree(),false); - Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); - ERR_FAIL_COND_V(!dss,false); - - uint32_t mask=0; - if (collide_static) - mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; - if (collide_kinematic) - mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; - if (collide_rigid) - mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; - if (collide_character) - mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; - - Vector2 motion = p_position-get_global_pos(); - Matrix32 xform=get_global_transform(); - - if (p_discrete) { - - xform.elements[2]+=motion; - motion=Vector2(); - } - - Set exclude; - exclude.insert(get_rid()); - - //fill exclude list.. - for(int i=0;iintersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),motion,0,NULL,0,exclude,get_layer_mask(),mask); - if (col) - return false; - } - - return true; -} - -bool KinematicBody2D::is_colliding() const { +bool KinematicBody2D::test_move(const Vector2& p_motion) { ERR_FAIL_COND_V(!is_inside_tree(),false); - return colliding; + return Physics2DServer::get_singleton()->body_test_motion(get_rid(),p_motion,margin); + + } + Vector2 KinematicBody2D::get_collision_pos() const { ERR_FAIL_COND_V(!colliding,Vector2()); return collision; } + Vector2 KinematicBody2D::get_collision_normal() const { ERR_FAIL_COND_V(!colliding,Vector2()); @@ -1143,43 +1124,10 @@ Variant KinematicBody2D::get_collider_metadata() const { } -void KinematicBody2D::set_collide_with_static_bodies(bool p_enable) { - collide_static=p_enable; -} -bool KinematicBody2D::can_collide_with_static_bodies() const { +bool KinematicBody2D::is_colliding() const{ - return collide_static; -} - -void KinematicBody2D::set_collide_with_rigid_bodies(bool p_enable) { - - collide_rigid=p_enable; - -} -bool KinematicBody2D::can_collide_with_rigid_bodies() const { - - - return collide_rigid; -} - -void KinematicBody2D::set_collide_with_kinematic_bodies(bool p_enable) { - - collide_kinematic=p_enable; - -} -bool KinematicBody2D::can_collide_with_kinematic_bodies() const { - - return collide_kinematic; -} - -void KinematicBody2D::set_collide_with_character_bodies(bool p_enable) { - - collide_character=p_enable; -} -bool KinematicBody2D::can_collide_with_character_bodies() const { - - return collide_character; + return colliding; } void KinematicBody2D::set_collision_margin(float p_margin) { @@ -1198,7 +1146,7 @@ void KinematicBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody2D::move); ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to); - ObjectTypeDB::bind_method(_MD("can_move_to","position","discrete"),&KinematicBody2D::can_move_to,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("test_move","rel_vec"),&KinematicBody2D::test_move); ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody2D::is_colliding); @@ -1209,26 +1157,9 @@ void KinematicBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape); ObjectTypeDB::bind_method(_MD("get_collider_metadata"),&KinematicBody2D::get_collider_metadata); - - ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody2D::set_collide_with_static_bodies); - ObjectTypeDB::bind_method(_MD("can_collide_with_static_bodies"),&KinematicBody2D::can_collide_with_static_bodies); - - ObjectTypeDB::bind_method(_MD("set_collide_with_kinematic_bodies","enable"),&KinematicBody2D::set_collide_with_kinematic_bodies); - ObjectTypeDB::bind_method(_MD("can_collide_with_kinematic_bodies"),&KinematicBody2D::can_collide_with_kinematic_bodies); - - ObjectTypeDB::bind_method(_MD("set_collide_with_rigid_bodies","enable"),&KinematicBody2D::set_collide_with_rigid_bodies); - ObjectTypeDB::bind_method(_MD("can_collide_with_rigid_bodies"),&KinematicBody2D::can_collide_with_rigid_bodies); - - ObjectTypeDB::bind_method(_MD("set_collide_with_character_bodies","enable"),&KinematicBody2D::set_collide_with_character_bodies); - ObjectTypeDB::bind_method(_MD("can_collide_with_character_bodies"),&KinematicBody2D::can_collide_with_character_bodies); - ObjectTypeDB::bind_method(_MD("set_collision_margin","pixels"),&KinematicBody2D::set_collision_margin); ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody2D::get_collision_margin); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/static"),_SCS("set_collide_with_static_bodies"),_SCS("can_collide_with_static_bodies")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/kinematic"),_SCS("set_collide_with_kinematic_bodies"),_SCS("can_collide_with_kinematic_bodies")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/rigid"),_SCS("set_collide_with_rigid_bodies"),_SCS("can_collide_with_rigid_bodies")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/character"),_SCS("set_collide_with_character_bodies"),_SCS("can_collide_with_character_bodies")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/margin",PROPERTY_HINT_RANGE,"0.001,256,0.001"),_SCS("set_collision_margin"),_SCS("get_collision_margin")); @@ -1236,11 +1167,6 @@ void KinematicBody2D::_bind_methods() { KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KINEMATIC){ - collide_static=true; - collide_rigid=true; - collide_kinematic=true; - collide_character=true; - colliding=false; collider=0; diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index c05a4ff058..b8cba6e5ba 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -188,6 +188,7 @@ private: void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape); void _direct_state_changed(Object *p_state); + bool _test_motion(const Vector2& p_motion,float p_margin=0.08,const Ref& p_result=Ref()); protected: @@ -249,6 +250,8 @@ public: void set_applied_force(const Vector2& p_force); Vector2 get_applied_force() const; + + Array get_colliding_bodies() const; //function for script RigidBody2D(); @@ -266,11 +269,6 @@ class KinematicBody2D : public PhysicsBody2D { OBJ_TYPE(KinematicBody2D,PhysicsBody2D); float margin; - bool collide_static; - bool collide_rigid; - bool collide_kinematic; - bool collide_character; - bool colliding; Vector2 collision; Vector2 normal; @@ -290,7 +288,7 @@ public: Vector2 move(const Vector2& p_motion); Vector2 move_to(const Vector2& p_position); - bool can_move_to(const Vector2& p_position,bool p_discrete=false); + bool test_move(const Vector2& p_motion); bool is_colliding() const; Vector2 get_collision_pos() const; Vector2 get_collision_normal() const; @@ -299,18 +297,6 @@ public: int get_collider_shape() const; Variant get_collider_metadata() const; - void set_collide_with_static_bodies(bool p_enable); - bool can_collide_with_static_bodies() const; - - void set_collide_with_rigid_bodies(bool p_enable); - bool can_collide_with_rigid_bodies() const; - - void set_collide_with_kinematic_bodies(bool p_enable); - bool can_collide_with_kinematic_bodies() const; - - void set_collide_with_character_bodies(bool p_enable); - bool can_collide_with_character_bodies() const; - void set_collision_margin(float p_margin); float get_collision_margin() const; diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index d8ad59d997..d0a0ff67d7 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -959,6 +959,18 @@ void Physics2DServerSW::body_set_pickable(RID p_body,bool p_pickable) { } +bool Physics2DServerSW::body_test_motion(RID p_body,const Vector2& p_motion,float p_margin,MotionResult *r_result) { + + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND_V(!body,false); + ERR_FAIL_COND_V(!body->get_space(),false); + ERR_FAIL_COND_V(body->get_space()->is_locked(),false); + + return body->get_space()->test_body_motion(body,p_motion,p_margin,r_result); + +} + + /* JOINT API */ void Physics2DServerSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) { diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index 10143bdadb..50675cbd09 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -223,6 +223,9 @@ public: virtual void body_set_pickable(RID p_body,bool p_pickable); + virtual bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL); + + /* JOINT API */ virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value); diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 0644147762..9a1b977bda 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -556,7 +556,511 @@ Physics2DDirectSpaceStateSW::Physics2DDirectSpaceStateSW() { +bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p_margin,Physics2DServer::MotionResult *r_result) { + //give me back regular physics engine logic + //this is madness + //and most people using this function will think + //what it does is simpler than using physics + //this took about a week to get right.. + //but is it right? who knows at this point.. + + Rect2 body_aabb; + + for(int i=0;iget_shape_count();i++) { + + if (i==0) + body_aabb=p_body->get_shape_aabb(i); + else + body_aabb=body_aabb.merge(p_body->get_shape_aabb(i)); + } + + body_aabb=body_aabb.grow(p_margin); + + { + //add motion + + Rect2 motion_aabb=body_aabb; + motion_aabb.pos+=p_motion; + body_aabb=body_aabb.merge(motion_aabb); + } + + + int amount = broadphase->cull_aabb(body_aabb,intersection_query_results,INTERSECTION_QUERY_MAX,intersection_query_subindex_results); + + for(int i=0;iget_type()==CollisionObject2DSW::TYPE_AREA) + keep=false; + else if ((static_cast(intersection_query_results[i])->get_layer_mask()&p_body->get_layer_mask())==0) + keep=false; + else if (static_cast(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) + keep=false; + else if (static_cast(intersection_query_results[i])->is_shape_set_as_trigger(intersection_query_subindex_results[i])) + keep=false; + + if (!keep) { + + if (iget_transform(); + + { + //STEP 1, FREE BODY IF STUCK + + const int max_results = 32; + int recover_attempts=4; + Vector2 sr[max_results*2]; + + do { + + Physics2DServerSW::CollCbkData cbk; + cbk.max=max_results; + cbk.amount=0; + cbk.ptr=sr; + + + CollisionSolver2DSW::CallbackResult cbkres=NULL; + + Physics2DServerSW::CollCbkData *cbkptr=NULL; + cbkptr=&cbk; + cbkres=Physics2DServerSW::_shape_col_cbk; + + bool collided=false; + + + for(int j=0;jget_shape_count();j++) { + if (p_body->is_shape_set_as_trigger(j)) + continue; + + Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j); + Shape2DSW *body_shape = p_body->get_shape(j); + for(int i=0;iget_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(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) { + collided=cbk.amount>0; + } + } + } + + + if (!collided) + break; + + Vector2 recover_motion; + + for(int i=0;iget_shape_count();j++) { + + if (p_body->is_shape_set_as_trigger(j)) + continue; + + Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j); + Shape2DSW *body_shape = p_body->get_shape(j); + + bool stuck=false; + + float best_safe=1; + float best_unsafe=1; + + for(int i=0;iget_transform() * col_obj->get_shape_transform(shape_idx); + //test initial overlap, does it collide if going all the way? + if (!CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) { + continue; + } + + + //test initial overlap + if (CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) { + + 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; + } + } + + stuck=true; + break; + } + + + //just do kinematic solving + float low=0; + float hi=1; + Vector2 mnormal=p_motion.normalized(); + + for(int i=0;i<8;i++) { //steps should be customizable.. + + //Matrix32 xfa = p_xform; + float ofs = (low+hi)*0.5; + + Vector2 sep=mnormal; //important optimization for this to work fast enough + bool collided = CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep,0); + + if (collided) { + + hi=ofs; + } else { + + low=ofs; + } + } + + 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(body_shape,body_shape_xform,p_motion*(hi+contact_max_allowed_penetration),col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),Physics2DServerSW::_shape_col_cbk,&cbk,&sep,0); + if (!collided || cbk.amount==0) { + continue; + } + + } + } + + + if (low=1) { + //not collided + collided=false; + if (r_result) { + + r_result->motion=p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]); + r_result->remainder=Vector2(); + } + + } else { + + //it collided, let's get the rest info in unsafe advance + Matrix32 ugt = body_transform; + ugt.elements[2]+=p_motion*unsafe; + + _RestCallbackData2D rcd; + rcd.best_len=0; + rcd.best_object=NULL; + rcd.best_shape=0; + + Matrix32 body_shape_xform = ugt * p_body->get_shape_transform(best_shape); + Shape2DSW *body_shape = p_body->get_shape(best_shape); + + + for(int i=0;iget_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(body_shape,body_shape_xform,Vector2(),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); + if (!sc) + continue; + + } + + if (rcd.best_len!=0) { + + if (r_result) { + r_result->collider=rcd.best_object->get_self(); + r_result->collider_id=rcd.best_object->get_instance_id(); + r_result->collider_shape=rcd.best_shape; + r_result->collision_normal=rcd.best_normal; + r_result->collision_point=rcd.best_contact; + r_result->collider_metadata=rcd.best_object->get_shape_metadata(rcd.best_shape); + + const Body2DSW *body = static_cast(rcd.best_object); + Vector2 rel_vec = r_result->collision_point-body->get_transform().get_origin(); + r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); + + r_result->motion=safe*p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]); + r_result->remainder=p_motion - safe * p_motion; + } + + collided=true; + } else { + if (r_result) { + + r_result->motion=p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]); + r_result->remainder=Vector2(); + } + + collided=false; + + } + } + + return collided; + + +#if 0 + //give me back regular physics engine logic + //this is madness + //and most people using this function will think + //what it does is simpler than using physics + //this took about a week to get right.. + //but is it right? who knows at this point.. + + + colliding=false; + ERR_FAIL_COND_V(!is_inside_tree(),Vector2()); + Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); + ERR_FAIL_COND_V(!dss,Vector2()); + const int max_shapes=32; + Vector2 sr[max_shapes*2]; + int res_shapes; + + Set exclude; + exclude.insert(get_rid()); + + + //recover first + int recover_attempts=4; + + bool collided=false; + uint32_t mask=0; + if (collide_static) + mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; + if (collide_kinematic) + mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; + if (collide_rigid) + mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; + if (collide_character) + mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; + +// print_line("motion: "+p_motion+" margin: "+rtos(margin)); + + //print_line("margin: "+rtos(margin)); + do { + + //motion recover + for(int i=0;icollide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) + collided=true; + + } + + if (!collided) + break; + + Vector2 recover_motion; + + for(int i=0;icast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask); + //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); + if (!valid) { + + safe=0; + unsafe=0; + best_shape=i; //sadly it's the best + break; + } + if (lsafe==1.0) { + continue; + } + if (lsafe < safe) { + + safe=lsafe; + unsafe=lunsafe; + best_shape=i; + } + } + + + //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); + + if (safe>=1) { + //not collided + colliding=false; + } else { + + //it collided, let's get the rest info in unsafe advance + Matrix32 ugt = get_global_transform(); + ugt.elements[2]+=p_motion*unsafe; + Physics2DDirectSpaceState::ShapeRestInfo rest_info; + bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask); + if (!c2) { + //should not happen, but floating point precision is so weird.. + + colliding=false; + } else { + + + //print_line("Travel: "+rtos(travel)); + colliding=true; + collision=rest_info.point; + normal=rest_info.normal; + collider=rest_info.collider_id; + collider_vel=rest_info.linear_velocity; + collider_shape=rest_info.shape; + collider_metadata=rest_info.metadata; + } + + } + + Vector2 motion=p_motion*safe; + Matrix32 gt = get_global_transform(); + gt.elements[2]+=motion; + set_global_transform(gt); + + return p_motion-motion; + +#endif + return false; +} diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index d100ada9db..95a576609e 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -165,6 +165,8 @@ public: int get_collision_pairs() const { return collision_pairs; } + bool test_body_motion(Body2DSW *p_body, const Vector2&p_motion, float p_margin, Physics2DServer::MotionResult *r_result); + Physics2DDirectSpaceStateSW *get_direct_state(); Space2DSW(); diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index ffd240365b..16a15617ff 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -421,13 +421,86 @@ void Physics2DShapeQueryResult::_bind_methods() { } +/////////////////////////////// +/*bool Physics2DTestMotionResult::is_colliding() const { + return colliding; +}*/ +Vector2 Physics2DTestMotionResult::get_motion() const{ + return result.motion; +} +Vector2 Physics2DTestMotionResult::get_motion_remainder() const{ + + return result.remainder; +} + +Vector2 Physics2DTestMotionResult::get_collision_point() const{ + + return result.collision_point; +} +Vector2 Physics2DTestMotionResult::get_collision_normal() const{ + + return result.collision_normal; +} +Vector2 Physics2DTestMotionResult::get_collider_velocity() const{ + + return result.collider_velocity; +} +ObjectID Physics2DTestMotionResult::get_collider_id() const{ + + return result.collider_id; +} +RID Physics2DTestMotionResult::get_collider_rid() const{ + + return result.collider; +} + +Object* Physics2DTestMotionResult::get_collider() const { + return ObjectDB::get_instance(result.collider_id); +} + +int Physics2DTestMotionResult::get_collider_shape() const{ + + return result.collider_shape; +} + +void Physics2DTestMotionResult::_bind_methods() { + + //ObjectTypeDB::bind_method(_MD("is_colliding"),&Physics2DTestMotionResult::is_colliding); + ObjectTypeDB::bind_method(_MD("get_motion"),&Physics2DTestMotionResult::get_motion); + ObjectTypeDB::bind_method(_MD("get_motion_remainder"),&Physics2DTestMotionResult::get_motion_remainder); + ObjectTypeDB::bind_method(_MD("get_collision_point"),&Physics2DTestMotionResult::get_collision_point); + ObjectTypeDB::bind_method(_MD("get_collision_normal"),&Physics2DTestMotionResult::get_collision_normal); + ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&Physics2DTestMotionResult::get_collider_velocity); + ObjectTypeDB::bind_method(_MD("get_collider_id"),&Physics2DTestMotionResult::get_collider_id); + ObjectTypeDB::bind_method(_MD("get_collider_rid"),&Physics2DTestMotionResult::get_collider_rid); + ObjectTypeDB::bind_method(_MD("get_collider"),&Physics2DTestMotionResult::get_collider); + ObjectTypeDB::bind_method(_MD("get_collider_shape"),&Physics2DTestMotionResult::get_collider_shape); + +} + +Physics2DTestMotionResult::Physics2DTestMotionResult(){ + + colliding=false; + result.collider_id=0; + result.collider_shape=0; +} /////////////////////////////////////// + + +bool Physics2DServer::_body_test_motion(RID p_body,const Vector2& p_motion,float p_margin,const Ref& p_result) { + + MotionResult *r=NULL; + if (p_result.is_valid()) + r=p_result->get_result_ptr(); + return body_test_motion(p_body,p_motion,p_margin,r); +} + void Physics2DServer::_bind_methods() { @@ -543,6 +616,8 @@ void Physics2DServer::_bind_methods() { ObjectTypeDB::bind_method(_MD("body_set_force_integration_callback","body","receiver","method"),&Physics2DServer::body_set_force_integration_callback); + ObjectTypeDB::bind_method(_MD("body_test_motion","body","motion","margin","result:Physics2DTestMotionResult"),&Physics2DServer::_body_test_motion,DEFVAL(0.08),DEFVAL(Variant())); + /* JOINT API */ ObjectTypeDB::bind_method(_MD("joint_set_param","joint","param","value"),&Physics2DServer::joint_set_param); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index a3e65ec28c..306144c2ba 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -230,6 +230,7 @@ public: Physics2DShapeQueryResult(); }; +class Physics2DTestMotionResult; class Physics2DServer : public Object { @@ -237,6 +238,8 @@ class Physics2DServer : public Object { static Physics2DServer * singleton; + virtual bool _body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.08,const Ref& p_result=Ref()); + protected: static void _bind_methods(); @@ -468,6 +471,22 @@ public: virtual void body_set_pickable(RID p_body,bool p_pickable)=0; + struct MotionResult { + + Vector2 motion; + Vector2 remainder; + + Vector2 collision_point; + Vector2 collision_normal; + Vector2 collider_velocity; + ObjectID collider_id; + RID collider; + int collider_shape; + Variant collider_metadata; + }; + + virtual bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL)=0; + /* JOINT API */ enum JointType { @@ -532,6 +551,37 @@ public: ~Physics2DServer(); }; + +class Physics2DTestMotionResult : public Reference { + + OBJ_TYPE( Physics2DTestMotionResult, Reference ); + + Physics2DServer::MotionResult result; + bool colliding; +friend class Physics2DServer; + +protected: + static void _bind_methods(); +public: + + Physics2DServer::MotionResult* get_result_ptr() const { return const_cast(&result); } + + //bool is_colliding() const; + Vector2 get_motion() const; + Vector2 get_motion_remainder() const; + + Vector2 get_collision_point() const; + Vector2 get_collision_normal() const; + Vector2 get_collider_velocity() const; + ObjectID get_collider_id() const; + RID get_collider_rid() const; + Object* get_collider() const; + int get_collider_shape() const; + + Physics2DTestMotionResult(); +}; + + VARIANT_ENUM_CAST( Physics2DServer::ShapeType ); VARIANT_ENUM_CAST( Physics2DServer::SpaceParameter ); VARIANT_ENUM_CAST( Physics2DServer::AreaParameter ); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 6ee01f9d43..d35b6e1e5f 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -55,6 +55,7 @@ void register_server_types() { ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_virtual_type(); + ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type();