summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
authorPouleyKetchoupp <pouleyketchoup@gmail.com>2021-06-17 18:09:40 -0700
committerPouleyKetchoupp <pouleyketchoup@gmail.com>2021-06-30 09:20:44 -0700
commit5cbdc7a0acbefcc3aa3cb0eb0fe05b5b10fe7370 (patch)
treeed92cd22587c8e8bf235e5b08b6017b5a5e8ca70 /scene
parent92f20fd70e6957cd65ccb7837fdc28f9b1e4a315 (diff)
Add support for controlling physics nodes' behavior when disabled
New property disable_mode to set different behaviors: Remove: remove from physics simulation MakeStatic: change body mode to static (doesn't affect area and soft body) KeepActive: do nothing Extra change: Handle disable/enable node state with specific notifications, in order to differentiate global pause from disabled nodes.
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/collision_object_2d.cpp145
-rw-r--r--scene/2d/collision_object_2d.h23
-rw-r--r--scene/2d/physical_bone_2d.cpp62
-rw-r--r--scene/2d/physics_body_2d.cpp105
-rw-r--r--scene/3d/collision_object_3d.cpp146
-rw-r--r--scene/3d/collision_object_3d.h23
-rw-r--r--scene/3d/physics_body_3d.cpp115
-rw-r--r--scene/3d/soft_body_3d.cpp66
-rw-r--r--scene/3d/soft_body_3d.h12
-rw-r--r--scene/3d/vehicle_body_3d.cpp43
-rw-r--r--scene/main/node.cpp48
-rw-r--r--scene/main/node.h6
12 files changed, 595 insertions, 199 deletions
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index a633923be7..93d154bb01 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();
}
- _update_pickable();
+ 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);
+ }
+ }
- //get space
+ _update_pickable();
} 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 e10f3097d9..7a71affbb5 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<uint32_t, ShapeData> 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<uint32_t> *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 0c1be16174..d547914e16 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();
+ }
+
+ // Simulate physics if set.
+ if (simulate_physics) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
- set_physics_process_internal(true);
+ 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 ce63b25ce0..8801033ee6 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();
-
- // Reset move_and_slide() data.
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
- motion_results.clear();
- floor_velocity = Vector2();
- }
+ 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();
+ } 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 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 28a0c72fe3..2bbb89d389 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 df5474d03e..8b0803addc 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;
}
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e1abea81ef..4685f6d1dc 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 e7b36f351b..3d4c3fd434 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();