diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 11fe595daf0..f084f5bdbdf 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -653,6 +653,9 @@
The [CanvasItem] has exited the canvas.
+
+ The [CanvasItem]'s active [World2D] changed.
+
The [CanvasItem] will inherit the filter from its parent.
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index ba3b0cec5c1..ab42c52913b 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -118,6 +118,15 @@ void CollisionObject2D::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_WORLD_2D_CHANGED: {
+ 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 NOTIFICATION_DISABLED: {
_apply_disabled();
} break;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index b36353158b7..ee10f7988eb 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -336,6 +336,10 @@ void CanvasItem::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
} break;
+ case NOTIFICATION_WORLD_2D_CHANGED: {
+ _exit_canvas();
+ _enter_canvas();
+ }
}
}
@@ -1108,6 +1112,7 @@ void CanvasItem::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
+ BIND_CONSTANT(NOTIFICATION_WORLD_2D_CHANGED);
BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 8cd57536bf0..b226314ea96 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1047,7 +1047,11 @@ void Viewport::set_world_2d(const Ref &p_world_2d) {
}
if (p_world_2d.is_valid()) {
+ bool do_propagate = world_2d.is_valid() && is_inside_tree();
world_2d = p_world_2d;
+ if (do_propagate) {
+ _propagate_world_2d_changed(this);
+ }
} else {
WARN_PRINT("Invalid world_2d");
world_2d = Ref(memnew(World2D));
@@ -3807,6 +3811,25 @@ float Viewport::get_texture_mipmap_bias() const {
#endif // _3D_DISABLED
+void Viewport::_propagate_world_2d_changed(Node *p_node) {
+ if (p_node != this) {
+ if (Object::cast_to(p_node)) {
+ p_node->notification(CanvasItem::NOTIFICATION_WORLD_2D_CHANGED);
+ } else {
+ Viewport *v = Object::cast_to(p_node);
+ if (v) {
+ if (v->world_2d.is_valid()) {
+ return;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); ++i) {
+ _propagate_world_2d_changed(p_node->get_child(i));
+ }
+}
+
void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d);
ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 5213c0db018..c0988de0fa5 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -729,6 +729,8 @@ public:
bool is_using_xr();
#endif // _3D_DISABLED
+ void _propagate_world_2d_changed(Node *p_node);
+
void _validate_property(PropertyInfo &p_property) const;
Viewport();
~Viewport();