diff options
author | PouleyKetchoupp <pouleyketchoup@gmail.com> | 2021-06-17 18:09:40 -0700 |
---|---|---|
committer | PouleyKetchoupp <pouleyketchoup@gmail.com> | 2021-06-30 09:20:44 -0700 |
commit | 5cbdc7a0acbefcc3aa3cb0eb0fe05b5b10fe7370 (patch) | |
tree | ed92cd22587c8e8bf235e5b08b6017b5a5e8ca70 /scene/2d | |
parent | 92f20fd70e6957cd65ccb7837fdc28f9b1e4a315 (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.cpp | 145 | ||||
-rw-r--r-- | scene/2d/collision_object_2d.h | 23 | ||||
-rw-r--r-- | scene/2d/physical_bone_2d.cpp | 62 | ||||
-rw-r--r-- | scene/2d/physics_body_2d.cpp | 105 |
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; } } |