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.
This commit is contained in:
PouleyKetchoupp 2021-06-17 18:09:40 -07:00
parent 92f20fd70e
commit 5cbdc7a0ac
16 changed files with 638 additions and 198 deletions

View file

@ -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]. 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. [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.
</member> </member>
<member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject2D.DisableMode" default="0">
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.
</member>
<member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true"> <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true">
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. 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.
</member> </member>
@ -294,5 +297,16 @@
</signal> </signal>
</signals> </signals>
<constants> <constants>
<constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode">
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.
</constant>
<constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode">
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.
</constant>
<constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode">
When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation.
</constant>
</constants> </constants>
</class> </class>

View file

@ -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]. 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. [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.
</member> </member>
<member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject3D.DisableMode" default="0">
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.
</member>
<member name="input_capture_on_drag" type="bool" setter="set_capture_input_on_drag" getter="get_capture_input_on_drag" default="false"> <member name="input_capture_on_drag" type="bool" setter="set_capture_input_on_drag" getter="get_capture_input_on_drag" default="false">
If [code]true[/code], the [CollisionObject3D] will continue to receive input events as the mouse is dragged across its shapes. If [code]true[/code], the [CollisionObject3D] will continue to receive input events as the mouse is dragged across its shapes.
</member> </member>
@ -265,5 +268,16 @@
</signal> </signal>
</signals> </signals>
<constants> <constants>
<constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode">
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.
</constant>
<constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode">
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.
</constant>
<constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode">
When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation.
</constant>
</constants> </constants>
</class> </class>

View file

@ -894,6 +894,12 @@
<constant name="NOTIFICATION_POST_ENTER_TREE" value="27"> <constant name="NOTIFICATION_POST_ENTER_TREE" value="27">
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 ready, just before [constant NOTIFICATION_READY] is received. Unlike the latter, it's sent every time the node enters tree, instead of only once.
</constant> </constant>
<constant name="NOTIFICATION_DISABLED" value="28">
Notification received when the node is disabled. See [constant PROCESS_MODE_DISABLED].
</constant>
<constant name="NOTIFICATION_ENABLED" value="29">
Notification received when the node is enabled again after being disabled. See [constant PROCESS_MODE_DISABLED].
</constant>
<constant name="NOTIFICATION_EDITOR_PRE_SAVE" value="9001"> <constant name="NOTIFICATION_EDITOR_PRE_SAVE" value="9001">
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. 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.
</constant> </constant>

View file

@ -93,6 +93,9 @@
</member> </member>
<member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01"> <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01">
</member> </member>
<member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="SoftBody3D.DisableMode" default="0">
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.
</member>
<member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0"> <member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0">
</member> </member>
<member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5"> <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5">
@ -113,5 +116,12 @@
</member> </member>
</members> </members>
<constants> <constants>
<constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode">
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.
</constant>
<constant name="DISABLE_MODE_KEEP_ACTIVE" value="1" enum="DisableMode">
When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation.
</constant>
</constants> </constants>
</class> </class>

View file

@ -31,7 +31,6 @@
#include "collision_object_2d.h" #include "collision_object_2d.h"
#include "scene/scene_string_names.h" #include "scene/scene_string_names.h"
#include "servers/physics_server_2d.h"
void CollisionObject2D::_notification(int p_what) { void CollisionObject2D::_notification(int p_what) {
switch (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); PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
} }
RID space = get_world_2d()->get_space(); bool disabled = !is_enabled();
if (area) {
PhysicsServer2D::get_singleton()->area_set_space(rid, space); if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) {
} else { _apply_disabled();
PhysicsServer2D::get_singleton()->body_set_space(rid, space); }
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(); _update_pickable();
//get space
} break; } break;
case NOTIFICATION_ENTER_CANVAS: { case NOTIFICATION_ENTER_CANVAS: {
@ -67,6 +72,7 @@ void CollisionObject2D::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable(); _update_pickable();
} break; } break;
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
if (only_update_transform_changes) { if (only_update_transform_changes) {
return; return;
@ -79,15 +85,22 @@ void CollisionObject2D::_notification(int p_what) {
} else { } else {
PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform); PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
} }
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
if (area) { bool disabled = !is_enabled();
PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
} else { if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); 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; } break;
case NOTIFICATION_EXIT_CANVAS: { case NOTIFICATION_EXIT_CANVAS: {
@ -97,6 +110,14 @@ void CollisionObject2D::_notification(int p_what) {
PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID()); PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID());
} }
} break; } 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); 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) { uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
ShapeData sd; ShapeData sd;
uint32_t id; uint32_t id;
@ -412,6 +506,22 @@ bool CollisionObject2D::is_only_update_transform_changes_enabled() const {
return only_update_transform_changes; 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() { void CollisionObject2D::_update_pickable() {
if (!is_inside_tree()) { if (!is_inside_tree()) {
return; 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("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("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("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("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable); ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable);
ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject2D::create_shape_owner); 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_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited")); 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_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_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_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Input", "input_"); ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable"); 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) { 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()); PhysicsServer2D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
} else { } else {
PhysicsServer2D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id()); PhysicsServer2D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode);
} }
} }

View file

@ -33,10 +33,19 @@
#include "scene/2d/node_2d.h" #include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h" #include "scene/resources/shape_2d.h"
#include "servers/physics_server_2d.h"
class CollisionObject2D : public Node2D { class CollisionObject2D : public Node2D {
GDCLASS(CollisionObject2D, 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_layer = 1;
uint32_t collision_mask = 1; uint32_t collision_mask = 1;
@ -44,6 +53,10 @@ class CollisionObject2D : public Node2D {
RID rid; RID rid;
bool pickable = false; bool pickable = false;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
PhysicsServer2D::BodyMode body_mode = PhysicsServer2D::BODY_MODE_STATIC;
struct ShapeData { struct ShapeData {
Object *owner = nullptr; Object *owner = nullptr;
Transform2D xform; Transform2D xform;
@ -64,6 +77,9 @@ class CollisionObject2D : public Node2D {
Map<uint32_t, ShapeData> shapes; Map<uint32_t, ShapeData> shapes;
bool only_update_transform_changes = false; //this is used for sync physics in CharacterBody2D bool only_update_transform_changes = false; //this is used for sync physics in CharacterBody2D
void _apply_disabled();
void _apply_enabled();
protected: protected:
CollisionObject2D(RID p_rid, bool p_area); CollisionObject2D(RID p_rid, bool p_area);
@ -79,6 +95,8 @@ protected:
void set_only_update_transform_changes(bool p_enable); void set_only_update_transform_changes(bool p_enable);
bool is_only_update_transform_changes_enabled() const; bool is_only_update_transform_changes_enabled() const;
void set_body_mode(PhysicsServer2D::BodyMode p_mode);
public: public:
void set_collision_layer(uint32_t p_layer); void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const; uint32_t get_collision_layer() const;
@ -92,6 +110,9 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value); void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const; 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); uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner); void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners); void get_shape_owners(List<uint32_t> *r_owners);
@ -131,4 +152,6 @@ public:
~CollisionObject2D(); ~CollisionObject2D();
}; };
VARIANT_ENUM_CAST(CollisionObject2D::DisableMode);
#endif // COLLISION_OBJECT_2D_H #endif // COLLISION_OBJECT_2D_H

View file

@ -31,33 +31,37 @@
#include "physical_bone_2d.h" #include "physical_bone_2d.h"
void PhysicalBone2D::_notification(int p_what) { void PhysicalBone2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { switch (p_what) {
// Position the RigidBody in the correct position case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (follow_bone_when_simulating) { // Position the RigidBody in the correct position.
_position_at_bone2d(); if (follow_bone_when_simulating) {
} _position_at_bone2d();
}
// Keep the child joint in the correct position. // Keep the child joint in the correct position.
if (child_joint && auto_configure_joint) { if (child_joint && auto_configure_joint) {
child_joint->set_global_position(get_global_position()); child_joint->set_global_position(get_global_position());
} }
} else if (p_what == NOTIFICATION_READY) { } break;
_find_skeleton_parent();
_find_joint_child();
// Configure joint case NOTIFICATION_READY: {
if (child_joint && auto_configure_joint) { _find_skeleton_parent();
_auto_configure_joint(); _find_joint_child();
}
// Simulate physics if set // Configure joint.
if (simulate_physics) { if (child_joint && auto_configure_joint) {
_start_physics_simulation(); _auto_configure_joint();
} else { }
_stop_physics_simulation();
}
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 // Apply the correct mode
RigidBody2D::Mode rigid_mode = get_mode(); RigidBody2D::Mode rigid_mode = get_mode();
if (rigid_mode == RigidBody2D::MODE_STATIC) { 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) { } 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) { } 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) { } 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 { } else {
// Default to Rigid // Default to Dynamic.
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC); set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
} }
_internal_simulate_physics = true; _internal_simulate_physics = true;

View file

@ -49,7 +49,7 @@ void PhysicsBody2D::_bind_methods() {
PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) : PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) { 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); set_pickable(false);
} }
@ -186,9 +186,9 @@ void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) {
kinematic_motion = p_enabled; kinematic_motion = p_enabled;
if (kinematic_motion) { if (kinematic_motion) {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC); set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
} else { } else {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC); set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
} }
_update_kinematic_motion(); _update_kinematic_motion();
@ -199,28 +199,30 @@ bool StaticBody2D::is_kinematic_motion_enabled() const {
} }
void StaticBody2D::_notification(int p_what) { void StaticBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { switch (p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
return; return;
} }
#endif #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.translate(constant_linear_velocity * delta_time);
new_transform.set_rotation(new_transform.get_rotation() + constant_angular_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. // Propagate transform change to node.
set_block_transform_notify(true); set_block_transform_notify(true);
set_global_transform(new_transform); set_global_transform(new_transform);
set_block_transform_notify(false); set_block_transform_notify(false);
} break;
} }
} }
@ -495,18 +497,18 @@ void RigidBody2D::set_mode(Mode p_mode) {
mode = p_mode; mode = p_mode;
switch (p_mode) { switch (p_mode) {
case MODE_DYNAMIC: { case MODE_DYNAMIC: {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_DYNAMIC); set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
} break; } break;
case MODE_STATIC: { case MODE_STATIC: {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC); set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
} break; } break;
case MODE_KINEMATIC: { case MODE_KINEMATIC: {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC); set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
} break; } break;
case MODE_DYNAMIC_LOCKED: { 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; } break;
} }
@ -762,18 +764,19 @@ bool RigidBody2D::is_contact_monitor_enabled() const {
void RigidBody2D::_notification(int p_what) { void RigidBody2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (p_what == NOTIFICATION_ENTER_TREE) { switch (p_what) {
if (Engine::get_singleton()->is_editor_hint()) { case NOTIFICATION_ENTER_TREE: {
set_notify_local_transform(true); //used for warnings and only in editor 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) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
update_configuration_warnings(); update_configuration_warnings();
} }
} break;
} }
#endif #endif
} }
@ -1232,26 +1235,28 @@ void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) {
} }
void CharacterBody2D::_notification(int p_what) { void CharacterBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) { switch (p_what) {
last_valid_transform = get_global_transform(); case NOTIFICATION_ENTER_TREE: {
last_valid_transform = get_global_transform();
// Reset move_and_slide() data. // Reset move_and_slide() data.
on_floor = false; on_floor = false;
on_floor_body = RID(); on_floor_body = RID();
on_ceiling = false; on_ceiling = false;
on_wall = false; on_wall = false;
motion_results.clear(); motion_results.clear();
floor_velocity = Vector2(); floor_velocity = Vector2();
} } break;
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
//used by sync to physics, send the new transform to the physics // Used by sync to physics, send the new transform to the physics.
Transform2D new_transform = get_global_transform(); Transform2D new_transform = get_global_transform();
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);
//but then revert changes // But then revert changes.
set_notify_local_transform(false); set_notify_local_transform(false);
set_global_transform(last_valid_transform); set_global_transform(last_valid_transform);
set_notify_local_transform(true); set_notify_local_transform(true);
} break;
} }
} }

View file

@ -32,7 +32,6 @@
#include "core/config/engine.h" #include "core/config/engine.h"
#include "scene/scene_string_names.h" #include "scene/scene_string_names.h"
#include "servers/physics_server_3d.h"
void CollisionObject3D::_notification(int p_what) { void CollisionObject3D::_notification(int p_what) {
switch (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()); PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
} }
RID space = get_world_3d()->get_space(); bool disabled = !is_enabled();
if (area) {
PhysicsServer3D::get_singleton()->area_set_space(rid, space); if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) {
} else { _apply_disabled();
PhysicsServer3D::get_singleton()->body_set_space(rid, space); }
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(); _update_pickable();
//get space
} break; } break;
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
@ -78,19 +84,34 @@ void CollisionObject3D::_notification(int p_what) {
} }
_on_transform_changed(); _on_transform_changed();
} break; } break;
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable(); _update_pickable();
} break; } break;
case NOTIFICATION_EXIT_WORLD: { case NOTIFICATION_EXIT_WORLD: {
if (area) { bool disabled = !is_enabled();
PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
} else { if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); 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; } break;
} }
} }
@ -153,6 +174,79 @@ bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit); 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) { 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()) { if (get_script_instance()) {
get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape); 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); 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() { void CollisionObject3D::_update_pickable() {
if (!is_inside_tree()) { if (!is_inside_tree()) {
return; 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("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("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("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("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("is_ray_pickable"), &CollisionObject3D::is_ray_pickable);
ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject3D::set_capture_input_on_drag); 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_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited")); 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_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_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"); 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_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable"); 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"); 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) { 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()); PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
} else { } else {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id()); 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) { void CollisionObject3D::set_capture_input_on_drag(bool p_capture) {

View file

@ -33,10 +33,19 @@
#include "scene/3d/node_3d.h" #include "scene/3d/node_3d.h"
#include "scene/resources/shape_3d.h" #include "scene/resources/shape_3d.h"
#include "servers/physics_server_3d.h"
class CollisionObject3D : public Node3D { class CollisionObject3D : public Node3D {
GDCLASS(CollisionObject3D, 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_layer = 1;
uint32_t collision_mask = 1; uint32_t collision_mask = 1;
@ -44,6 +53,10 @@ class CollisionObject3D : public Node3D {
RID rid; RID rid;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
PhysicsServer3D::BodyMode body_mode = PhysicsServer3D::BODY_MODE_STATIC;
struct ShapeData { struct ShapeData {
Object *owner = nullptr; Object *owner = nullptr;
Transform3D xform; Transform3D xform;
@ -76,6 +89,9 @@ class CollisionObject3D : public Node3D {
void _update_debug_shapes(); void _update_debug_shapes();
void _clear_debug_shapes(); void _clear_debug_shapes();
void _apply_disabled();
void _apply_enabled();
protected: protected:
CollisionObject3D(RID p_rid, bool p_area); CollisionObject3D(RID p_rid, bool p_area);
@ -89,6 +105,8 @@ protected:
virtual void _mouse_enter(); virtual void _mouse_enter();
virtual void _mouse_exit(); virtual void _mouse_exit();
void set_body_mode(PhysicsServer3D::BodyMode p_mode);
public: public:
void set_collision_layer(uint32_t p_layer); void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const; uint32_t get_collision_layer() const;
@ -102,6 +120,9 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value); void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const; 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); uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner); void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners); void get_shape_owners(List<uint32_t> *r_owners);
@ -138,4 +159,6 @@ public:
~CollisionObject3D(); ~CollisionObject3D();
}; };
VARIANT_ENUM_CAST(CollisionObject3D::DisableMode);
#endif // COLLISION_OBJECT__H #endif // COLLISION_OBJECT__H

View file

@ -65,7 +65,7 @@ void PhysicsBody3D::_bind_methods() {
PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode); set_body_mode(p_mode);
} }
PhysicsBody3D::~PhysicsBody3D() { PhysicsBody3D::~PhysicsBody3D() {
@ -200,9 +200,9 @@ void StaticBody3D::set_kinematic_motion_enabled(bool p_enabled) {
kinematic_motion = p_enabled; kinematic_motion = p_enabled;
if (kinematic_motion) { if (kinematic_motion) {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
} else { } else {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
} }
_update_kinematic_motion(); _update_kinematic_motion();
@ -249,35 +249,37 @@ Vector3 StaticBody3D::get_angular_velocity() const {
} }
void StaticBody3D::_notification(int p_what) { void StaticBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { switch (p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
return; return;
} }
#endif #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(); Transform3D new_transform = get_global_transform();
new_transform.origin += constant_linear_velocity * delta_time; new_transform.origin += constant_linear_velocity * delta_time;
real_t ang_vel = constant_angular_velocity.length(); real_t ang_vel = constant_angular_velocity.length();
if (!Math::is_zero_approx(ang_vel)) { if (!Math::is_zero_approx(ang_vel)) {
Vector3 ang_vel_axis = constant_angular_velocity / ang_vel; Vector3 ang_vel_axis = constant_angular_velocity / ang_vel;
Basis rot(ang_vel_axis, ang_vel * delta_time); Basis rot(ang_vel_axis, ang_vel * delta_time);
new_transform.basis = rot * new_transform.basis; new_transform.basis = rot * new_transform.basis;
new_transform.orthonormalize(); 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. // Propagate transform change to node.
set_ignore_transform_notification(true); set_ignore_transform_notification(true);
set_global_transform(new_transform); set_global_transform(new_transform);
set_ignore_transform_notification(false); set_ignore_transform_notification(false);
_on_transform_changed(); _on_transform_changed();
} break;
} }
} }
@ -565,18 +567,19 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
void RigidBody3D::_notification(int p_what) { void RigidBody3D::_notification(int p_what) {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (p_what == NOTIFICATION_ENTER_TREE) { switch (p_what) {
if (Engine::get_singleton()->is_editor_hint()) { case NOTIFICATION_ENTER_TREE: {
set_notify_local_transform(true); //used for warnings and only in editor 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) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
update_configuration_warnings(); update_configuration_warnings();
} }
} break;
} }
#endif #endif
} }
@ -584,18 +587,16 @@ void RigidBody3D::set_mode(Mode p_mode) {
mode = p_mode; mode = p_mode;
switch (p_mode) { switch (p_mode) {
case MODE_DYNAMIC: { case MODE_DYNAMIC: {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC); set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
} break; } break;
case MODE_STATIC: { case MODE_STATIC: {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
} break; } break;
case MODE_DYNAMIC_LOCKED: { 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; } break;
case MODE_KINEMATIC: { case MODE_KINEMATIC: {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
} break; } break;
} }
update_configuration_warnings(); update_configuration_warnings();
@ -1233,14 +1234,16 @@ void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) {
} }
void CharacterBody3D::_notification(int p_what) { void CharacterBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) { switch (p_what) {
// Reset move_and_slide() data. case NOTIFICATION_ENTER_TREE: {
on_floor = false; // Reset move_and_slide() data.
on_floor_body = RID(); on_floor = false;
on_ceiling = false; on_floor_body = RID();
on_wall = false; on_ceiling = false;
motion_results.clear(); on_wall = false;
floor_velocity = Vector3(); motion_results.clear();
floor_velocity = Vector3();
} break;
} }
} }
@ -2095,7 +2098,8 @@ void PhysicalBone3D::_notification(int p_what) {
_reload_joint(); _reload_joint();
} }
break; break;
case NOTIFICATION_EXIT_TREE:
case NOTIFICATION_EXIT_TREE: {
if (parent_skeleton) { if (parent_skeleton) {
if (-1 != bone_id) { if (-1 != bone_id) {
parent_skeleton->unbind_physical_bone_from_bone(bone_id); parent_skeleton->unbind_physical_bone_from_bone(bone_id);
@ -2105,12 +2109,13 @@ void PhysicalBone3D::_notification(int p_what) {
} }
parent_skeleton = nullptr; parent_skeleton = nullptr;
PhysicsServer3D::get_singleton()->joint_clear(joint); PhysicsServer3D::get_singleton()->joint_clear(joint);
break; } break;
case NOTIFICATION_TRANSFORM_CHANGED:
case NOTIFICATION_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
update_offset(); update_offset();
} }
break; } break;
} }
} }
@ -2605,7 +2610,7 @@ void PhysicalBone3D::_start_physics_simulation() {
return; return;
} }
reset_to_rest_position(); 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_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); 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)); 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; return;
} }
if (parent_skeleton->get_animate_physical_bones()) { 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_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
} else { } 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_layer(get_rid(), 0);
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
} }

View file

@ -266,12 +266,13 @@ void SoftBody3D::_notification(int p_what) {
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space); PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
prepare_physics_server(); prepare_physics_server();
} break; } break;
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
if (!parent_collision_ignore.is_empty()) { if (!parent_collision_ignore.is_empty()) {
add_collision_exception_with(get_node(parent_collision_ignore)); add_collision_exception_with(get_node(parent_collision_ignore));
} }
} break; } break;
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
_reset_points_offsets(); _reset_points_offsets();
@ -285,27 +286,36 @@ void SoftBody3D::_notification(int p_what) {
set_as_top_level(true); set_as_top_level(true);
set_transform(Transform3D()); set_transform(Transform3D());
set_notify_transform(true); set_notify_transform(true);
} break; } break;
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable(); _update_pickable();
} break; } break;
case NOTIFICATION_EXIT_WORLD: { case NOTIFICATION_EXIT_WORLD: {
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID()); PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID());
} break; } 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 #ifdef TOOLS_ENABLED
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (Engine::get_singleton()->is_editor_hint()) {
if (Engine::get_singleton()->is_editor_hint()) { update_configuration_warnings();
update_configuration_warnings(); }
} } break;
}
#endif #endif
}
} }
void SoftBody3D::_bind_methods() { 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("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("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("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("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); 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::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::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 { TypedArray<String> SoftBody3D::get_configuration_warnings() const {
@ -421,6 +439,7 @@ void SoftBody3D::_draw_soft_mesh() {
} }
void SoftBody3D::prepare_physics_server() { void SoftBody3D::prepare_physics_server() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
if (get_mesh().is_valid()) { if (get_mesh().is_valid()) {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
@ -430,8 +449,9 @@ void SoftBody3D::prepare_physics_server() {
return; return;
} }
#endif
if (get_mesh().is_valid()) { if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) {
become_mesh_owner(); become_mesh_owner();
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); 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)); 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); 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) { void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
parent_collision_ignore = p_parent_collision_ignore; parent_collision_ignore = p_parent_collision_ignore;
} }

View file

@ -67,6 +67,11 @@ class SoftBody3D : public MeshInstance3D {
GDCLASS(SoftBody3D, MeshInstance3D); GDCLASS(SoftBody3D, MeshInstance3D);
public: public:
enum DisableMode {
DISABLE_MODE_REMOVE,
DISABLE_MODE_KEEP_ACTIVE,
};
struct PinnedPoint { struct PinnedPoint {
int point_index = -1; int point_index = -1;
NodePath spatial_attachment_path; NodePath spatial_attachment_path;
@ -83,6 +88,8 @@ private:
RID physics_rid; RID physics_rid;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
bool mesh_owner = false; bool mesh_owner = false;
uint32_t collision_mask = 1; uint32_t collision_mask = 1;
uint32_t collision_layer = 1; uint32_t collision_layer = 1;
@ -137,6 +144,9 @@ public:
void set_collision_layer_bit(int p_bit, bool p_value); void set_collision_layer_bit(int p_bit, bool p_value);
bool get_collision_layer_bit(int p_bit) const; 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); void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
const NodePath &get_parent_collision_ignore() const; const NodePath &get_parent_collision_ignore() const;
@ -192,4 +202,6 @@ private:
int _has_pinned_point(int p_point_index) const; int _has_pinned_point(int p_point_index) const;
}; };
VARIANT_ENUM_CAST(SoftBody3D::DisableMode);
#endif // SOFT_PHYSICS_BODY_H #endif // SOFT_PHYSICS_BODY_H

View file

@ -79,26 +79,29 @@ public:
}; };
void VehicleWheel3D::_notification(int p_what) { void VehicleWheel3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) { switch (p_what) {
VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); case NOTIFICATION_ENTER_TREE: {
if (!cb) { VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
return; if (!cb) {
} return;
body = cb; }
local_xform = get_transform(); body = cb;
cb->wheels.push_back(this); local_xform = get_transform();
cb->wheels.push_back(this);
m_chassisConnectionPointCS = get_transform().origin; m_chassisConnectionPointCS = get_transform().origin;
m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
} } break;
if (p_what == NOTIFICATION_EXIT_TREE) {
VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); case NOTIFICATION_EXIT_TREE: {
if (!cb) { VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
return; if (!cb) {
} return;
cb->wheels.erase(this); }
body = nullptr; cb->wheels.erase(this);
body = nullptr;
} break;
} }
} }

View file

@ -402,6 +402,7 @@ void Node::set_process_mode(ProcessMode p_mode) {
} }
bool prev_can_process = can_process(); bool prev_can_process = can_process();
bool prev_enabled = _is_enabled();
data.process_mode = p_mode; 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_can_process = can_process();
bool next_enabled = _is_enabled();
int pause_notification = 0; int pause_notification = 0;
@ -425,7 +427,16 @@ void Node::set_process_mode(ProcessMode p_mode) {
pause_notification = NOTIFICATION_UNPAUSED; 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 #ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes // This is required for the editor to update the visibility of disabled nodes
// It's very expensive during runtime to change, so editor-only // 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; 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; data.process_owner = p_owner;
if (p_notification != 0) { if (p_pause_notification != 0) {
notification(p_notification); notification(p_pause_notification);
}
if (p_enabled_notification != 0) {
notification(p_enabled_notification);
} }
for (int i = 0; i < data.children.size(); i++) { for (int i = 0; i < data.children.size(); i++) {
Node *c = data.children[i]; Node *c = data.children[i];
if (c->data.process_mode == PROCESS_MODE_INHERIT) { 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 { float Node::get_physics_process_delta_time() const {
if (data.tree) { if (data.tree) {
return data.tree->get_physics_process_time(); return data.tree->get_physics_process_time();
@ -2619,6 +2655,8 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE); BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_DISABLED);
BIND_CONSTANT(NOTIFICATION_ENABLED);
BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE); BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE);
BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE); BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE);

View file

@ -163,7 +163,7 @@ private:
void _propagate_after_exit_tree(); void _propagate_after_exit_tree();
void _propagate_validate_owner(); void _propagate_validate_owner();
void _print_stray_nodes(); 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); Array _get_node_and_resource(const NodePath &p_path);
void _duplicate_signals(const Node *p_original, Node *p_copy) const; void _duplicate_signals(const Node *p_original, Node *p_copy) const;
@ -181,6 +181,7 @@ private:
void _propagate_pause_notification(bool p_enable); void _propagate_pause_notification(bool p_enable);
_FORCE_INLINE_ bool _can_process(bool p_paused) const; _FORCE_INLINE_ bool _can_process(bool p_paused) const;
_FORCE_INLINE_ bool _is_enabled() const;
protected: protected:
void _block() { data.blocked++; } void _block() { data.blocked++; }
@ -224,6 +225,8 @@ public:
NOTIFICATION_INTERNAL_PROCESS = 25, NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26, NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27, NOTIFICATION_POST_ENTER_TREE = 27,
NOTIFICATION_DISABLED = 28,
NOTIFICATION_ENABLED = 29,
//keep these linked to node //keep these linked to node
NOTIFICATION_WM_MOUSE_ENTER = 1002, NOTIFICATION_WM_MOUSE_ENTER = 1002,
@ -380,6 +383,7 @@ public:
ProcessMode get_process_mode() const; ProcessMode get_process_mode() const;
bool can_process() const; bool can_process() const;
bool can_process_notification(int p_what) const; bool can_process_notification(int p_what) const;
bool is_enabled() const;
void request_ready(); void request_ready();