diff options
Diffstat (limited to 'scene/3d/physics_body_3d.cpp')
-rw-r--r-- | scene/3d/physics_body_3d.cpp | 1670 |
1 files changed, 850 insertions, 820 deletions
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 72d1762ab5..00c6664e65 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,91 +31,48 @@ #include "physics_body_3d.h" #include "core/core_string_names.h" -#include "core/engine.h" -#include "core/list.h" -#include "core/method_bind_ext.gen.inc" -#include "core/object.h" -#include "core/rid.h" -#include "scene/3d/collision_shape_3d.h" #include "scene/scene_string_names.h" -#include "servers/navigation_server_3d.h" #ifdef TOOLS_ENABLED #include "editor/plugins/node_3d_editor_plugin.h" #endif -Vector3 PhysicsBody3D::get_linear_velocity() const { - - return Vector3(); -} -Vector3 PhysicsBody3D::get_angular_velocity() const { - - return Vector3(); -} - -float PhysicsBody3D::get_inverse_mass() const { - - return 0; -} - -void PhysicsBody3D::set_collision_layer(uint32_t p_layer) { - - collision_layer = p_layer; - PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer); -} - -uint32_t PhysicsBody3D::get_collision_layer() const { - - return collision_layer; -} - -void PhysicsBody3D::set_collision_mask(uint32_t p_mask) { - - collision_mask = p_mask; - PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask); -} - -uint32_t PhysicsBody3D::get_collision_mask() const { - - return collision_mask; -} - -void PhysicsBody3D::set_collision_mask_bit(int p_bit, bool p_value) { +void PhysicsBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001)); + ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001)); - uint32_t mask = get_collision_mask(); - if (p_value) - mask |= 1 << p_bit; - else - mask &= ~(1 << p_bit); - set_collision_mask(mask); -} + ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); + ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); -bool PhysicsBody3D::get_collision_mask_bit(int p_bit) const { + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions); + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with); + ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with); - return get_collision_mask() & (1 << p_bit); + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); } -void PhysicsBody3D::set_collision_layer_bit(int p_bit, bool p_value) { - - uint32_t mask = get_collision_layer(); - if (p_value) - mask |= 1 << p_bit; - else - mask &= ~(1 << p_bit); - set_collision_layer(mask); +PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : + CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { + set_body_mode(p_mode); } -bool PhysicsBody3D::get_collision_layer_bit(int p_bit) const { - - return get_collision_layer() & (1 << p_bit); +PhysicsBody3D::~PhysicsBody3D() { + if (motion_cache.is_valid()) { + motion_cache->owner = nullptr; + } } -Array PhysicsBody3D::get_collision_exceptions() { +TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() { List<RID> exceptions; PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); Array ret; - for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) { - RID body = E->get(); + for (const RID &body : exceptions) { ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body); Object *obj = ObjectDB::get_instance(instance_id); PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj); @@ -125,7 +82,6 @@ Array PhysicsBody3D::get_collision_exceptions() { } void PhysicsBody3D::add_collision_exception_with(Node *p_node) { - ERR_FAIL_NULL(p_node); CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds."); @@ -133,49 +89,119 @@ void PhysicsBody3D::add_collision_exception_with(Node *p_node) { } void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { - ERR_FAIL_NULL(p_node); CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds."); PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } -void PhysicsBody3D::_set_layers(uint32_t p_mask) { - set_collision_layer(p_mask); - set_collision_mask(p_mask); +Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin) { + PhysicsServer3D::MotionResult result; + if (move_and_collide(p_motion, result, p_margin, p_test_only)) { + if (motion_cache.is_null()) { + motion_cache.instantiate(); + motion_cache->owner = this; + } + + motion_cache->result = result; + + return motion_cache; + } + + return Ref<KinematicCollision3D>(); } -uint32_t PhysicsBody3D::_get_layers() const { +bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) { + Transform3D gt = get_global_transform(); + bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_collide_separation_ray, p_exclude); + + // Restore direction of motion to be along original motion, + // in order to avoid sliding due to recovery, + // but only if collision depth is low enough to avoid tunneling. + if (p_cancel_sliding) { + real_t motion_length = p_motion.length(); + real_t precision = 0.001; + + if (colliding) { + // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, + // so even in normal resting cases the depth can be a bit more than the margin. + precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); + + if (r_result.collision_depth > (real_t)p_margin + precision) { + p_cancel_sliding = false; + } + } + + if (p_cancel_sliding) { + // When motion is null, recovery is the resulting motion. + Vector3 motion_normal; + if (motion_length > CMP_EPSILON) { + motion_normal = p_motion / motion_length; + } + + // Check depth of recovery. + real_t projected_length = r_result.travel.dot(motion_normal); + Vector3 recovery = r_result.travel - motion_normal * projected_length; + real_t recovery_length = recovery.length(); + // Fixes cases where canceling slide causes the motion to go too deep into the ground, + // because we're only taking rest information into account and not general recovery. + if (recovery_length < (real_t)p_margin + precision) { + // Apply adjustment to motion. + r_result.travel = motion_normal * projected_length; + r_result.remainder = p_motion - r_result.travel; + } + } + } + + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + r_result.travel[i] = 0; + } + } + + if (!p_test_only) { + gt.origin += r_result.travel; + set_global_transform(gt); + } - return get_collision_layer(); + return colliding; } -void PhysicsBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody3D::set_collision_layer); - ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody3D::get_collision_layer); +bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) { + ERR_FAIL_COND_V(!is_inside_tree(), false); - ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody3D::set_collision_mask); - ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody3D::get_collision_mask); + PhysicsServer3D::MotionResult *r = nullptr; + if (r_collision.is_valid()) { + // Needs const_cast because method bindings don't support non-const Ref. + r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result); + } - ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody3D::set_collision_mask_bit); - ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody3D::get_collision_mask_bit); + return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r); +} - ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody3D::set_collision_layer_bit); - ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody3D::get_collision_layer_bit); +void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { + if (p_lock) { + locked_axis |= p_axis; + } else { + locked_axis &= (~p_axis); + } + PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); +} - ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody3D::_set_layers); - ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody3D::_get_layers); +bool PhysicsBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { + return (locked_axis & p_axis); +} - ADD_GROUP("Collision", "collision_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); +Vector3 PhysicsBody3D::get_linear_velocity() const { + return Vector3(); } -PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : - CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(p_mode), false) { +Vector3 PhysicsBody3D::get_angular_velocity() const { + return Vector3(); +} - collision_layer = 1; - collision_mask = 1; +real_t PhysicsBody3D::get_inverse_mass() const { + return 0; } void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { @@ -198,28 +224,26 @@ Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const { } void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) { - constant_linear_velocity = p_vel; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); } void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) { - constant_angular_velocity = p_vel; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); } Vector3 StaticBody3D::get_constant_linear_velocity() const { - return constant_linear_velocity; } -Vector3 StaticBody3D::get_constant_angular_velocity() const { +Vector3 StaticBody3D::get_constant_angular_velocity() const { return constant_angular_velocity; } void StaticBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity); ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity); ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity); @@ -228,21 +252,15 @@ void StaticBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override); - ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions); - ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with); - ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); } -StaticBody3D::StaticBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { +StaticBody3D::StaticBody3D(PhysicsServer3D::BodyMode p_mode) : + PhysicsBody3D(p_mode) { } -StaticBody3D::~StaticBody3D() {} - void StaticBody3D::_reload_physics_characteristics() { if (physics_material_override.is_null()) { PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); @@ -253,8 +271,100 @@ void StaticBody3D::_reload_physics_characteristics() { } } -void RigidBody3D::_body_enter_tree(ObjectID p_id) { +Vector3 AnimatableBody3D::get_linear_velocity() const { + return linear_velocity; +} + +Vector3 AnimatableBody3D::get_angular_velocity() const { + return angular_velocity; +} + +void AnimatableBody3D::set_sync_to_physics(bool p_enable) { + if (sync_to_physics == p_enable) { + return; + } + + sync_to_physics = p_enable; + + _update_kinematic_motion(); +} + +bool AnimatableBody3D::is_sync_to_physics_enabled() const { + return sync_to_physics; +} + +void AnimatableBody3D::_update_kinematic_motion() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + if (sync_to_physics) { + set_only_update_transform_changes(true); + set_notify_local_transform(true); + } else { + set_only_update_transform_changes(false); + set_notify_local_transform(false); + } +} + +void AnimatableBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) { + AnimatableBody3D *body = (AnimatableBody3D *)p_instance; + body->_body_state_changed(p_state); +} + +void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); + + if (!sync_to_physics) { + return; + } + + last_valid_transform = p_state->get_transform(); + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); + _on_transform_changed(); +} + +void AnimatableBody3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + last_valid_transform = get_global_transform(); + } break; + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + // Used by sync to physics, send the new transform to the physics... + Transform3D new_transform = get_global_transform(); + + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); + + // ... but then revert changes. + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); + _on_transform_changed(); + } break; + } +} + +void AnimatableBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody3D::set_sync_to_physics); + ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody3D::is_sync_to_physics_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); +} +AnimatableBody3D::AnimatableBody3D() : + StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); + + _update_kinematic_motion(); +} + +void RigidBody3D::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = Object::cast_to<Node>(obj); ERR_FAIL_COND(!node); @@ -271,15 +381,13 @@ void RigidBody3D::_body_enter_tree(ObjectID p_id) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); for (int i = 0; i < E->get().shapes.size(); i++) { - - emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape); + emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape); } contact_monitor->locked = false; } void RigidBody3D::_body_exit_tree(ObjectID p_id) { - Object *obj = ObjectDB::get_instance(p_id); Node *node = Object::cast_to<Node>(obj); ERR_FAIL_COND(!node); @@ -294,15 +402,13 @@ void RigidBody3D::_body_exit_tree(ObjectID p_id) { emit_signal(SceneStringNames::get_singleton()->body_exited, node); for (int i = 0; i < E->get().shapes.size(); i++) { - - emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape); + emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape); } contact_monitor->locked = false; } -void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape) { - +void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) { bool body_in = p_status == 1; ObjectID objid = p_instance; @@ -316,8 +422,8 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap if (body_in) { if (!E) { - E = contact_monitor->body_map.insert(objid, BodyState()); + E->get().rid = p_body; //E->get().rc=0; E->get().in_tree = node && node->is_inside_tree(); if (node) { @@ -329,98 +435,101 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap } } //E->get().rc++; - if (node) + if (node) { E->get().shapes.insert(ShapePair(p_body_shape, p_local_shape)); + } if (E->get().in_tree) { - emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_local_shape); + emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape); } } else { - //E->get().rc--; - if (node) + if (node) { E->get().shapes.erase(ShapePair(p_body_shape, p_local_shape)); + } bool in_tree = E->get().in_tree; - if (E->get().shapes.empty()) { - + if (E->get().shapes.is_empty()) { if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree)); - if (in_tree) + if (in_tree) { emit_signal(SceneStringNames::get_singleton()->body_exited, node); + } } contact_monitor->body_map.erase(E); } if (node && in_tree) { - emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_local_shape); + emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_local_shape); } } } struct _RigidBodyInOut { - + RID rid; ObjectID id; - int shape; - int local_shape; + int shape = 0; + int local_shape = 0; }; -void RigidBody3D::_direct_state_changed(Object *p_state) { - -#ifdef DEBUG_ENABLED - state = Object::cast_to<PhysicsDirectBodyState3D>(p_state); -#else - state = (PhysicsDirectBodyState3D *)p_state; //trust it -#endif +void RigidBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) { + RigidBody3D *body = (RigidBody3D *)p_instance; + body->_body_state_changed(p_state); +} +void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { set_ignore_transform_notification(true); - set_global_transform(state->get_transform()); - linear_velocity = state->get_linear_velocity(); - angular_velocity = state->get_angular_velocity(); - if (sleeping != state->is_sleeping()) { - sleeping = state->is_sleeping(); + set_global_transform(p_state->get_transform()); + + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); + + inverse_inertia_tensor = p_state->get_inverse_inertia_tensor(); + + if (sleeping != p_state->is_sleeping()) { + sleeping = p_state->is_sleeping(); emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); } - if (get_script_instance()) - get_script_instance()->call("_integrate_forces", state); + + GDVIRTUAL_CALL(_integrate_forces, p_state); + set_ignore_transform_notification(false); + _on_transform_changed(); if (contact_monitor) { - contact_monitor->locked = true; //untag all int rc = 0; for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) { - for (int i = 0; i < E->get().shapes.size(); i++) { - E->get().shapes[i].tagged = false; rc++; } } - _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(state->get_contact_count() * sizeof(_RigidBodyInOut)); + _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBodyInOut)); int toadd_count = 0; //state->get_contact_count(); RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction)); int toremove_count = 0; //put the ones to add - for (int i = 0; i < state->get_contact_count(); i++) { - - ObjectID obj = state->get_contact_collider_id(i); - int local_shape = state->get_contact_local_shape(i); - int shape = state->get_contact_collider_shape(i); + for (int i = 0; i < p_state->get_contact_count(); i++) { + RID rid = p_state->get_contact_collider(i); + ObjectID obj = p_state->get_contact_collider_id(i); + int local_shape = p_state->get_contact_local_shape(i); + int shape = p_state->get_contact_collider_shape(i); //bool found=false; Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj); if (!E) { + toadd[toadd_count].rid = rid; toadd[toadd_count].local_shape = local_shape; toadd[toadd_count].id = obj; toadd[toadd_count].shape = shape; @@ -431,7 +540,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) { ShapePair sp(shape, local_shape); int idx = E->get().shapes.find(sp); if (idx == -1) { - + toadd[toadd_count].rid = rid; toadd[toadd_count].local_shape = local_shape; toadd[toadd_count].id = obj; toadd[toadd_count].shape = shape; @@ -445,11 +554,9 @@ void RigidBody3D::_direct_state_changed(Object *p_state) { //put the ones to remove for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) { - for (int i = 0; i < E->get().shapes.size(); i++) { - if (!E->get().shapes[i].tagged) { - + toremove[toremove_count].rid = E->get().rid; toremove[toremove_count].body_id = E->key(); toremove[toremove_count].pair = E->get().shapes[i]; toremove_count++; @@ -457,95 +564,125 @@ void RigidBody3D::_direct_state_changed(Object *p_state) { } } - //process remotions + //process removals for (int i = 0; i < toremove_count; i++) { - - _body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); + _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); } - //process aditions + //process additions for (int i = 0; i < toadd_count; i++) { - - _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape); + _body_inout(1, toremove[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape); } contact_monitor->locked = false; } - - state = nullptr; } void RigidBody3D::_notification(int p_what) { - #ifdef TOOLS_ENABLED - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); //used for warnings and only in editor - } - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); //used for warnings and only in editor + } + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warning(); - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; } - #endif } void RigidBody3D::set_mode(Mode p_mode) { - mode = p_mode; switch (p_mode) { - - case MODE_RIGID: { - - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID); + case MODE_DYNAMIC: { + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); } break; case MODE_STATIC: { - - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); - + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); } break; - case MODE_CHARACTER: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_CHARACTER); - + case MODE_DYNAMIC_LOCKED: { + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED); } break; case MODE_KINEMATIC: { - - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); } break; } - update_configuration_warning(); + update_configuration_warnings(); } RigidBody3D::Mode RigidBody3D::get_mode() const { - return mode; } void RigidBody3D::set_mass(real_t p_mass) { - ERR_FAIL_COND(p_mass <= 0); mass = p_mass; - _change_notify("mass"); - _change_notify("weight"); PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass); } -real_t RigidBody3D::get_mass() const { +real_t RigidBody3D::get_mass() const { return mass; } -void RigidBody3D::set_weight(real_t p_weight) { +void RigidBody3D::set_inertia(const Vector3 &p_inertia) { + ERR_FAIL_COND(p_inertia.x < 0); + ERR_FAIL_COND(p_inertia.y < 0); + ERR_FAIL_COND(p_inertia.z < 0); + + inertia = p_inertia; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); +} + +const Vector3 &RigidBody3D::get_inertia() const { + return inertia; +} + +void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) { + if (center_of_mass_mode == p_mode) { + return; + } + + center_of_mass_mode = p_mode; + + switch (center_of_mass_mode) { + case CENTER_OF_MASS_MODE_AUTO: { + center_of_mass = Vector3(); + PhysicsServer3D::get_singleton()->body_reset_mass_properties(get_rid()); + if (inertia != Vector3()) { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); + } + } break; + + case CENTER_OF_MASS_MODE_CUSTOM: { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); + } break; + } +} + +RigidBody3D::CenterOfMassMode RigidBody3D::get_center_of_mass_mode() const { + return center_of_mass_mode; +} + +void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) { + if (center_of_mass == p_center_of_mass) { + return; + } - set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8))); + ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); + center_of_mass = p_center_of_mass; + + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); } -real_t RigidBody3D::get_weight() const { - return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)); +const Vector3 &RigidBody3D::get_center_of_mass() const { + return center_of_mass; } void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { @@ -568,121 +705,100 @@ Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const { } void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) { - gravity_scale = p_gravity_scale; PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); } -real_t RigidBody3D::get_gravity_scale() const { +real_t RigidBody3D::get_gravity_scale() const { return gravity_scale; } void RigidBody3D::set_linear_damp(real_t p_linear_damp) { - ERR_FAIL_COND(p_linear_damp < -1); linear_damp = p_linear_damp; PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp); } -real_t RigidBody3D::get_linear_damp() const { +real_t RigidBody3D::get_linear_damp() const { return linear_damp; } void RigidBody3D::set_angular_damp(real_t p_angular_damp) { - ERR_FAIL_COND(p_angular_damp < -1); angular_damp = p_angular_damp; PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp); } -real_t RigidBody3D::get_angular_damp() const { +real_t RigidBody3D::get_angular_damp() const { return angular_damp; } void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) { - - Vector3 v = state ? state->get_linear_velocity() : linear_velocity; Vector3 axis = p_axis.normalized(); - v -= axis * axis.dot(v); - v += p_axis; - if (state) { - set_linear_velocity(v); - } else { - PhysicsServer3D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis); - linear_velocity = v; - } + linear_velocity -= axis * axis.dot(linear_velocity); + linear_velocity += p_axis; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); } void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) { - linear_velocity = p_velocity; - if (state) - state->set_linear_velocity(linear_velocity); - else - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); } Vector3 RigidBody3D::get_linear_velocity() const { - return linear_velocity; } void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) { - angular_velocity = p_velocity; - if (state) - state->set_angular_velocity(angular_velocity); - else - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); } -Vector3 RigidBody3D::get_angular_velocity() const { +Vector3 RigidBody3D::get_angular_velocity() const { return angular_velocity; } -void RigidBody3D::set_use_custom_integrator(bool p_enable) { +Basis RigidBody3D::get_inverse_inertia_tensor() const { + return inverse_inertia_tensor; +} - if (custom_integrator == p_enable) +void RigidBody3D::set_use_custom_integrator(bool p_enable) { + if (custom_integrator == p_enable) { return; + } custom_integrator = p_enable; PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); } -bool RigidBody3D::is_using_custom_integrator() { +bool RigidBody3D::is_using_custom_integrator() { return custom_integrator; } void RigidBody3D::set_sleeping(bool p_sleeping) { - sleeping = p_sleeping; PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping); } void RigidBody3D::set_can_sleep(bool p_active) { - can_sleep = p_active; PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active); } bool RigidBody3D::is_able_to_sleep() const { - return can_sleep; } bool RigidBody3D::is_sleeping() const { - return sleeping; } void RigidBody3D::set_max_contacts_reported(int p_amount) { - max_contacts_reported = p_amount; PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount); } int RigidBody3D::get_max_contacts_reported() const { - return max_contacts_reported; } @@ -690,8 +806,9 @@ void RigidBody3D::add_central_force(const Vector3 &p_force) { PhysicsServer3D::get_singleton()->body_add_central_force(get_rid(), p_force); } -void RigidBody3D::add_force(const Vector3 &p_force, const Vector3 &p_pos) { - PhysicsServer3D::get_singleton()->body_add_force(get_rid(), p_force, p_pos); +void RigidBody3D::add_force(const Vector3 &p_force, const Vector3 &p_position) { + PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); + singleton->body_add_force(get_rid(), p_force, p_position); } void RigidBody3D::add_torque(const Vector3 &p_torque) { @@ -702,9 +819,9 @@ void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) { PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); } -void RigidBody3D::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) { - - PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); +void RigidBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { + PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); + singleton->body_apply_impulse(get_rid(), p_impulse, p_position); } void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) { @@ -712,27 +829,23 @@ void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) { } void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) { - ccd = p_enable; PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable); } bool RigidBody3D::is_using_continuous_collision_detection() const { - return ccd; } void RigidBody3D::set_contact_monitor(bool p_enabled) { - - if (p_enabled == is_contact_monitor_enabled()) + if (p_enabled == is_contact_monitor_enabled()) { return; + } if (!p_enabled) { - ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead."); for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) { - //clean up mess Object *obj = ObjectDB::get_instance(E->key()); Node *node = Object::cast_to<Node>(obj); @@ -746,27 +859,16 @@ void RigidBody3D::set_contact_monitor(bool p_enabled) { memdelete(contact_monitor); contact_monitor = nullptr; } else { - contact_monitor = memnew(ContactMonitor); contact_monitor->locked = false; } } bool RigidBody3D::is_contact_monitor_enabled() const { - return contact_monitor != nullptr; } -void RigidBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); -} - -bool RigidBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); -} - Array RigidBody3D::get_colliding_bodies() const { - ERR_FAIL_COND_V(!contact_monitor, Array()); Array ret; @@ -784,32 +886,33 @@ Array RigidBody3D::get_colliding_bodies() const { return ret; } -String RigidBody3D::get_configuration_warning() const { - - Transform t = get_transform(); +TypedArray<String> RigidBody3D::get_configuration_warnings() const { + Transform3D t = get_transform(); - String warning = CollisionObject3D::get_configuration_warning(); + TypedArray<String> warnings = Node::get_configuration_warnings(); - if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { - if (warning != String()) { - warning += "\n\n"; - } - warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); + if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { + warnings.push_back(TTR("Size changes to RigidBody3D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } - return warning; + return warnings; } void RigidBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidBody3D::set_mode); ClassDB::bind_method(D_METHOD("get_mode"), &RigidBody3D::get_mode); ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass); - ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody3D::set_weight); - ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody3D::get_weight); + ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody3D::set_inertia); + ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody3D::get_inertia); + + ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody3D::set_center_of_mass_mode); + ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody3D::get_center_of_mass_mode); + + ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody3D::set_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody3D::get_center_of_mass); ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override); @@ -820,6 +923,8 @@ void RigidBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity); ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity); + ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor); + ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale); ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale); @@ -844,11 +949,11 @@ void RigidBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity); ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody3D::add_central_force); - ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody3D::add_force); + ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody3D::add_force, Vector3()); ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody3D::add_torque); ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse); - ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody3D::apply_impulse); + ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody3D::apply_impulse, Vector3()); ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse); ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping); @@ -857,18 +962,16 @@ void RigidBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep); - ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody3D::_direct_state_changed); - - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody3D::get_axis_lock); - ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies); - BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D"))); + GDVIRTUAL_BIND(_integrate_forces, "state"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater"), "set_center_of_mass", "get_center_of_mass"); + ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); @@ -877,13 +980,6 @@ void RigidBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); @@ -891,46 +987,38 @@ void RigidBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - BIND_ENUM_CONSTANT(MODE_RIGID); + BIND_ENUM_CONSTANT(MODE_DYNAMIC); BIND_ENUM_CONSTANT(MODE_STATIC); - BIND_ENUM_CONSTANT(MODE_CHARACTER); + BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(MODE_KINEMATIC); -} - -RigidBody3D::RigidBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) { - - mode = MODE_RIGID; - - mass = 1; - max_contacts_reported = 0; - state = nullptr; - gravity_scale = 1; - linear_damp = -1; - angular_damp = -1; - - //angular_velocity=0; - sleeping = false; - ccd = false; + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); +} - custom_integrator = false; - contact_monitor = nullptr; - can_sleep = true; +void RigidBody3D::_validate_property(PropertyInfo &property) const { + if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { + if (property.name == "center_of_mass") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } +} - PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); +RigidBody3D::RigidBody3D() : + PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) { + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); } RigidBody3D::~RigidBody3D() { - - if (contact_monitor) + if (contact_monitor) { memdelete(contact_monitor); + } } void RigidBody3D::_reload_physics_characteristics() { @@ -943,461 +1031,446 @@ void RigidBody3D::_reload_physics_characteristics() { } } -////////////////////////////////////////////////////// -////////////////////////// - -Ref<KinematicCollision3D> KinematicBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) { - - Collision col; - if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) { - if (motion_cache.is_null()) { - motion_cache.instance(); - motion_cache->owner = this; - } - - motion_cache->collision = col; - - return motion_cache; - } - - return Ref<KinematicCollision3D>(); -} - -Vector3 KinematicBody3D::get_linear_velocity() const { - return linear_velocity; -} - -Vector3 KinematicBody3D::get_angular_velocity() const { - return angular_velocity; -} - -bool KinematicBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { - - Transform gt = get_global_transform(); - PhysicsServer3D::MotionResult result; - bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes); - - if (colliding) { - r_collision.collider_metadata = result.collider_metadata; - r_collision.collider_shape = result.collider_shape; - r_collision.collider_vel = result.collider_velocity; - r_collision.collision = result.collision_point; - r_collision.normal = result.collision_normal; - r_collision.collider = result.collider_id; - r_collision.collider_rid = result.collider; - r_collision.travel = result.motion; - r_collision.remainder = result.remainder; - r_collision.local_shape = result.collision_local_shape; - } - - for (int i = 0; i < 3; i++) { - if (locked_axis & (1 << i)) { - result.motion[i] = 0; - } - } - - if (!p_test_only) { - gt.origin += result.motion; - set_global_transform(gt); - } - - return colliding; -} +/////////////////////////////////////// //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +bool CharacterBody3D::move_and_slide() { + bool was_on_floor = on_floor; - Vector3 body_velocity = p_linear_velocity; - Vector3 body_velocity_normal = body_velocity.normalized(); + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); for (int i = 0; i < 3; i++) { if (locked_axis & (1 << i)) { - body_velocity[i] = 0; + linear_velocity[i] = 0.0; } } - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - Vector3 motion = (floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); + Vector3 current_floor_velocity = floor_velocity; + if ((on_floor || on_wall) && on_floor_body.is_valid()) { + //this approach makes sure there is less delay between the actual body velocity and the one we saved + PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(on_floor_body); + if (bs) { + Transform3D gt = get_global_transform(); + Vector3 local_position = gt.origin - bs->get_transform().origin; + current_floor_velocity = bs->get_velocity_at_local_position(local_position); + } + } + motion_results.clear(); on_floor = false; - on_floor_body = RID(); on_ceiling = false; on_wall = false; - colliders.clear(); floor_normal = Vector3(); floor_velocity = Vector3(); - while (p_max_slides) { - - Collision collision; - bool found_collision = false; + if (!current_floor_velocity.is_equal_approx(Vector3()) && on_floor_body.is_valid()) { + PhysicsServer3D::MotionResult floor_result; + Set<RID> exclude; + exclude.insert(on_floor_body); + if (move_and_collide(current_floor_velocity * delta, floor_result, margin, false, false, false, exclude)) { + motion_results.push_back(floor_result); + _set_collision_direction(floor_result); + } + } - for (int i = 0; i < 2; ++i) { - bool collided; - if (i == 0) { //collide - collided = move_and_collide(motion, p_infinite_inertia, collision); - if (!collided) { - motion = Vector3(); //clear because no collision happened and motion completed - } - } else { //separate raycasts (if any) - collided = separate_raycast_shapes(p_infinite_inertia, collision); - if (collided) { - collision.remainder = motion; //keep - collision.travel = Vector3(); + on_floor_body = RID(); + Vector3 motion = linear_velocity * delta; + + // No sliding on first attempt to keep floor motion stable when possible, + // when stop on slope is enabled. + bool sliding_enabled = !floor_stop_on_slope; + + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer3D::MotionResult result; + bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled); + if (collided) { + motion_results.push_back(result); + _set_collision_direction(result); + + if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) { + Transform3D gt = get_global_transform(); + if (result.travel.length() > margin) { + gt.origin -= result.travel.slide(up_direction); + } else { + gt.origin -= result.travel; } + set_global_transform(gt); + linear_velocity = Vector3(); + motion = Vector3(); + break; } - if (collided) { - found_collision = true; - - colliders.push_back(collision); - motion = collision.remainder; + if (result.remainder.is_equal_approx(Vector3())) { + motion = Vector3(); + break; + } - if (p_up_direction == Vector3()) { - //all is a wall - on_wall = true; + if (sliding_enabled || !on_floor) { + Vector3 slide_motion = result.remainder.slide(result.collision_normal); + if (slide_motion.dot(linear_velocity) > 0.0) { + motion = slide_motion; } else { - if (Math::acos(collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor - - on_floor = true; - floor_normal = collision.normal; - on_floor_body = collision.collider_rid; - floor_velocity = collision.collider_vel; - - if (p_stop_on_slope) { - if ((body_velocity_normal + p_up_direction).length() < 0.01 && collision.travel.length() < 1) { - Transform gt = get_global_transform(); - gt.origin -= collision.travel.slide(p_up_direction); - set_global_transform(gt); - return Vector3(); - } - } - } else if (Math::acos(collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling - on_ceiling = true; - } else { - on_wall = true; - } + motion = Vector3(); } + } else { + motion = result.remainder; + } + } + + sliding_enabled = true; - motion = motion.slide(collision.normal); - body_velocity = body_velocity.slide(collision.normal); + if (!collided || motion.is_equal_approx(Vector3())) { + break; + } + } - for (int j = 0; j < 3; j++) { - if (locked_axis & (1 << j)) { - body_velocity[j] = 0; + if (was_on_floor && !on_floor && !snap.is_equal_approx(Vector3())) { + // Apply snap. + Transform3D gt = get_global_transform(); + PhysicsServer3D::MotionResult result; + if (move_and_collide(snap, result, margin, true, false, true)) { + bool apply = true; + if (up_direction != Vector3()) { + if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + on_floor = true; + floor_normal = result.collision_normal; + on_floor_body = result.collider; + floor_velocity = result.collider_velocity; + if (floor_stop_on_slope) { + // move and collide may stray the object a bit because of pre un-stucking, + // so only ensure that motion happens on floor direction in this case. + if (result.travel.length() > margin) { + result.travel = result.travel.project(up_direction); + } else { + result.travel = Vector3(); + } } + } else { + apply = false; //snapped with floor direction, but did not snap to a floor, do not snap. } } + if (apply) { + gt.origin += result.travel; + set_global_transform(gt); + } } - - if (!found_collision || motion == Vector3()) - break; - - --p_max_slides; } - return body_velocity; -} - -Vector3 KinematicBody3D::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { - - bool was_on_floor = on_floor; - - Vector3 ret = move_and_slide(p_linear_velocity, p_up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); - if (!was_on_floor || p_snap == Vector3()) { - return ret; + if (!on_floor && !on_wall) { + // Add last platform velocity when just left a moving platform. + linear_velocity += current_floor_velocity; } - Collision col; - Transform gt = get_global_transform(); + // Reset the gravity accumulation when touching the ground. + if (on_floor && linear_velocity.dot(up_direction) <= 0) { + linear_velocity = linear_velocity.slide(up_direction); + } - if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { + return motion_results.size() > 0; +} - bool apply = true; - if (p_up_direction != Vector3()) { - if (Math::acos(p_up_direction.normalized().dot(col.normal)) < p_floor_max_angle) { - on_floor = true; - floor_normal = col.normal; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; - if (p_stop_on_slope) { - // move and collide may stray the object a bit because of pre un-stucking, - // so only ensure that motion happens on floor direction in this case. - col.travel = col.travel.project(p_up_direction); - } - } else { - apply = false; //snapped with floor direction, but did not snap to a floor, do not snap. +void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result) { + if (up_direction == Vector3()) { + //all is a wall + on_wall = true; + } else { + if (p_result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + on_floor = true; + floor_normal = p_result.collision_normal; + on_floor_body = p_result.collider; + floor_velocity = p_result.collider_velocity; + } else if (p_result.get_angle(-up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + on_ceiling = true; + } else { + on_wall = true; + // Don't apply wall velocity when the collider is a CharacterBody3D. + if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) { + on_floor_body = p_result.collider; + floor_velocity = p_result.collider_velocity; } } - if (apply) { - gt.origin += col.travel; - set_global_transform(gt); - } } - - return ret; } -bool KinematicBody3D::is_on_floor() const { - - return on_floor; +void CharacterBody3D::set_safe_margin(real_t p_margin) { + margin = p_margin; } -bool KinematicBody3D::is_on_wall() const { - - return on_wall; +real_t CharacterBody3D::get_safe_margin() const { + return margin; } -bool KinematicBody3D::is_on_ceiling() const { - return on_ceiling; +Vector3 CharacterBody3D::get_linear_velocity() const { + return linear_velocity; } -Vector3 KinematicBody3D::get_floor_normal() const { - - return floor_normal; +void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) { + linear_velocity = p_velocity; } -Vector3 KinematicBody3D::get_floor_velocity() const { - - return floor_velocity; +bool CharacterBody3D::is_on_floor() const { + return on_floor; } -bool KinematicBody3D::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) { - - ERR_FAIL_COND_V(!is_inside_tree(), false); - - return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia); +bool CharacterBody3D::is_on_floor_only() const { + return on_floor && !on_wall && !on_ceiling; } -bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) { - - PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays - - Transform gt = get_global_transform(); - - Vector3 recover; - int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); - int deepest = -1; - float deepest_depth; - for (int i = 0; i < hits; i++) { - if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) { - deepest = i; - deepest_depth = sep_res[i].collision_depth; - } - } - - gt.origin += recover; - set_global_transform(gt); - - if (deepest != -1) { - r_collision.collider = sep_res[deepest].collider_id; - r_collision.collider_metadata = sep_res[deepest].collider_metadata; - r_collision.collider_shape = sep_res[deepest].collider_shape; - r_collision.collider_vel = sep_res[deepest].collider_velocity; - r_collision.collision = sep_res[deepest].collision_point; - r_collision.normal = sep_res[deepest].collision_normal; - r_collision.local_shape = sep_res[deepest].collision_local_shape; - r_collision.travel = recover; - r_collision.remainder = Vector3(); - - return true; - } else { - return false; - } +bool CharacterBody3D::is_on_wall() const { + return on_wall; } -void KinematicBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); +bool CharacterBody3D::is_on_wall_only() const { + return on_wall && !on_floor && !on_ceiling; } -bool KinematicBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); +bool CharacterBody3D::is_on_ceiling() const { + return on_ceiling; } -void KinematicBody3D::set_safe_margin(float p_margin) { - - margin = p_margin; - PhysicsServer3D::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin); +bool CharacterBody3D::is_on_ceiling_only() const { + return on_ceiling && !on_floor && !on_wall; } -float KinematicBody3D::get_safe_margin() const { +Vector3 CharacterBody3D::get_floor_normal() const { + return floor_normal; +} - return margin; +real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector3(), 0); + return Math::acos(floor_normal.dot(p_up_direction)); } -int KinematicBody3D::get_slide_count() const { - return colliders.size(); +Vector3 CharacterBody3D::get_platform_velocity() const { + return floor_velocity; } -KinematicBody3D::Collision KinematicBody3D::get_slide_collision(int p_bounce) const { - ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision()); - return colliders[p_bounce]; +int CharacterBody3D::get_slide_collision_count() const { + return motion_results.size(); } -Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) { +PhysicsServer3D::MotionResult CharacterBody3D::get_slide_collision(int p_bounce) const { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer3D::MotionResult()); + return motion_results[p_bounce]; +} - ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision3D>()); +Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision3D>()); if (p_bounce >= slide_colliders.size()) { slide_colliders.resize(p_bounce + 1); } if (slide_colliders[p_bounce].is_null()) { - slide_colliders.write[p_bounce].instance(); + slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } - slide_colliders.write[p_bounce]->collision = colliders[p_bounce]; + slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; return slide_colliders[p_bounce]; } -void KinematicBody3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - // Reset move_and_slide() data. - on_floor = false; - on_floor_body = RID(); - on_ceiling = false; - on_wall = false; - colliders.clear(); - floor_velocity = Vector3(); +Ref<KinematicCollision3D> CharacterBody3D::_get_last_slide_collision() { + if (motion_results.size() == 0) { + return Ref<KinematicCollision3D>(); } + return _get_slide_collision(motion_results.size() - 1); } -void KinematicBody3D::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody3D::_direct_state_changed); - - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); +bool CharacterBody3D::is_floor_stop_on_slope_enabled() const { + return floor_stop_on_slope; +} - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody3D::test_move, DEFVAL(true)); +void CharacterBody3D::set_floor_stop_on_slope_enabled(bool p_enabled) { + floor_stop_on_slope = p_enabled; +} - ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody3D::is_on_floor); - ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody3D::is_on_ceiling); - ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody3D::is_on_wall); - ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody3D::get_floor_normal); - ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody3D::get_floor_velocity); +int CharacterBody3D::get_max_slides() const { + return max_slides; +} - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &KinematicBody3D::get_axis_lock); +void CharacterBody3D::set_max_slides(int p_max_slides) { + ERR_FAIL_COND(p_max_slides < 1); + max_slides = p_max_slides; +} - ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody3D::set_safe_margin); - ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody3D::get_safe_margin); +real_t CharacterBody3D::get_floor_max_angle() const { + return floor_max_angle; +} - ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody3D::get_slide_count); - ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody3D::_get_slide_collision); +void CharacterBody3D::set_floor_max_angle(real_t p_radians) { + floor_max_angle = p_radians; +} - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); +const Vector3 &CharacterBody3D::get_snap() const { + return snap; +} - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); +void CharacterBody3D::set_snap(const Vector3 &p_snap) { + snap = p_snap; } -void KinematicBody3D::_direct_state_changed(Object *p_state) { -#ifdef DEBUG_ENABLED - PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state); -#else - PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it -#endif +const Vector3 &CharacterBody3D::get_up_direction() const { + return up_direction; +} - linear_velocity = state->get_linear_velocity(); - angular_velocity = state->get_angular_velocity(); +void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) { + up_direction = p_up_direction.normalized(); } -KinematicBody3D::KinematicBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { +void CharacterBody3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + // Reset move_and_slide() data. + on_floor = false; + on_floor_body = RID(); + on_ceiling = false; + on_wall = false; + motion_results.clear(); + floor_velocity = Vector3(); + } break; + } +} - margin = 0.001; - locked_axis = 0; - on_floor = false; - on_ceiling = false; - on_wall = false; +void CharacterBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody3D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody3D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); + ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides); + ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides); + ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle); + ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle); + ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody3D::get_snap); + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody3D::set_snap); + ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction); + ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction); + + ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody3D::is_on_ceiling_only); + ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall); + ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody3D::is_on_wall_only); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal); + ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0))); + ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity); + + ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count); + ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision); + ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision); - PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap"), "set_snap", "get_snap"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); + ADD_GROUP("Floor", "floor_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); } -KinematicBody3D::~KinematicBody3D() { - if (motion_cache.is_valid()) { - motion_cache->owner = nullptr; - } +CharacterBody3D::CharacterBody3D() : + PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { +} +CharacterBody3D::~CharacterBody3D() { for (int i = 0; i < slide_colliders.size(); i++) { if (slide_colliders[i].is_valid()) { slide_colliders.write[i]->owner = nullptr; } } } + /////////////////////////////////////// Vector3 KinematicCollision3D::get_position() const { - - return collision.collision; + return result.collision_point; } + Vector3 KinematicCollision3D::get_normal() const { - return collision.normal; + return result.collision_normal; } + Vector3 KinematicCollision3D::get_travel() const { - return collision.travel; + return result.travel; } + Vector3 KinematicCollision3D::get_remainder() const { - return collision.remainder; + return result.remainder; +} + +real_t KinematicCollision3D::get_angle(const Vector3 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector3(), 0); + return result.get_angle(p_up_direction); } + Object *KinematicCollision3D::get_local_shape() const { - if (!owner) return nullptr; - uint32_t ownerid = owner->shape_find_owner(collision.local_shape); + if (!owner) { + return nullptr; + } + uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape); return owner->shape_owner_get_owner(ownerid); } Object *KinematicCollision3D::get_collider() const { - - if (collision.collider.is_valid()) { - return ObjectDB::get_instance(collision.collider); + if (result.collider_id.is_valid()) { + return ObjectDB::get_instance(result.collider_id); } return nullptr; } + ObjectID KinematicCollision3D::get_collider_id() const { + return result.collider_id; +} - return collision.collider; +RID KinematicCollision3D::get_collider_rid() const { + return result.collider; } -Object *KinematicCollision3D::get_collider_shape() const { +Object *KinematicCollision3D::get_collider_shape() const { Object *collider = get_collider(); if (collider) { CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider); if (obj2d) { - uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape); + uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape); return obj2d->shape_owner_get_owner(ownerid); } } return nullptr; } -int KinematicCollision3D::get_collider_shape_index() const { - return collision.collider_shape; +int KinematicCollision3D::get_collider_shape_index() const { + return result.collider_shape; } -Vector3 KinematicCollision3D::get_collider_velocity() const { - return collision.collider_vel; +Vector3 KinematicCollision3D::get_collider_velocity() const { + return result.collider_velocity; } -Variant KinematicCollision3D::get_collider_metadata() const { +Variant KinematicCollision3D::get_collider_metadata() const { return Variant(); } void KinematicCollision3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision3D::get_position); ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision3D::get_normal); ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel); ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder); + ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision3D::get_angle, DEFVAL(Vector3(0.0, 1.0, 0.0))); ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision3D::get_local_shape); ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision3D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision3D::get_collider_id); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision3D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision3D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision3D::get_collider_shape_index); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision3D::get_collider_velocity); @@ -1410,19 +1483,13 @@ void KinematicCollision3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity"); ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata"); } -KinematicCollision3D::KinematicCollision3D() { - - collision.collider_shape = 0; - collision.local_shape = 0; - owner = nullptr; -} - /////////////////////////////////////// bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) { @@ -1440,8 +1507,8 @@ void PhysicalBone3D::apply_central_impulse(const Vector3 &p_impulse) { PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); } -void PhysicalBone3D::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) { - PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); +void PhysicalBone3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { + PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); } void PhysicalBone3D::reset_physics_simulation_state() { @@ -1469,18 +1536,21 @@ bool PhysicalBone3D::PinJointData::_set(const StringName &p_name, const Variant if ("joint_constraints/bias" == p_name) { bias = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_BIAS, bias); + } } else if ("joint_constraints/damping" == p_name) { damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_DAMPING, damping); + } } else if ("joint_constraints/impulse_clamp" == p_name) { impulse_clamp = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp); + } } else { return false; @@ -1522,28 +1592,33 @@ bool PhysicalBone3D::ConeJointData::_set(const StringName &p_name, const Variant if ("joint_constraints/swing_span" == p_name) { swing_span = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, swing_span); + } } else if ("joint_constraints/twist_span" == p_name) { twist_span = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, twist_span); + } } else if ("joint_constraints/bias" == p_name) { bias = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, bias); + } } else if ("joint_constraints/softness" == p_name) { softness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, softness); + } } else if ("joint_constraints/relaxation" == p_name) { relaxation = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, relaxation); + } } else { return false; @@ -1591,33 +1666,39 @@ bool PhysicalBone3D::HingeJointData::_set(const StringName &p_name, const Varian if ("joint_constraints/angular_limit_enabled" == p_name) { angular_limit_enabled = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->hinge_joint_set_flag(j, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled); + } } else if ("joint_constraints/angular_limit_upper" == p_name) { angular_limit_upper = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper); + } } else if ("joint_constraints/angular_limit_lower" == p_name) { angular_limit_lower = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower); + } } else if ("joint_constraints/angular_limit_bias" == p_name) { angular_limit_bias = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias); + } } else if ("joint_constraints/angular_limit_softness" == p_name) { angular_limit_softness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness); + } } else if ("joint_constraints/angular_limit_relaxation" == p_name) { angular_limit_relaxation = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation); + } } else { return false; @@ -1668,53 +1749,63 @@ bool PhysicalBone3D::SliderJointData::_set(const StringName &p_name, const Varia if ("joint_constraints/linear_limit_upper" == p_name) { linear_limit_upper = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper); + } } else if ("joint_constraints/linear_limit_lower" == p_name) { linear_limit_lower = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower); + } } else if ("joint_constraints/linear_limit_softness" == p_name) { linear_limit_softness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness); + } } else if ("joint_constraints/linear_limit_restitution" == p_name) { linear_limit_restitution = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution); + } } else if ("joint_constraints/linear_limit_damping" == p_name) { linear_limit_damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution); + } } else if ("joint_constraints/angular_limit_upper" == p_name) { angular_limit_upper = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper); + } } else if ("joint_constraints/angular_limit_lower" == p_name) { angular_limit_lower = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower); + } } else if ("joint_constraints/angular_limit_softness" == p_name) { angular_limit_softness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); + } } else if ("joint_constraints/angular_limit_restitution" == p_name) { angular_limit_restitution = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); + } } else if ("joint_constraints/angular_limit_damping" == p_name) { angular_limit_damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping); + } } else { return false; @@ -1778,6 +1869,10 @@ bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Varia String path = p_name; + if (!path.begins_with("joint_constraints/")) { + return false; + } + Vector3::Axis axis; { const String axis_s = path.get_slicec('/', 1); @@ -1796,108 +1891,129 @@ bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Varia if ("linear_limit_enabled" == var_name) { axis_data[axis].linear_limit_enabled = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled); + } } else if ("linear_limit_upper" == var_name) { axis_data[axis].linear_limit_upper = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper); + } } else if ("linear_limit_lower" == var_name) { axis_data[axis].linear_limit_lower = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower); + } } else if ("linear_limit_softness" == var_name) { axis_data[axis].linear_limit_softness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness); + } } else if ("linear_spring_enabled" == var_name) { axis_data[axis].linear_spring_enabled = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, axis_data[axis].linear_spring_enabled); + } } else if ("linear_spring_stiffness" == var_name) { axis_data[axis].linear_spring_stiffness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, axis_data[axis].linear_spring_stiffness); + } } else if ("linear_spring_damping" == var_name) { axis_data[axis].linear_spring_damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, axis_data[axis].linear_spring_damping); + } } else if ("linear_equilibrium_point" == var_name) { axis_data[axis].linear_equilibrium_point = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].linear_equilibrium_point); + } } else if ("linear_restitution" == var_name) { axis_data[axis].linear_restitution = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution); + } } else if ("linear_damping" == var_name) { axis_data[axis].linear_damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping); + } } else if ("angular_limit_enabled" == var_name) { axis_data[axis].angular_limit_enabled = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled); + } } else if ("angular_limit_upper" == var_name) { axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper); + } } else if ("angular_limit_lower" == var_name) { axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value)); - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower); + } } else if ("angular_limit_softness" == var_name) { axis_data[axis].angular_limit_softness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness); + } } else if ("angular_restitution" == var_name) { axis_data[axis].angular_restitution = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution); + } } else if ("angular_damping" == var_name) { axis_data[axis].angular_damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping); + } } else if ("erp" == var_name) { axis_data[axis].erp = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp); + } } else if ("angular_spring_enabled" == var_name) { axis_data[axis].angular_spring_enabled = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, axis_data[axis].angular_spring_enabled); + } } else if ("angular_spring_stiffness" == var_name) { axis_data[axis].angular_spring_stiffness = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, axis_data[axis].angular_spring_stiffness); + } } else if ("angular_spring_damping" == var_name) { axis_data[axis].angular_spring_damping = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, axis_data[axis].angular_spring_damping); + } } else if ("angular_equilibrium_point" == var_name) { axis_data[axis].angular_equilibrium_point = p_value; - if (j.is_valid()) + if (j.is_valid()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].angular_equilibrium_point); + } } else { return false; @@ -1913,6 +2029,10 @@ bool PhysicalBone3D::SixDOFJointData::_get(const StringName &p_name, Variant &r_ String path = p_name; + if (!path.begins_with("joint_constraints/")) { + return false; + } + int axis; { const String axis_s = path.get_slicec('/', 1); @@ -2012,10 +2132,9 @@ bool PhysicalBone3D::_set(const StringName &p_name, const Variant &p_value) { } if (joint_data) { - if (joint_data->_set(p_name, p_value)) { + if (joint_data->_set(p_name, p_value, joint)) { #ifdef TOOLS_ENABLED - if (get_gizmo().is_valid()) - get_gizmo()->redraw(); + update_gizmos(); #endif return true; } @@ -2038,21 +2157,19 @@ bool PhysicalBone3D::_get(const StringName &p_name, Variant &r_ret) const { } void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const { - Skeleton3D *parent = find_skeleton_parent(get_parent()); if (parent) { - String names; for (int i = 0; i < parent->get_bone_count(); i++) { - if (i > 0) + if (i > 0) { names += ","; + } names += parent->get_bone_name(i); } p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name", PROPERTY_HINT_ENUM, names)); } else { - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name")); } @@ -2068,52 +2185,48 @@ void PhysicalBone3D::_notification(int p_what) { update_bone_id(); reset_to_rest_position(); reset_physics_simulation_state(); - if (!joint.is_valid() && joint_data) { + if (joint_data) { _reload_joint(); } break; - case NOTIFICATION_EXIT_TREE: + + case NOTIFICATION_EXIT_TREE: { if (parent_skeleton) { if (-1 != bone_id) { parent_skeleton->unbind_physical_bone_from_bone(bone_id); + bone_id = -1; } } parent_skeleton = nullptr; - if (joint.is_valid()) { - PhysicsServer3D::get_singleton()->free(joint); - joint = RID(); - } - break; - case NOTIFICATION_TRANSFORM_CHANGED: - if (Engine::get_singleton()->is_editor_hint()) { + PhysicsServer3D::get_singleton()->joint_clear(joint); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { update_offset(); } - break; + } break; } } -void PhysicalBone3D::_direct_state_changed(Object *p_state) { +void PhysicalBone3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) { + PhysicalBone3D *bone = (PhysicalBone3D *)p_instance; + bone->_body_state_changed(p_state); +} +void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { if (!simulate_physics || !_internal_simulate_physics) { return; } - /// Update bone transform + /// Update bone transform. - PhysicsDirectBodyState3D *state; - -#ifdef DEBUG_ENABLED - state = Object::cast_to<PhysicsDirectBodyState3D>(p_state); -#else - state = (PhysicsDirectBodyState3D *)p_state; //trust it -#endif - - Transform global_transform(state->get_transform()); + Transform3D global_transform(p_state->get_transform()); set_ignore_transform_notification(true); set_global_transform(global_transform); set_ignore_transform_notification(false); + _on_transform_changed(); // Update skeleton if (parent_skeleton) { @@ -2125,9 +2238,7 @@ void PhysicalBone3D::_direct_state_changed(Object *p_state) { void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse); - ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &PhysicalBone3D::apply_impulse); - - ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone3D::_direct_state_changed); + ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3()); ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type); ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type); @@ -2136,8 +2247,6 @@ void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone3D::get_joint_offset); ClassDB::bind_method(D_METHOD("set_joint_rotation", "euler"), &PhysicalBone3D::set_joint_rotation); ClassDB::bind_method(D_METHOD("get_joint_rotation"), &PhysicalBone3D::get_joint_rotation); - ClassDB::bind_method(D_METHOD("set_joint_rotation_degrees", "euler_degrees"), &PhysicalBone3D::set_joint_rotation_degrees); - ClassDB::bind_method(D_METHOD("get_joint_rotation_degrees"), &PhysicalBone3D::get_joint_rotation_degrees); ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone3D::set_body_offset); ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone3D::get_body_offset); @@ -2151,9 +2260,6 @@ void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone3D::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone3D::get_mass); - ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone3D::set_weight); - ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone3D::get_weight); - ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone3D::set_friction); ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone3D::get_friction); @@ -2172,19 +2278,14 @@ void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep); - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicalBone3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicalBone3D::get_axis_lock); - ADD_GROUP("Joint", "joint_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_joint_rotation_degrees", "get_joint_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_NONE, "", 0), "set_joint_rotation", "get_joint_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset"), "set_joint_offset", "get_joint_offset"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_lesser,or_greater,radians"), "set_joint_rotation", "get_joint_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset"), "set_body_offset", "get_body_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); @@ -2192,14 +2293,6 @@ void PhysicalBone3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); - BIND_ENUM_CONSTANT(JOINT_TYPE_NONE); BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); BIND_ENUM_CONSTANT(JOINT_TYPE_CONE); @@ -2224,8 +2317,7 @@ void PhysicalBone3D::_update_joint_offset() { set_ignore_transform_notification(false); #ifdef TOOLS_ENABLED - if (get_gizmo().is_valid()) - get_gizmo()->redraw(); + update_gizmos(); #endif } @@ -2237,29 +2329,24 @@ void PhysicalBone3D::_fix_joint_offset() { } void PhysicalBone3D::_reload_joint() { - - if (joint.is_valid()) { - PhysicsServer3D::get_singleton()->free(joint); - joint = RID(); - } - if (!parent_skeleton) { + PhysicsServer3D::get_singleton()->joint_clear(joint); return; } PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id); if (!body_a) { + PhysicsServer3D::get_singleton()->joint_clear(joint); return; } - Transform joint_transf = get_global_transform() * joint_offset; - Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf; + Transform3D joint_transf = get_global_transform() * joint_offset; + Transform3D local_a = body_a->get_global_transform().affine_inverse() * joint_transf; local_a.orthonormalize(); switch (get_joint_type()) { case JOINT_TYPE_PIN: { - - joint = PhysicsServer3D::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); + PhysicsServer3D::get_singleton()->joint_make_pin(joint, body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); const PinJointData *pjd(static_cast<const PinJointData *>(joint_data)); PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_BIAS, pjd->bias); PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_DAMPING, pjd->damping); @@ -2267,8 +2354,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_CONE: { - - joint = PhysicsServer3D::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_cone_twist(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data)); PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span); PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span); @@ -2278,8 +2364,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_HINGE: { - - joint = PhysicsServer3D::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_hinge(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data)); PhysicsServer3D::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled); PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper); @@ -2290,8 +2375,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_SLIDER: { - - joint = PhysicsServer3D::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_slider(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data)); PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper); PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower); @@ -2306,8 +2390,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_6DOF: { - - joint = PhysicsServer3D::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_generic_6dof(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data)); for (int axis = 0; axis < 3; ++axis) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled); @@ -2351,11 +2434,11 @@ void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) { } #ifdef TOOLS_ENABLED -Transform PhysicalBone3D::get_global_gizmo_transform() const { +Transform3D PhysicalBone3D::get_global_gizmo_transform() const { return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform(); } -Transform PhysicalBone3D::get_local_gizmo_transform() const { +Transform3D PhysicalBone3D::get_local_gizmo_transform() const { return gizmo_move_joint ? get_transform() * joint_offset : get_transform(); } #endif @@ -2369,12 +2452,13 @@ Skeleton3D *PhysicalBone3D::find_skeleton_parent() { } void PhysicalBone3D::set_joint_type(JointType p_joint_type) { - - if (p_joint_type == get_joint_type()) + if (p_joint_type == get_joint_type()) { return; + } - if (joint_data) + if (joint_data) { memdelete(joint_data); + } joint_data = nullptr; switch (p_joint_type) { case JOINT_TYPE_PIN: @@ -2399,9 +2483,8 @@ void PhysicalBone3D::set_joint_type(JointType p_joint_type) { _reload_joint(); #ifdef TOOLS_ENABLED - _change_notify(); - if (get_gizmo().is_valid()) - get_gizmo()->redraw(); + notify_property_list_changed(); + update_gizmos(); #endif } @@ -2409,14 +2492,13 @@ PhysicalBone3D::JointType PhysicalBone3D::get_joint_type() const { return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE; } -void PhysicalBone3D::set_joint_offset(const Transform &p_offset) { +void PhysicalBone3D::set_joint_offset(const Transform3D &p_offset) { joint_offset = p_offset; _update_joint_offset(); - _change_notify("joint_rotation_degrees"); } -const Transform &PhysicalBone3D::get_joint_offset() const { +const Transform3D &PhysicalBone3D::get_joint_offset() const { return joint_offset; } @@ -2424,26 +2506,17 @@ void PhysicalBone3D::set_joint_rotation(const Vector3 &p_euler_rad) { joint_offset.basis.set_euler_scale(p_euler_rad, joint_offset.basis.get_scale()); _update_joint_offset(); - _change_notify("joint_offset"); } Vector3 PhysicalBone3D::get_joint_rotation() const { return joint_offset.basis.get_rotation(); } -void PhysicalBone3D::set_joint_rotation_degrees(const Vector3 &p_euler_deg) { - set_joint_rotation(p_euler_deg * Math_PI / 180.0); -} - -Vector3 PhysicalBone3D::get_joint_rotation_degrees() const { - return get_joint_rotation() * 180.0 / Math_PI; -} - -const Transform &PhysicalBone3D::get_body_offset() const { +const Transform3D &PhysicalBone3D::get_body_offset() const { return body_offset; } -void PhysicalBone3D::set_body_offset(const Transform &p_offset) { +void PhysicalBone3D::set_body_offset(const Transform3D &p_offset) { body_offset = p_offset; body_offset_inverse = body_offset.affine_inverse(); @@ -2468,7 +2541,6 @@ bool PhysicalBone3D::is_simulating_physics() { } void PhysicalBone3D::set_bone_name(const String &p_name) { - bone_name = p_name; bone_id = -1; @@ -2477,34 +2549,20 @@ void PhysicalBone3D::set_bone_name(const String &p_name) { } const String &PhysicalBone3D::get_bone_name() const { - return bone_name; } void PhysicalBone3D::set_mass(real_t p_mass) { - ERR_FAIL_COND(p_mass <= 0); mass = p_mass; PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass); } real_t PhysicalBone3D::get_mass() const { - return mass; } -void PhysicalBone3D::set_weight(real_t p_weight) { - - set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8))); -} - -real_t PhysicalBone3D::get_weight() const { - - return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)); -} - void PhysicalBone3D::set_friction(real_t p_friction) { - ERR_FAIL_COND(p_friction < 0 || p_friction > 1); friction = p_friction; @@ -2512,12 +2570,10 @@ void PhysicalBone3D::set_friction(real_t p_friction) { } real_t PhysicalBone3D::get_friction() const { - return friction; } void PhysicalBone3D::set_bounce(real_t p_bounce) { - ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); bounce = p_bounce; @@ -2525,18 +2581,15 @@ void PhysicalBone3D::set_bounce(real_t p_bounce) { } real_t PhysicalBone3D::get_bounce() const { - return bounce; } void PhysicalBone3D::set_gravity_scale(real_t p_gravity_scale) { - gravity_scale = p_gravity_scale; PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); } real_t PhysicalBone3D::get_gravity_scale() const { - return gravity_scale; } @@ -2569,39 +2622,17 @@ bool PhysicalBone3D::is_able_to_sleep() const { return can_sleep; } -void PhysicalBone3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); -} - -bool PhysicalBone3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); -} - PhysicalBone3D::PhysicalBone3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC), -#ifdef TOOLS_ENABLED - gizmo_move_joint(false), -#endif - joint_data(nullptr), - parent_skeleton(nullptr), - simulate_physics(false), - _internal_simulate_physics(false), - bone_id(-1), - bone_name(""), - bounce(0), - mass(1), - friction(1), - gravity_scale(1), - linear_damp(-1), - angular_damp(-1), - can_sleep(true) { - + PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { + joint = PhysicsServer3D::get_singleton()->joint_create(); reset_physics_simulation_state(); } PhysicalBone3D::~PhysicalBone3D() { - if (joint_data) + if (joint_data) { memdelete(joint_data); + } + PhysicsServer3D::get_singleton()->free(joint); } void PhysicalBone3D::update_bone_id() { @@ -2615,7 +2646,6 @@ void PhysicalBone3D::update_bone_id() { if (-1 != bone_id) { // Assert the unbind from old node parent_skeleton->unbind_physical_bone_from_bone(bone_id); - parent_skeleton->unbind_child_node_from_bone(bone_id, this); } bone_id = new_bone_id; @@ -2630,10 +2660,10 @@ void PhysicalBone3D::update_bone_id() { void PhysicalBone3D::update_offset() { #ifdef TOOLS_ENABLED if (parent_skeleton) { - - Transform bone_transform(parent_skeleton->get_global_transform()); - if (-1 != bone_id) + Transform3D bone_transform(parent_skeleton->get_global_transform()); + if (-1 != bone_id) { bone_transform *= parent_skeleton->get_bone_global_pose(bone_id); + } if (gizmo_move_joint) { bone_transform *= body_offset; @@ -2650,11 +2680,11 @@ void PhysicalBone3D::_start_physics_simulation() { return; } reset_to_rest_position(); - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID); + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); - PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); - set_as_toplevel(true); + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); + set_as_top_level(true); _internal_simulate_physics = true; } @@ -2663,18 +2693,18 @@ void PhysicalBone3D::_stop_physics_simulation() { return; } if (parent_skeleton->get_animate_physical_bones()) { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); } else { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); } if (_internal_simulate_physics) { - PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, ""); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); - set_as_toplevel(false); + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false); + set_as_top_level(false); _internal_simulate_physics = false; } } |