summaryrefslogtreecommitdiff
path: root/scene/2d
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/2d
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/2d')
-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
4 files changed, 243 insertions, 92 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;
}
}