diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index 7c4c75bf0fc..e96124c9eb0 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -266,6 +266,9 @@
The physics layers this CollisionObject2D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
[b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+
+ Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes.
+
If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set.
@@ -294,5 +297,16 @@
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [CollisionObject2D].
+ Automatically re-added to the physics simulation when the [Node] is processed again.
+
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody2D] can't be affected by forces or other bodies while static.
+ Automatically set [PhysicsBody2D] back to its original mode when the [Node] is processed again.
+
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation.
+
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 4ab37f5c7b0..dfd1e85e561 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -230,6 +230,9 @@
The physics layers this CollisionObject3D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
[b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+
+ Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes.
+
If [code]true[/code], the [CollisionObject3D] will continue to receive input events as the mouse is dragged across its shapes.
@@ -265,5 +268,16 @@
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [CollisionObject3D].
+ Automatically re-added to the physics simulation when the [Node] is processed again.
+
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody3D] can't be affected by forces or other bodies while static.
+ Automatically set [PhysicsBody3D] back to its original mode when the [Node] is processed again.
+
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation.
+
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index a9c38e4d068..7a9cb702e3b 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -894,6 +894,12 @@
Notification received when the node is ready, just before [constant NOTIFICATION_READY] is received. Unlike the latter, it's sent every time the node enters tree, instead of only once.
+
+ Notification received when the node is disabled. See [constant PROCESS_MODE_DISABLED].
+
+
+ Notification received when the node is enabled again after being disabled. See [constant PROCESS_MODE_DISABLED].
+
Notification received right before the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects.
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index 7999ad774d7..b143c60d9d9 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -93,6 +93,9 @@
+
+ Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes.
+
@@ -113,5 +116,12 @@
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [SoftBody3D].
+ Automatically re-added to the physics simulation when the [Node] is processed again.
+
+
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation.
+
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index a633923be73..93d154bb010 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -31,7 +31,6 @@
#include "collision_object_2d.h"
#include "scene/scene_string_names.h"
-#include "servers/physics_server_2d.h"
void CollisionObject2D::_notification(int p_what) {
switch (p_what) {
@@ -44,16 +43,22 @@ void CollisionObject2D::_notification(int p_what) {
PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
}
- RID space = get_world_2d()->get_space();
- if (area) {
- PhysicsServer2D::get_singleton()->area_set_space(rid, space);
- } else {
- PhysicsServer2D::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_2d()->get_space();
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, space);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, space);
+ }
}
_update_pickable();
-
- //get space
} break;
case NOTIFICATION_ENTER_CANVAS: {
@@ -67,6 +72,7 @@ void CollisionObject2D::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
} break;
+
case NOTIFICATION_TRANSFORM_CHANGED: {
if (only_update_transform_changes) {
return;
@@ -79,15 +85,22 @@ void CollisionObject2D::_notification(int p_what) {
} else {
PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
}
-
} break;
+
case NOTIFICATION_EXIT_TREE: {
- if (area) {
- PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
- } else {
- PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ bool disabled = !is_enabled();
+
+ if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ }
}
+ if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) {
+ _apply_enabled();
+ }
} break;
case NOTIFICATION_EXIT_CANVAS: {
@@ -97,6 +110,14 @@ void CollisionObject2D::_notification(int p_what) {
PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID());
}
} break;
+
+ case NOTIFICATION_DISABLED: {
+ _apply_disabled();
+ } break;
+
+ case NOTIFICATION_ENABLED: {
+ _apply_enabled();
+ } break;
}
}
@@ -158,6 +179,79 @@ bool CollisionObject2D::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit);
}
+void CollisionObject2D::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();
+ }
+}
+
+CollisionObject2D::DisableMode CollisionObject2D::get_disable_mode() const {
+ return disable_mode;
+}
+
+void CollisionObject2D::_apply_disabled() {
+ switch (disable_mode) {
+ case DISABLE_MODE_REMOVE: {
+ if (is_inside_tree()) {
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ }
+ }
+ } break;
+
+ case DISABLE_MODE_MAKE_STATIC: {
+ if (!area && (body_mode != PhysicsServer2D::BODY_MODE_STATIC)) {
+ PhysicsServer2D::get_singleton()->body_set_mode(rid, PhysicsServer2D::BODY_MODE_STATIC);
+ }
+ } break;
+
+ case DISABLE_MODE_KEEP_ACTIVE: {
+ // Nothing to do.
+ } break;
+ }
+}
+
+void CollisionObject2D::_apply_enabled() {
+ switch (disable_mode) {
+ case DISABLE_MODE_REMOVE: {
+ if (is_inside_tree()) {
+ RID space = get_world_2d()->get_space();
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, space);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, space);
+ }
+ }
+ } break;
+
+ case DISABLE_MODE_MAKE_STATIC: {
+ if (!area && (body_mode != PhysicsServer2D::BODY_MODE_STATIC)) {
+ PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode);
+ }
+ } break;
+
+ case DISABLE_MODE_KEEP_ACTIVE: {
+ // Nothing to do.
+ } break;
+ }
+}
+
uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
ShapeData sd;
uint32_t id;
@@ -412,6 +506,22 @@ bool CollisionObject2D::is_only_update_transform_changes_enabled() const {
return only_update_transform_changes;
}
+void CollisionObject2D::set_body_mode(PhysicsServer2D::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;
+ }
+
+ PhysicsServer2D::get_singleton()->body_set_mode(rid, p_mode);
+}
+
void CollisionObject2D::_update_pickable() {
if (!is_inside_tree()) {
return;
@@ -445,6 +555,8 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject2D::get_collision_layer_bit);
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject2D::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject2D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode);
+ ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable);
ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject2D::create_shape_owner);
@@ -473,12 +585,18 @@ void CollisionObject2D::_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_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable");
+
+ BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE);
+ BIND_ENUM_CONSTANT(DISABLE_MODE_MAKE_STATIC);
+ BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
@@ -493,6 +611,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
PhysicsServer2D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
} else {
PhysicsServer2D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
+ PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode);
}
}
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index e10f3097d96..7a71affbb56 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -33,10 +33,19 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h"
+#include "servers/physics_server_2d.h"
class CollisionObject2D : public Node2D {
GDCLASS(CollisionObject2D, Node2D);
+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 CollisionObject2D : public Node2D {
RID rid;
bool pickable = false;
+ DisableMode disable_mode = DISABLE_MODE_REMOVE;
+
+ PhysicsServer2D::BodyMode body_mode = PhysicsServer2D::BODY_MODE_STATIC;
+
struct ShapeData {
Object *owner = nullptr;
Transform2D xform;
@@ -64,6 +77,9 @@ class CollisionObject2D : public Node2D {
Map shapes;
bool only_update_transform_changes = false; //this is used for sync physics in CharacterBody2D
+ void _apply_disabled();
+ void _apply_enabled();
+
protected:
CollisionObject2D(RID p_rid, bool p_area);
@@ -79,6 +95,8 @@ protected:
void set_only_update_transform_changes(bool p_enable);
bool is_only_update_transform_changes_enabled() const;
+ void set_body_mode(PhysicsServer2D::BodyMode p_mode);
+
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
@@ -92,6 +110,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 *r_owners);
@@ -131,4 +152,6 @@ public:
~CollisionObject2D();
};
+VARIANT_ENUM_CAST(CollisionObject2D::DisableMode);
+
#endif // COLLISION_OBJECT_2D_H
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
index 0c1be16174b..d547914e16a 100644
--- a/scene/2d/physical_bone_2d.cpp
+++ b/scene/2d/physical_bone_2d.cpp
@@ -31,33 +31,37 @@
#include "physical_bone_2d.h"
void PhysicalBone2D::_notification(int p_what) {
- if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
- // Position the RigidBody in the correct position
- if (follow_bone_when_simulating) {
- _position_at_bone2d();
- }
+ switch (p_what) {
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ // Position the RigidBody in the correct position.
+ if (follow_bone_when_simulating) {
+ _position_at_bone2d();
+ }
- // Keep the child joint in the correct position.
- if (child_joint && auto_configure_joint) {
- child_joint->set_global_position(get_global_position());
- }
- } else if (p_what == NOTIFICATION_READY) {
- _find_skeleton_parent();
- _find_joint_child();
+ // Keep the child joint in the correct position.
+ if (child_joint && auto_configure_joint) {
+ child_joint->set_global_position(get_global_position());
+ }
+ } break;
- // Configure joint
- if (child_joint && auto_configure_joint) {
- _auto_configure_joint();
- }
+ case NOTIFICATION_READY: {
+ _find_skeleton_parent();
+ _find_joint_child();
- // Simulate physics if set
- if (simulate_physics) {
- _start_physics_simulation();
- } else {
- _stop_physics_simulation();
- }
+ // Configure joint.
+ if (child_joint && auto_configure_joint) {
+ _auto_configure_joint();
+ }
- set_physics_process_internal(true);
+ // Simulate physics if set.
+ if (simulate_physics) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
+
+ set_physics_process_internal(true);
+ } break;
}
}
@@ -156,16 +160,16 @@ void PhysicalBone2D::_start_physics_simulation() {
// Apply the correct mode
RigidBody2D::Mode rigid_mode = get_mode();
if (rigid_mode == RigidBody2D::MODE_STATIC) {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
} else if (rigid_mode == RigidBody2D::MODE_DYNAMIC) {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
} else if (rigid_mode == RigidBody2D::MODE_KINEMATIC) {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_KINEMATIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
} else if (rigid_mode == RigidBody2D::MODE_DYNAMIC_LOCKED) {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC_LOCKED);
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED);
} else {
- // Default to Rigid
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC);
+ // Default to Dynamic.
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
}
_internal_simulate_physics = true;
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index ce63b25ce07..8801033ee68 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -49,7 +49,7 @@ void PhysicsBody2D::_bind_methods() {
PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), p_mode);
+ set_body_mode(p_mode);
set_pickable(false);
}
@@ -186,9 +186,9 @@ void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) {
kinematic_motion = p_enabled;
if (kinematic_motion) {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
} else {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
}
_update_kinematic_motion();
@@ -199,28 +199,30 @@ bool StaticBody2D::is_kinematic_motion_enabled() const {
}
void StaticBody2D::_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();
- Transform2D new_transform = get_global_transform();
+ Transform2D new_transform = get_global_transform();
- new_transform.translate(constant_linear_velocity * delta_time);
- new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
+ new_transform.translate(constant_linear_velocity * delta_time);
+ new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
- // Propagate transform change to node.
- set_block_transform_notify(true);
- set_global_transform(new_transform);
- set_block_transform_notify(false);
+ // Propagate transform change to node.
+ set_block_transform_notify(true);
+ set_global_transform(new_transform);
+ set_block_transform_notify(false);
+ } break;
}
}
@@ -495,18 +497,18 @@ void RigidBody2D::set_mode(Mode p_mode) {
mode = p_mode;
switch (p_mode) {
case MODE_DYNAMIC: {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_DYNAMIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
} break;
case MODE_STATIC: {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
} break;
case MODE_KINEMATIC: {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
} break;
case MODE_DYNAMIC_LOCKED: {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED);
+ set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED);
} break;
}
@@ -762,18 +764,19 @@ bool RigidBody2D::is_contact_monitor_enabled() const {
void RigidBody2D::_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
}
@@ -1232,26 +1235,28 @@ void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) {
}
void CharacterBody2D::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- last_valid_transform = get_global_transform();
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ last_valid_transform = get_global_transform();
- // Reset move_and_slide() data.
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
- motion_results.clear();
- floor_velocity = Vector2();
- }
+ // Reset move_and_slide() data.
+ on_floor = false;
+ on_floor_body = RID();
+ on_ceiling = false;
+ on_wall = false;
+ motion_results.clear();
+ floor_velocity = Vector2();
+ } break;
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- //used by sync to physics, send the new transform to the physics
- Transform2D new_transform = get_global_transform();
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::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);
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ // Used by sync to physics, send the new transform to the physics.
+ Transform2D new_transform = get_global_transform();
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::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);
+ } break;
}
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index a04667e53bd..40e3f7c7644 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 &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 50a9b4fcd06..a3a890db759 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 *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 28a0c72fe36..2bbb89d389c 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() {
@@ -200,9 +200,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();
@@ -249,35 +249,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;
}
}
@@ -565,18 +567,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
}
@@ -584,18 +587,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();
@@ -1233,14 +1234,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;
}
}
@@ -2095,7 +2098,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);
@@ -2105,12 +2109,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;
}
}
@@ -2605,7 +2610,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));
@@ -2618,11 +2623,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 df5474d03e8..8b0803addc5 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;
- }
+
+ case NOTIFICATION_DISABLED: {
+ if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
+ prepare_physics_server();
+ }
+ } break;
+
+ case NOTIFICATION_ENABLED: {
+ if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
+ prepare_physics_server();
+ }
+ } break;
#ifdef TOOLS_ENABLED
-
- 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
+ }
}
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 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 0d0d39d48f4..81aa0c10c6c 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 0d88769b704..b0e37b81a5f 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(get_parent());
- if (!cb) {
- return;
- }
- body = cb;
- local_xform = get_transform();
- cb->wheels.push_back(this);
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ VehicleBody3D *cb = Object::cast_to(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(get_parent());
- if (!cb) {
- return;
- }
- cb->wheels.erase(this);
- body = nullptr;
+ 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(get_parent());
+ if (!cb) {
+ return;
+ }
+ cb->wheels.erase(this);
+ body = nullptr;
+ } break;
}
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e1abea81ef9..4685f6d1dce 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -402,6 +402,7 @@ void Node::set_process_mode(ProcessMode p_mode) {
}
bool prev_can_process = can_process();
+ bool prev_enabled = _is_enabled();
data.process_mode = p_mode;
@@ -416,6 +417,7 @@ void Node::set_process_mode(ProcessMode p_mode) {
}
bool next_can_process = can_process();
+ bool next_enabled = _is_enabled();
int pause_notification = 0;
@@ -425,7 +427,16 @@ void Node::set_process_mode(ProcessMode p_mode) {
pause_notification = NOTIFICATION_UNPAUSED;
}
- _propagate_process_owner(data.process_owner, pause_notification);
+ int enabled_notification = 0;
+
+ if (prev_enabled && !next_enabled) {
+ enabled_notification = NOTIFICATION_DISABLED;
+ } else if (!prev_enabled && next_enabled) {
+ enabled_notification = NOTIFICATION_ENABLED;
+ }
+
+ _propagate_process_owner(data.process_owner, pause_notification, enabled_notification);
+
#ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes
// It's very expensive during runtime to change, so editor-only
@@ -454,17 +465,21 @@ Node::ProcessMode Node::get_process_mode() const {
return data.process_mode;
}
-void Node::_propagate_process_owner(Node *p_owner, int p_notification) {
+void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification) {
data.process_owner = p_owner;
- if (p_notification != 0) {
- notification(p_notification);
+ if (p_pause_notification != 0) {
+ notification(p_pause_notification);
+ }
+
+ if (p_enabled_notification != 0) {
+ notification(p_enabled_notification);
}
for (int i = 0; i < data.children.size(); i++) {
Node *c = data.children[i];
if (c->data.process_mode == PROCESS_MODE_INHERIT) {
- c->_propagate_process_owner(p_owner, p_notification);
+ c->_propagate_process_owner(p_owner, p_pause_notification, p_enabled_notification);
}
}
}
@@ -668,6 +683,27 @@ bool Node::_can_process(bool p_paused) const {
}
}
+bool Node::_is_enabled() const {
+ ProcessMode process_mode;
+
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
+ if (!data.process_owner) {
+ process_mode = PROCESS_MODE_PAUSABLE;
+ } else {
+ process_mode = data.process_owner->data.process_mode;
+ }
+ } else {
+ process_mode = data.process_mode;
+ }
+
+ return (process_mode != PROCESS_MODE_DISABLED);
+}
+
+bool Node::is_enabled() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+ return _is_enabled();
+}
+
float Node::get_physics_process_delta_time() const {
if (data.tree) {
return data.tree->get_physics_process_time();
@@ -2619,6 +2655,8 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
+ BIND_CONSTANT(NOTIFICATION_DISABLED);
+ BIND_CONSTANT(NOTIFICATION_ENABLED);
BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE);
BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE);
diff --git a/scene/main/node.h b/scene/main/node.h
index e7b36f351bf..3d4c3fd434f 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -163,7 +163,7 @@ private:
void _propagate_after_exit_tree();
void _propagate_validate_owner();
void _print_stray_nodes();
- void _propagate_process_owner(Node *p_owner, int p_notification);
+ void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification);
Array _get_node_and_resource(const NodePath &p_path);
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
@@ -181,6 +181,7 @@ private:
void _propagate_pause_notification(bool p_enable);
_FORCE_INLINE_ bool _can_process(bool p_paused) const;
+ _FORCE_INLINE_ bool _is_enabled() const;
protected:
void _block() { data.blocked++; }
@@ -224,6 +225,8 @@ public:
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27,
+ NOTIFICATION_DISABLED = 28,
+ NOTIFICATION_ENABLED = 29,
//keep these linked to node
NOTIFICATION_WM_MOUSE_ENTER = 1002,
@@ -380,6 +383,7 @@ public:
ProcessMode get_process_mode() const;
bool can_process() const;
bool can_process_notification(int p_what) const;
+ bool is_enabled() const;
void request_ready();