From 15bf4aefd06402f30e0f3a7399c36e49672d4476 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 4 Mar 2023 21:29:49 +0100 Subject: [PATCH] Ported: Rework how current Camera2D is determined https://github.com/godotengine/godot/commit/7e2a8afb57f59ec70bac6259f186887d953a1eed - KoBeWi and Fix Camera2D crashes https://github.com/godotengine/godot/commit/724d6581d64d3b8e99dae0bb1011edef8fbf700e - KoBeWi From godot4. Also fixed issues with active Camera2D switching. --- doc/classes/Camera2D.xml | 19 ++++++-- scene/2d/camera_2d.cpp | 95 +++++++++++++++++++--------------------- scene/2d/camera_2d.h | 6 ++- scene/main/viewport.cpp | 24 +++++++++- scene/main/viewport.h | 1 + 5 files changed, 89 insertions(+), 56 deletions(-) diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml index 4709eb0af..78e63004b 100644 --- a/doc/classes/Camera2D.xml +++ b/doc/classes/Camera2D.xml @@ -54,6 +54,18 @@ Returns the specified camera limit. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right]. + + + + Returns [code]true[/code] if this [Camera2D] is the active camera (see [method Viewport.get_camera_2d]). + + + + + + Forces this [Camera2D] to become the current active one. [member enabled] must be [code]true[/code]. + + @@ -82,9 +94,6 @@ The Camera2D's anchor point. See [enum AnchorMode] constants. - - If [code]true[/code], the camera is the active camera for the current scene. Only one camera can be current, so setting a different camera [code]current[/code] will disable this one. - The custom [Viewport] node attached to the [Camera2D]. If [code]null[/code] or not a [Viewport], uses the default viewport instead. @@ -106,6 +115,10 @@ If [code]true[/code], the camera only moves when reaching the vertical drag margins. If [code]false[/code], the camera moves vertically regardless of margins. + + Controls whether the camera can be active or not. If [code]true[/code], the [Camera2D] will become the main camera when it enters the scene tree and there is no active camera currently (see [method Viewport.get_camera_2d]). + When the camera is currently active and [member enabled] is set to [code]false[/code], the next enabled [Camera2D] in the scene tree will become active. + If [code]true[/code], draws the camera's drag margin rectangle in the editor. diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index cbb40e45b..38e9a686c 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -50,7 +50,7 @@ void Camera2D::_update_scroll() { return; } - if (current) { + if (is_current()) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); Transform2D xform = get_camera_transform(); @@ -252,32 +252,25 @@ void Camera2D::_notification(int p_what) { _setup_viewport(); _update_process_mode(); - if (is_current()) { - // if a camera enters the tree that is set to current, - // it should take over as the current camera, and mark - // all other cameras as non current - if (viewport->get_camera_2d() == NULL) { - first = true; - viewport->_camera_2d_set(this); - } else { - first = false; - make_current(); - } + if (!Engine::get_singleton()->is_editor_hint() && enabled && !viewport->get_camera_2d()) { + make_current(); } + + first = true; } break; case NOTIFICATION_EXIT_TREE: { - const bool viewport_valid = !custom_viewport || ObjectDB::get_instance(custom_viewport_id); + remove_from_group(group_name); + remove_from_group(canvas_group_name); + if (is_current()) { - if (viewport && viewport_valid) { - viewport->set_canvas_transform(Transform2D()); - clear_current(); - } + clear_current(); } + + const bool viewport_valid = !custom_viewport || ObjectDB::get_instance(custom_viewport_id); if (viewport && viewport_valid) { viewport->disconnect("size_changed", this, "_update_scroll"); } - remove_from_group(group_name); - remove_from_group(canvas_group_name); + viewport = nullptr; } break; @@ -404,11 +397,26 @@ Camera2D::Camera2DProcessMode Camera2D::get_process_mode() const { return process_mode; } +void Camera2D::set_enabled(bool p_enabled) { + enabled = p_enabled; + + if (enabled && is_inside_tree() && !viewport->get_camera_2d()) { + make_current(); + } else if (!enabled && is_current()) { + clear_current(); + } +} + +bool Camera2D::is_enabled() const { + return enabled; +} + void Camera2D::_make_current(Object *p_which) { if (p_which == this) { if (is_inside_tree()) { get_viewport()->_camera_2d_set(this); update(); + _update_scroll(); } } else { if (is_inside_tree()) { @@ -420,42 +428,26 @@ void Camera2D::_make_current(Object *p_which) { } } -void Camera2D::set_current(bool p_current) { - current = p_current; - - if (is_inside_tree()) { - if (p_current) { - make_current(); - } else { - if (get_viewport()->get_camera_2d() == this) { - clear_current(); - } - } - } -} - -bool Camera2D::is_current() const { - if (is_inside_tree()) { - return (get_viewport()->get_camera_2d() == this); - } - - return current; -} - void Camera2D::make_current() { - if (is_inside_tree()) { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", this); - } - + ERR_FAIL_COND(!enabled || !is_inside_tree()); + get_tree()->call_group(group_name, "_make_current", this); _update_scroll(); } void Camera2D::clear_current() { - if (is_inside_tree()) { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", (Object *)nullptr); + ERR_FAIL_COND(!is_current()); + if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) { + viewport->assign_next_enabled_camera_2d(group_name); } } +bool Camera2D::is_current() const { + if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) { + return viewport->get_camera_2d() == this; + } + return false; +} + void Camera2D::set_limit(Margin p_margin, int p_limit) { ERR_FAIL_INDEX((int)p_margin, 4); limit[p_margin] = p_limit; @@ -676,7 +668,10 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Camera2D::set_process_mode); ClassDB::bind_method(D_METHOD("get_process_mode"), &Camera2D::get_process_mode); - ClassDB::bind_method(D_METHOD("set_current", "current"), &Camera2D::set_current); + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &Camera2D::set_enabled); + ClassDB::bind_method(D_METHOD("is_enabled"), &Camera2D::is_enabled); + + ClassDB::bind_method(D_METHOD("make_current"), &Camera2D::make_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current); ClassDB::bind_method(D_METHOD("_make_current"), &Camera2D::_make_current); @@ -732,7 +727,7 @@ void Camera2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); @@ -776,7 +771,7 @@ void Camera2D::_bind_methods() { Camera2D::Camera2D() { anchor_mode = ANCHOR_MODE_DRAG_CENTER; rotating = false; - current = false; + enabled = true; limit[MARGIN_LEFT] = -10000000; limit[MARGIN_TOP] = -10000000; limit[MARGIN_RIGHT] = 10000000; diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index baff8f2a9..5c0b7569d 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -64,7 +64,7 @@ protected: Vector2 zoom; AnchorMode anchor_mode; bool rotating; - bool current; + bool enabled; float smoothing; bool smoothing_enabled; bool smoothing_active; // smoothing can be enabled but not active in the editor @@ -86,7 +86,6 @@ protected: void _setup_viewport(); void _make_current(Object *p_which); - void set_current(bool p_current); bool screen_drawing_enabled; bool limit_drawing_enabled; @@ -139,6 +138,9 @@ public: void set_process_mode(Camera2DProcessMode p_mode); Camera2DProcessMode get_process_mode() const; + void set_enabled(bool p_enabled); + bool is_enabled() const; + void make_current(); void clear_current(); bool is_current() const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 2c3da0ff2..22f814d67 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1159,6 +1159,28 @@ Transform2D Viewport::get_final_transform() const { return stretch_transform * global_canvas_transform; } +void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) { + List camera_list; + get_tree()->get_nodes_in_group(p_camera_group, &camera_list); + + Camera2D *new_camera = nullptr; + for (List::Element *E = camera_list.front(); E; E = E->next()) { + Camera2D *cam = Object::cast_to(E->get()); + if (cam->is_enabled()) { + new_camera = cam; + break; + } + } + + camera_2d = NULL; + + if (!new_camera) { + set_canvas_transform(Transform2D()); + } else { + new_camera->make_current(); + } +} + void Viewport::_update_canvas_items(Node *p_node) { if (p_node != this) { Viewport *vp = Object::cast_to(p_node); @@ -2255,7 +2277,7 @@ void Viewport::_gui_input_event(Ref p_event) { _gui_call_input(over, touch_event); set_input_as_handled(); } - + gui.touch_focus.erase(touch_index); return; } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index f994f1493..6b9f8cae0 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -193,6 +193,7 @@ public: Transform2D get_global_canvas_transform() const; Transform2D get_final_transform() const; + void assign_next_enabled_camera_2d(const StringName &p_camera_group); void set_transparent_background(bool p_enable); bool has_transparent_background() const;