diff options
author | Rémi Verschelde <remi@verschelde.fr> | 2021-06-30 20:36:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-30 20:36:36 +0200 |
commit | 915344fe76af8d8d62ef6f614dd7a64aa68468e3 (patch) | |
tree | b610d49b954cce97413b339efd50215b9fbe4176 /scene/3d | |
parent | 270f9d4c88c43895ae6d6a4ff8247f77f811beda (diff) | |
parent | 5cbdc7a0acbefcc3aa3cb0eb0fe05b5b10fe7370 (diff) |
Merge pull request #49834 from nekomatata/physics-disable-modes
Add support for controlling physics nodes' behavior when disabled
Diffstat (limited to 'scene/3d')
-rw-r--r-- | scene/3d/collision_object_3d.cpp | 146 | ||||
-rw-r--r-- | scene/3d/collision_object_3d.h | 23 | ||||
-rw-r--r-- | scene/3d/physics_body_3d.cpp | 115 | ||||
-rw-r--r-- | scene/3d/soft_body_3d.cpp | 66 | ||||
-rw-r--r-- | scene/3d/soft_body_3d.h | 12 | ||||
-rw-r--r-- | scene/3d/vehicle_body_3d.cpp | 43 |
6 files changed, 304 insertions, 101 deletions
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index a04667e53b..40e3f7c764 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -32,7 +32,6 @@ #include "core/config/engine.h" #include "scene/scene_string_names.h" -#include "servers/physics_server_3d.h" void CollisionObject3D::_notification(int p_what) { switch (p_what) { @@ -59,15 +58,22 @@ void CollisionObject3D::_notification(int p_what) { PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); } - RID space = get_world_3d()->get_space(); - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, space); - } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, space); + bool disabled = !is_enabled(); + + if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { + _apply_disabled(); + } + + if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { + RID space = get_world_3d()->get_space(); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, space); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, space); + } } _update_pickable(); - //get space } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -78,19 +84,34 @@ void CollisionObject3D::_notification(int p_what) { } _on_transform_changed(); - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); - } break; + case NOTIFICATION_EXIT_WORLD: { - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); - } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + bool disabled = !is_enabled(); + + if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } + } + + if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { + _apply_enabled(); } + } break; + case NOTIFICATION_DISABLED: { + _apply_disabled(); + } break; + + case NOTIFICATION_ENABLED: { + _apply_enabled(); } break; } } @@ -153,6 +174,79 @@ bool CollisionObject3D::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } +void CollisionObject3D::set_disable_mode(DisableMode p_mode) { + if (disable_mode == p_mode) { + return; + } + + bool disabled = is_inside_tree() && !is_enabled(); + + if (disabled) { + // Cancel previous disable mode. + _apply_enabled(); + } + + disable_mode = p_mode; + + if (disabled) { + // Apply new disable mode. + _apply_disabled(); + } +} + +CollisionObject3D::DisableMode CollisionObject3D::get_disable_mode() const { + return disable_mode; +} + +void CollisionObject3D::_apply_disabled() { + switch (disable_mode) { + case DISABLE_MODE_REMOVE: { + if (is_inside_tree()) { + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } + } + } break; + + case DISABLE_MODE_MAKE_STATIC: { + if (!area && (body_mode != PhysicsServer3D::BODY_MODE_STATIC)) { + PhysicsServer3D::get_singleton()->body_set_mode(rid, PhysicsServer3D::BODY_MODE_STATIC); + } + } break; + + case DISABLE_MODE_KEEP_ACTIVE: { + // Nothing to do. + } break; + } +} + +void CollisionObject3D::_apply_enabled() { + switch (disable_mode) { + case DISABLE_MODE_REMOVE: { + if (is_inside_tree()) { + RID space = get_world_3d()->get_space(); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, space); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, space); + } + } + } break; + + case DISABLE_MODE_MAKE_STATIC: { + if (!area && (body_mode != PhysicsServer3D::BODY_MODE_STATIC)) { + PhysicsServer3D::get_singleton()->body_set_mode(rid, body_mode); + } + } break; + + case DISABLE_MODE_KEEP_ACTIVE: { + // Nothing to do. + } break; + } +} + void CollisionObject3D::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { if (get_script_instance()) { get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape); @@ -174,6 +268,22 @@ void CollisionObject3D::_mouse_exit() { emit_signal(SceneStringNames::get_singleton()->mouse_exited); } +void CollisionObject3D::set_body_mode(PhysicsServer3D::BodyMode p_mode) { + ERR_FAIL_COND(area); + + if (body_mode == p_mode) { + return; + } + + body_mode = p_mode; + + if (is_inside_tree() && !is_enabled() && (disable_mode == DISABLE_MODE_MAKE_STATIC)) { + return; + } + + PhysicsServer3D::get_singleton()->body_set_mode(rid, p_mode); +} + void CollisionObject3D::_update_pickable() { if (!is_inside_tree()) { return; @@ -305,6 +415,8 @@ void CollisionObject3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject3D::get_collision_layer_bit); ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject3D::set_collision_mask_bit); ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject3D::get_collision_mask_bit); + ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode); + ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode); ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable); ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject3D::is_ray_pickable); ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject3D::set_capture_input_on_drag); @@ -332,6 +444,8 @@ void CollisionObject3D::_bind_methods() { ADD_SIGNAL(MethodInfo("mouse_entered")); ADD_SIGNAL(MethodInfo("mouse_exited")); + ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,MakeStatic,KeepActive"), "set_disable_mode", "get_disable_mode"); + 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"); @@ -339,6 +453,10 @@ void CollisionObject3D::_bind_methods() { ADD_GROUP("Input", "input_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_capture_on_drag"), "set_capture_input_on_drag", "get_capture_input_on_drag"); + + BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE); + BIND_ENUM_CONSTANT(DISABLE_MODE_MAKE_STATIC); + BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); } uint32_t CollisionObject3D::create_shape_owner(Object *p_owner) { @@ -540,8 +658,8 @@ CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) { PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id()); } else { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id()); + PhysicsServer3D::get_singleton()->body_set_mode(rid, body_mode); } - //set_transform_notify(true); } void CollisionObject3D::set_capture_input_on_drag(bool p_capture) { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 50a9b4fcd0..a3a890db75 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -33,10 +33,19 @@ #include "scene/3d/node_3d.h" #include "scene/resources/shape_3d.h" +#include "servers/physics_server_3d.h" class CollisionObject3D : public Node3D { GDCLASS(CollisionObject3D, Node3D); +public: + enum DisableMode { + DISABLE_MODE_REMOVE, + DISABLE_MODE_MAKE_STATIC, + DISABLE_MODE_KEEP_ACTIVE, + }; + +private: uint32_t collision_layer = 1; uint32_t collision_mask = 1; @@ -44,6 +53,10 @@ class CollisionObject3D : public Node3D { RID rid; + DisableMode disable_mode = DISABLE_MODE_REMOVE; + + PhysicsServer3D::BodyMode body_mode = PhysicsServer3D::BODY_MODE_STATIC; + struct ShapeData { Object *owner = nullptr; Transform3D xform; @@ -76,6 +89,9 @@ class CollisionObject3D : public Node3D { void _update_debug_shapes(); void _clear_debug_shapes(); + void _apply_disabled(); + void _apply_enabled(); + protected: CollisionObject3D(RID p_rid, bool p_area); @@ -89,6 +105,8 @@ protected: virtual void _mouse_enter(); virtual void _mouse_exit(); + void set_body_mode(PhysicsServer3D::BodyMode p_mode); + public: void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; @@ -102,6 +120,9 @@ public: void set_collision_mask_bit(int p_bit, bool p_value); bool get_collision_mask_bit(int p_bit) const; + void set_disable_mode(DisableMode p_mode); + DisableMode get_disable_mode() const; + uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); @@ -138,4 +159,6 @@ public: ~CollisionObject3D(); }; +VARIANT_ENUM_CAST(CollisionObject3D::DisableMode); + #endif // COLLISION_OBJECT__H diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index cb2a873f62..e7482d35e7 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -65,7 +65,7 @@ void PhysicsBody3D::_bind_methods() { PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode); + set_body_mode(p_mode); } PhysicsBody3D::~PhysicsBody3D() { @@ -233,9 +233,9 @@ void StaticBody3D::set_kinematic_motion_enabled(bool p_enabled) { kinematic_motion = p_enabled; if (kinematic_motion) { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); } else { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); } _update_kinematic_motion(); @@ -282,35 +282,37 @@ Vector3 StaticBody3D::get_angular_velocity() const { } void StaticBody3D::_notification(int p_what) { - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { + switch (p_what) { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } + if (Engine::get_singleton()->is_editor_hint()) { + return; + } #endif - ERR_FAIL_COND(!kinematic_motion); + ERR_FAIL_COND(!kinematic_motion); - real_t delta_time = get_physics_process_delta_time(); + real_t delta_time = get_physics_process_delta_time(); - Transform3D new_transform = get_global_transform(); - new_transform.origin += constant_linear_velocity * delta_time; + Transform3D new_transform = get_global_transform(); + new_transform.origin += constant_linear_velocity * delta_time; - real_t ang_vel = constant_angular_velocity.length(); - if (!Math::is_zero_approx(ang_vel)) { - Vector3 ang_vel_axis = constant_angular_velocity / ang_vel; - Basis rot(ang_vel_axis, ang_vel * delta_time); - new_transform.basis = rot * new_transform.basis; - new_transform.orthonormalize(); - } + real_t ang_vel = constant_angular_velocity.length(); + if (!Math::is_zero_approx(ang_vel)) { + Vector3 ang_vel_axis = constant_angular_velocity / ang_vel; + Basis rot(ang_vel_axis, ang_vel * delta_time); + new_transform.basis = rot * new_transform.basis; + new_transform.orthonormalize(); + } - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); - // Propagate transform change to node. - set_ignore_transform_notification(true); - set_global_transform(new_transform); - set_ignore_transform_notification(false); - _on_transform_changed(); + // Propagate transform change to node. + set_ignore_transform_notification(true); + set_global_transform(new_transform); + set_ignore_transform_notification(false); + _on_transform_changed(); + } break; } } @@ -598,18 +600,19 @@ void RigidBody3D::_direct_state_changed(Object *p_state) { 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_warnings(); - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; } - #endif } @@ -617,18 +620,16 @@ void RigidBody3D::set_mode(Mode p_mode) { mode = p_mode; switch (p_mode) { case MODE_DYNAMIC: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_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_DYNAMIC_LOCKED: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_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_warnings(); @@ -1262,14 +1263,16 @@ void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) { } void CharacterBody3D::_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; - motion_results.clear(); - floor_velocity = Vector3(); + 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; } } @@ -2121,7 +2124,8 @@ void PhysicalBone3D::_notification(int p_what) { _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); @@ -2131,12 +2135,13 @@ void PhysicalBone3D::_notification(int p_what) { } parent_skeleton = nullptr; PhysicsServer3D::get_singleton()->joint_clear(joint); - break; - case NOTIFICATION_TRANSFORM_CHANGED: + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { if (Engine::get_singleton()->is_editor_hint()) { update_offset(); } - break; + } break; } } @@ -2620,7 +2625,7 @@ void PhysicalBone3D::_start_physics_simulation() { return; } reset_to_rest_position(); - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC); + 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(), callable_mp(this, &PhysicalBone3D::_direct_state_changed)); @@ -2633,11 +2638,11 @@ 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); } diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index 324131d400..efd8a2b50c 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -266,12 +266,13 @@ void SoftBody3D::_notification(int p_what) { PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space); prepare_physics_server(); } break; + case NOTIFICATION_READY: { if (!parent_collision_ignore.is_empty()) { add_collision_exception_with(get_node(parent_collision_ignore)); } - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (Engine::get_singleton()->is_editor_hint()) { _reset_points_offsets(); @@ -285,27 +286,36 @@ void SoftBody3D::_notification(int p_what) { set_as_top_level(true); set_transform(Transform3D()); set_notify_transform(true); - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); - } break; + case NOTIFICATION_EXIT_WORLD: { PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID()); - } break; - } -#ifdef TOOLS_ENABLED + case NOTIFICATION_DISABLED: { + if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - } - } + case NOTIFICATION_ENABLED: { + if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } + } break; +#ifdef TOOLS_ENABLED + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; #endif + } } void SoftBody3D::_bind_methods() { @@ -326,6 +336,9 @@ void SoftBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore); ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore); + ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftBody3D::set_disable_mode); + ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftBody3D::get_disable_mode); + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with); @@ -364,6 +377,11 @@ void SoftBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable"); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,KeepActive"), "set_disable_mode", "get_disable_mode"); + + BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE); + BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); } TypedArray<String> SoftBody3D::get_configuration_warnings() const { @@ -421,6 +439,7 @@ void SoftBody3D::_draw_soft_mesh() { } void SoftBody3D::prepare_physics_server() { +#ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { if (get_mesh().is_valid()) { PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); @@ -430,8 +449,9 @@ void SoftBody3D::prepare_physics_server() { return; } +#endif - if (get_mesh().is_valid()) { + if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) { become_mesh_owner(); PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh)); @@ -527,6 +547,28 @@ bool SoftBody3D::get_collision_layer_bit(int p_bit) const { return get_collision_layer() & (1 << p_bit); } +void SoftBody3D::set_disable_mode(DisableMode p_mode) { + if (disable_mode == p_mode) { + return; + } + + bool inside_tree = is_inside_tree(); + + if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } + + disable_mode = p_mode; + + if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } +} + +SoftBody3D::DisableMode SoftBody3D::get_disable_mode() const { + return disable_mode; +} + void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) { parent_collision_ignore = p_parent_collision_ignore; } diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index 0d0d39d48f..81aa0c10c6 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -67,6 +67,11 @@ class SoftBody3D : public MeshInstance3D { GDCLASS(SoftBody3D, MeshInstance3D); public: + enum DisableMode { + DISABLE_MODE_REMOVE, + DISABLE_MODE_KEEP_ACTIVE, + }; + struct PinnedPoint { int point_index = -1; NodePath spatial_attachment_path; @@ -83,6 +88,8 @@ private: RID physics_rid; + DisableMode disable_mode = DISABLE_MODE_REMOVE; + bool mesh_owner = false; uint32_t collision_mask = 1; uint32_t collision_layer = 1; @@ -137,6 +144,9 @@ public: void set_collision_layer_bit(int p_bit, bool p_value); bool get_collision_layer_bit(int p_bit) const; + void set_disable_mode(DisableMode p_mode); + DisableMode get_disable_mode() const; + void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore); const NodePath &get_parent_collision_ignore() const; @@ -192,4 +202,6 @@ private: int _has_pinned_point(int p_point_index) const; }; +VARIANT_ENUM_CAST(SoftBody3D::DisableMode); + #endif // SOFT_PHYSICS_BODY_H diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index 0d88769b70..b0e37b81a5 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -79,26 +79,29 @@ public: }; void VehicleWheel3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); - if (!cb) { - return; - } - body = cb; - local_xform = get_transform(); - cb->wheels.push_back(this); - - m_chassisConnectionPointCS = get_transform().origin; - m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); - m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); - } - if (p_what == NOTIFICATION_EXIT_TREE) { - VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); - if (!cb) { - return; - } - cb->wheels.erase(this); - body = nullptr; + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); + if (!cb) { + return; + } + body = cb; + local_xform = get_transform(); + cb->wheels.push_back(this); + + m_chassisConnectionPointCS = get_transform().origin; + m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); + m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); + } break; + + case NOTIFICATION_EXIT_TREE: { + VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); + if (!cb) { + return; + } + cb->wheels.erase(this); + body = nullptr; + } break; } } |