diff options
Diffstat (limited to 'scene/3d/physics_body.cpp')
-rw-r--r-- | scene/3d/physics_body.cpp | 563 |
1 files changed, 464 insertions, 99 deletions
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 721fd368e1..f5e3ad66ee 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -57,160 +57,111 @@ float PhysicsBody::get_inverse_mass() const { return 0; } -PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) { - +void PhysicsBody::set_layer_mask(uint32_t p_mask) { + layer_mask=p_mask; + PhysicsServer::get_singleton()->body_set_layer_mask(get_rid(),p_mask); } -void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) { - - constant_linear_velocity=p_vel; - PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity); +uint32_t PhysicsBody::get_layer_mask() const { + return layer_mask; } -void StaticBody::set_constant_angular_velocity(const Vector3& p_vel) { - - constant_angular_velocity=p_vel; - PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity); +void PhysicsBody::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody::set_layer_mask); + ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody::get_layer_mask); + ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); } -Vector3 StaticBody::get_constant_linear_velocity() const { - - return constant_linear_velocity; -} -Vector3 StaticBody::get_constant_angular_velocity() const { - - return constant_angular_velocity; -} +PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) { -void StaticBody::_state_notify(Object *p_object) { + layer_mask=1; - if (!pre_xform) - return; +} - PhysicsDirectBodyState *p2d = (PhysicsDirectBodyState*)p_object; - setting=true; - Transform new_xform = p2d->get_transform(); - *pre_xform=new_xform; - set_ignore_transform_notification(true); - set_global_transform(new_xform); - set_ignore_transform_notification(false); +void StaticBody::set_friction(real_t p_friction){ - setting=false; + ERR_FAIL_COND(p_friction<0 || p_friction>1); + friction=p_friction; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction); } +real_t StaticBody::get_friction() const{ -void StaticBody::_update_xform() { - - if (!pre_xform || !pending) - return; - - setting=true; - - - Transform new_xform = get_global_transform(); //obtain the new one + return friction; +} - //set_block_transform_notify(true); - set_ignore_transform_notification(true); - PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_TRANSFORM,*pre_xform); //then simulate motion! - set_global_transform(*pre_xform); //but restore state to previous one in both visual and physics - set_ignore_transform_notification(false); +void StaticBody::set_bounce(real_t p_bounce){ - PhysicsServer::get_singleton()->body_static_simulate_motion(get_rid(),new_xform); //then simulate motion! + ERR_FAIL_COND(p_bounce<0 || p_bounce>1); - setting=false; - pending=false; + bounce=p_bounce; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_BOUNCE,bounce); } +real_t StaticBody::get_bounce() const{ -void StaticBody::_notification(int p_what) { - - switch(p_what) { - - case NOTIFICATION_ENTER_SCENE: { - - if (pre_xform) - *pre_xform = get_global_transform(); - pending=false; - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { + return bounce; +} - if (simulating_motion && !pending && is_inside_scene() && !setting && !get_scene()->is_editor_hint()) { +void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) { - call_deferred(SceneStringNames::get_singleton()->_update_xform); - pending=true; - } + constant_linear_velocity=p_vel; + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity); - } break; - } +} +void StaticBody::set_constant_angular_velocity(const Vector3& p_vel) { + constant_angular_velocity=p_vel; + PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity); } -void StaticBody::set_simulate_motion(bool p_enable) { - - if (p_enable==simulating_motion) - return; - simulating_motion=p_enable; +Vector3 StaticBody::get_constant_linear_velocity() const { - if (p_enable) { - pre_xform = memnew( Transform ); - if (is_inside_scene()) - *pre_xform=get_transform(); -// query = PhysicsServer::get_singleton()->query_create(this,"_state_notify",Variant()); - // PhysicsServer::get_singleton()->query_body_direct_state(query,get_rid()); - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_state_notify"); + return constant_linear_velocity; +} +Vector3 StaticBody::get_constant_angular_velocity() const { - } else { - memdelete( pre_xform ); - pre_xform=NULL; - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),NULL,StringName()); - pending=false; - } + return constant_angular_velocity; } -bool StaticBody::is_simulating_motion() const { - return simulating_motion; -} void StaticBody::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_simulate_motion","enabled"),&StaticBody::set_simulate_motion); - ObjectTypeDB::bind_method(_MD("is_simulating_motion"),&StaticBody::is_simulating_motion); - ObjectTypeDB::bind_method(_MD("_update_xform"),&StaticBody::_update_xform); - ObjectTypeDB::bind_method(_MD("_state_notify"),&StaticBody::_state_notify); ObjectTypeDB::bind_method(_MD("set_constant_linear_velocity","vel"),&StaticBody::set_constant_linear_velocity); ObjectTypeDB::bind_method(_MD("set_constant_angular_velocity","vel"),&StaticBody::set_constant_angular_velocity); ObjectTypeDB::bind_method(_MD("get_constant_linear_velocity"),&StaticBody::get_constant_linear_velocity); ObjectTypeDB::bind_method(_MD("get_constant_angular_velocity"),&StaticBody::get_constant_angular_velocity); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"simulate_motion"),_SCS("set_simulate_motion"),_SCS("is_simulating_motion")); + ObjectTypeDB::bind_method(_MD("set_friction","friction"),&StaticBody::set_friction); + ObjectTypeDB::bind_method(_MD("get_friction"),&StaticBody::get_friction); + + ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&StaticBody::set_bounce); + ObjectTypeDB::bind_method(_MD("get_bounce"),&StaticBody::get_bounce); + + ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"constant_linear_velocity"),_SCS("set_constant_linear_velocity"),_SCS("get_constant_linear_velocity")); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"constant_angular_velocity"),_SCS("set_constant_angular_velocity"),_SCS("get_constant_angular_velocity")); } StaticBody::StaticBody() : PhysicsBody(PhysicsServer::BODY_MODE_STATIC) { - simulating_motion=false; - pre_xform=NULL; - setting=false; - pending=false; - //constant_angular_velocity=0; - + bounce=0; + friction=1; } StaticBody::~StaticBody() { - if (pre_xform) - memdelete(pre_xform); - //if (query.is_valid()) - // PhysicsServer::get_singleton()->free(query); + } @@ -768,4 +719,418 @@ RigidBody::~RigidBody() { } +////////////////////////////////////////////////////// +////////////////////////// + + +Variant KinematicBody::_get_collider() const { + + ObjectID oid=get_collider(); + if (oid==0) + return Variant(); + Object *obj = ObjectDB::get_instance(oid); + if (!obj) + return Variant(); + + Reference *ref = obj->cast_to<Reference>(); + if (ref) { + return Ref<Reference>(ref); + } + + return obj; +} + + +bool KinematicBody::_ignores_mode(PhysicsServer::BodyMode p_mode) const { + + switch(p_mode) { + case PhysicsServer::BODY_MODE_STATIC: return !collide_static; + case PhysicsServer::BODY_MODE_KINEMATIC: return !collide_kinematic; + case PhysicsServer::BODY_MODE_RIGID: return !collide_rigid; + case PhysicsServer::BODY_MODE_CHARACTER: return !collide_character; + } + + return true; +} + +Vector3 KinematicBody::move(const Vector3& p_motion) { + + //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_scene(),Vector3()); + PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space()); + ERR_FAIL_COND_V(!dss,Vector3()); + const int max_shapes=32; + Vector3 sr[max_shapes*2]; + int res_shapes; + + Set<RID> exclude; + exclude.insert(get_rid()); + + + //recover first + int recover_attempts=4; + + bool collided=false; + uint32_t mask=0; + if (collide_static) + mask|=PhysicsDirectSpaceState::TYPE_MASK_STATIC_BODY; + if (collide_kinematic) + mask|=PhysicsDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; + if (collide_rigid) + mask|=PhysicsDirectSpaceState::TYPE_MASK_RIGID_BODY; + if (collide_character) + mask|=PhysicsDirectSpaceState::TYPE_MASK_CHARACTER_BODY; + +// print_line("motion: "+p_motion+" margin: "+rtos(margin)); + + //print_line("margin: "+rtos(margin)); + + float m = margin; + //m=0.001; + + do { + + //motion recover + for(int i=0;i<get_shape_count();i++) { + + + if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),m,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) { + collided=true; + } + + } + + + + if (!collided) + break; + + //print_line("have to recover"); + Vector3 recover_motion; + bool all_outside=true; + for(int j=0;j<8;j++) { + for(int i=0;i<res_shapes;i++) { + + Vector3 a = sr[i*2+0]; + Vector3 b = sr[i*2+1]; + //print_line(String()+a+" -> "+b); +#if 0 + float d = a.distance_to(b); + + //if (d<margin) + /// continue; + /// + /// + recover_motion+=(b-a)*0.2; +#else + float dist = a.distance_to(b); + if (dist>CMP_EPSILON) { + Vector3 norm = (b-a).normalized(); + if (dist>margin*0.5) + all_outside=false; + float adv = norm.dot(recover_motion); + //print_line(itos(i)+" dist: "+rtos(dist)+" adv: "+rtos(adv)); + recover_motion+=norm*MAX(dist-adv,0)*0.4; + } +#endif + + } + } + + + if (recover_motion==Vector3()) { + collided=false; + break; + } + + //print_line("**** RECOVER: "+recover_motion); + + Transform gt = get_global_transform(); + gt.origin+=recover_motion; + set_global_transform(gt); + + recover_attempts--; + + if (all_outside) + break; + + } while (recover_attempts); + + + //move second + float safe = 1.0; + float unsafe = 1.0; + int best_shape=-1; + + PhysicsDirectSpaceState::ShapeRestInfo rest; + + //print_line("pos: "+get_global_transform().origin); + //print_line("motion: "+p_motion); + + + for(int i=0;i<get_shape_count();i++) { + + + + float lsafe,lunsafe; + PhysicsDirectSpaceState::ShapeRestInfo lrest; + bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion,0, lsafe,lunsafe,exclude,get_layer_mask(),mask,&lrest); + //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); + if (!valid) { + safe=0; + unsafe=0; + best_shape=i; //sadly it's the best + //print_line("initial stuck"); + + break; + } + if (lsafe==1.0) { + //print_line("initial free"); + continue; + } + if (lsafe < safe) { + + //print_line("initial at "+rtos(lsafe)); + safe=lsafe; + safe=MAX(0,lsafe-0.01); + unsafe=lunsafe; + best_shape=i; + rest=lrest; + } + } + + + //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); + + if (safe>=1) { + //not collided + colliding=false; + } else { + + colliding=true; + + if (true || (safe==0 && unsafe==0)) { //use it always because it's more precise than GJK + //no advance, use rest info from collision + Transform ugt = get_global_transform(); + ugt.origin+=p_motion*unsafe; + + PhysicsDirectSpaceState::ShapeRestInfo rest_info; + bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), m,&rest,exclude,get_layer_mask(),mask); + if (!c2) { + //should not happen, but floating point precision is so weird.. + colliding=false; + } + + // print_line("Rest Travel: "+rest.normal); + + } + + if (colliding) { + + collision=rest.point; + normal=rest.normal; + collider=rest.collider_id; + collider_vel=rest.linear_velocity; + } + } + + Vector3 motion=p_motion*safe; + //if (colliding) + // motion+=normal*0.001; + Transform gt = get_global_transform(); + gt.origin+=motion; + set_global_transform(gt); + + return p_motion-motion; + +} + +Vector3 KinematicBody::move_to(const Vector3& p_position) { + + return move(p_position-get_global_transform().origin); +} + +bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) { + + ERR_FAIL_COND_V(!is_inside_scene(),false); + PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space()); + ERR_FAIL_COND_V(!dss,false); + + uint32_t mask=0; + if (collide_static) + mask|=PhysicsDirectSpaceState::TYPE_MASK_STATIC_BODY; + if (collide_kinematic) + mask|=PhysicsDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; + if (collide_rigid) + mask|=PhysicsDirectSpaceState::TYPE_MASK_RIGID_BODY; + if (collide_character) + mask|=PhysicsDirectSpaceState::TYPE_MASK_CHARACTER_BODY; + + Vector3 motion = p_position-get_global_transform().origin; + Transform xform=get_global_transform(); + + if (true || p_discrete) { + + xform.origin+=motion; + motion=Vector3(); + } + + Set<RID> exclude; + exclude.insert(get_rid()); + + //fill exclude list.. + for(int i=0;i<get_shape_count();i++) { + + + bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,0,exclude,get_layer_mask(),mask); + if (col) + return false; + } + + return true; +} + +bool KinematicBody::is_colliding() const { + + ERR_FAIL_COND_V(!is_inside_scene(),false); + + return colliding; +} +Vector3 KinematicBody::get_collision_pos() const { + + ERR_FAIL_COND_V(!colliding,Vector3()); + return collision; + +} +Vector3 KinematicBody::get_collision_normal() const { + + ERR_FAIL_COND_V(!colliding,Vector3()); + return normal; + +} + +Vector3 KinematicBody::get_collider_velocity() const { + + return collider_vel; +} + +ObjectID KinematicBody::get_collider() const { + + ERR_FAIL_COND_V(!colliding,0); + return collider; +} + +void KinematicBody::set_collide_with_static_bodies(bool p_enable) { + + collide_static=p_enable; +} +bool KinematicBody::can_collide_with_static_bodies() const { + + return collide_static; +} + +void KinematicBody::set_collide_with_rigid_bodies(bool p_enable) { + + collide_rigid=p_enable; + +} +bool KinematicBody::can_collide_with_rigid_bodies() const { + + + return collide_rigid; +} + +void KinematicBody::set_collide_with_kinematic_bodies(bool p_enable) { + + collide_kinematic=p_enable; + +} +bool KinematicBody::can_collide_with_kinematic_bodies() const { + + return collide_kinematic; +} + +void KinematicBody::set_collide_with_character_bodies(bool p_enable) { + + collide_character=p_enable; +} +bool KinematicBody::can_collide_with_character_bodies() const { + + return collide_character; +} + +void KinematicBody::set_collision_margin(float p_margin) { + + margin=p_margin; +} + +float KinematicBody::get_collision_margin() const{ + + return margin; +} + +void KinematicBody::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody::move); + ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody::move_to); + + ObjectTypeDB::bind_method(_MD("can_move_to","position"),&KinematicBody::can_move_to); + + ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody::is_colliding); + + ObjectTypeDB::bind_method(_MD("get_collision_pos"),&KinematicBody::get_collision_pos); + ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody::get_collision_normal); + ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody::get_collider_velocity); + ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody::_get_collider); + + + ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody::set_collide_with_static_bodies); + ObjectTypeDB::bind_method(_MD("can_collide_with_static_bodies"),&KinematicBody::can_collide_with_static_bodies); + + ObjectTypeDB::bind_method(_MD("set_collide_with_kinematic_bodies","enable"),&KinematicBody::set_collide_with_kinematic_bodies); + ObjectTypeDB::bind_method(_MD("can_collide_with_kinematic_bodies"),&KinematicBody::can_collide_with_kinematic_bodies); + + ObjectTypeDB::bind_method(_MD("set_collide_with_rigid_bodies","enable"),&KinematicBody::set_collide_with_rigid_bodies); + ObjectTypeDB::bind_method(_MD("can_collide_with_rigid_bodies"),&KinematicBody::can_collide_with_rigid_bodies); + + ObjectTypeDB::bind_method(_MD("set_collide_with_character_bodies","enable"),&KinematicBody::set_collide_with_character_bodies); + ObjectTypeDB::bind_method(_MD("can_collide_with_character_bodies"),&KinematicBody::can_collide_with_character_bodies); + + ObjectTypeDB::bind_method(_MD("set_collision_margin","pixels"),&KinematicBody::set_collision_margin); + ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody::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")); + + +} + +KinematicBody::KinematicBody() : PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC){ + + collide_static=true; + collide_rigid=true; + collide_kinematic=true; + collide_character=true; + + colliding=false; + collider=0; + margin=0.001; +} +KinematicBody::~KinematicBody() { + + +} + |