Browse Source

Merge pull request #65698 from KoBeWi/cameraman

Rework how current Camera2D is determined
Rémi Verschelde 2 years ago
parent
commit
14a4408e02
5 changed files with 79 additions and 44 deletions
  1. 16 3
      doc/classes/Camera2D.xml
  2. 39 39
      scene/2d/camera_2d.cpp
  3. 4 2
      scene/2d/camera_2d.h
  4. 19 0
      scene/main/viewport.cpp
  5. 1 0
      scene/main/viewport.h

+ 16 - 3
doc/classes/Camera2D.xml

@@ -55,6 +55,18 @@
 				[b]Note:[/b] The returned value is not the same as [member Node2D.global_position], as it is affected by the drag properties. It is also not the same as the current position if [member position_smoothing_enabled] is [code]true[/code] (see [method get_screen_center_position]).
 			</description>
 		</method>
+		<method name="is_current" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this [Camera2D] is the active camera (see [method Viewport.get_camera_2d]).
+			</description>
+		</method>
+		<method name="make_current">
+			<return type="void" />
+			<description>
+				Forces this [Camera2D] to become the current active one. [member enabled] must be [code]true[/code].
+			</description>
+		</method>
 		<method name="reset_smoothing">
 			<return type="void" />
 			<description>
@@ -83,9 +95,6 @@
 		<member name="anchor_mode" type="int" setter="set_anchor_mode" getter="get_anchor_mode" enum="Camera2D.AnchorMode" default="1">
 			The Camera2D's anchor point. See [enum AnchorMode] constants.
 		</member>
-		<member name="current" type="bool" setter="set_current" getter="is_current" default="false">
-			If [code]true[/code], the camera acts as the active camera for its [Viewport] ancestor. Only one camera can be current in a given viewport, so setting a different camera in the same viewport [code]current[/code] will disable whatever camera was already active in that viewport.
-		</member>
 		<member name="custom_viewport" type="Node" setter="set_custom_viewport" getter="get_custom_viewport">
 			The custom [Viewport] node attached to the [Camera2D]. If [code]null[/code] or not a [Viewport], uses the default viewport instead.
 		</member>
@@ -124,6 +133,10 @@
 		<member name="editor_draw_screen" type="bool" setter="set_screen_drawing_enabled" getter="is_screen_drawing_enabled" default="true">
 			If [code]true[/code], draws the camera's screen rectangle in the editor.
 		</member>
+		<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
+			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.
+		</member>
 		<member name="ignore_rotation" type="bool" setter="set_ignore_rotation" getter="is_ignoring_rotation" default="true">
 			If [code]true[/code], the camera's rendered view is not affected by its [member Node2D.rotation] and [member Node2D.global_rotation].
 		</member>

+ 39 - 39
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();
@@ -241,10 +241,6 @@ void Camera2D::_notification(int p_what) {
 				viewport = get_viewport();
 			}
 
-			if (is_current()) {
-				viewport->_camera_2d_set(this);
-			}
-
 			canvas = get_canvas();
 
 			RID vp = viewport->get_viewport_rid();
@@ -254,6 +250,10 @@ void Camera2D::_notification(int p_what) {
 			add_to_group(group_name);
 			add_to_group(canvas_group_name);
 
+			if (enabled && !viewport->get_camera_2d()) {
+				make_current();
+			}
+
 			_update_process_callback();
 			first = true;
 			_update_scroll();
@@ -261,11 +261,7 @@ void Camera2D::_notification(int p_what) {
 
 		case NOTIFICATION_EXIT_TREE: {
 			if (is_current()) {
-				if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
-					viewport->set_canvas_transform(Transform2D());
-					clear_current();
-					current = true;
-				}
+				clear_current();
 			}
 			remove_from_group(group_name);
 			remove_from_group(canvas_group_name);
@@ -397,19 +393,31 @@ void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
 	_update_process_callback();
 }
 
+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;
+}
+
 Camera2D::Camera2DProcessCallback Camera2D::get_process_callback() const {
 	return process_callback;
 }
 
 void Camera2D::_make_current(Object *p_which) {
 	if (p_which == this) {
-		current = true;
 		if (is_inside_tree()) {
 			get_viewport()->_camera_2d_set(this);
 			queue_redraw();
 		}
 	} else {
-		current = false;
 		if (is_inside_tree()) {
 			if (get_viewport()->get_camera_2d() == this) {
 				get_viewport()->_camera_2d_set(nullptr);
@@ -419,43 +427,32 @@ void Camera2D::_make_current(Object *p_which) {
 	}
 }
 
-void Camera2D::set_current(bool p_current) {
-	if (p_current) {
-		make_current();
-	} else {
-		if (current) {
-			clear_current();
-		}
-	}
-}
-
 void Camera2D::_update_process_internal_for_smoothing() {
 	bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint());
 	bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0;
 
-	bool enabled = is_any_smoothing_valid && is_not_in_scene_or_editor;
-	set_process_internal(enabled);
-}
-
-bool Camera2D::is_current() const {
-	return current;
+	bool enable = is_any_smoothing_valid && is_not_in_scene_or_editor;
+	set_process_internal(enable);
 }
 
 void Camera2D::make_current() {
-	if (is_inside_tree()) {
-		get_tree()->call_group(group_name, "_make_current", this);
-	} else {
-		current = true;
-	}
+	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(group_name, "_make_current", (Object *)nullptr);
-	} else {
-		current = false;
+	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(Side p_side, int p_limit) {
@@ -715,7 +712,10 @@ void Camera2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &Camera2D::set_process_callback);
 	ClassDB::bind_method(D_METHOD("get_process_callback"), &Camera2D::get_process_callback);
 
-	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);
 
@@ -779,7 +779,7 @@ void Camera2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "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, "ignore_rotation"), "set_ignore_rotation", "is_ignoring_rotation");
-	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", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");

+ 4 - 2
scene/2d/camera_2d.h

@@ -64,7 +64,7 @@ protected:
 	Vector2 zoom_scale = Vector2(1, 1);
 	AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
 	bool ignore_rotation = true;
-	bool current = false;
+	bool enabled = true;
 	real_t position_smoothing_speed = 5.0;
 	bool follow_smoothing_enabled = false;
 
@@ -88,7 +88,6 @@ protected:
 	void _update_scroll();
 
 	void _make_current(Object *p_which);
-	void set_current(bool p_current);
 
 	void _set_old_smoothing(real_t p_enable);
 
@@ -155,6 +154,9 @@ public:
 	void set_process_callback(Camera2DProcessCallback p_mode);
 	Camera2DProcessCallback get_process_callback() const;
 
+	void set_enabled(bool p_enabled);
+	bool is_enabled() const;
+
 	void make_current();
 	void clear_current();
 	bool is_current() const;

+ 19 - 0
scene/main/viewport.cpp

@@ -1045,6 +1045,25 @@ Transform2D Viewport::get_final_transform() const {
 	return _get_input_pre_xform().affine_inverse() * stretch_transform * global_canvas_transform;
 }
 
+void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
+	List<Node *> camera_list;
+	get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
+
+	Camera2D *new_camera = nullptr;
+	for (const Node *E : camera_list) {
+		const Camera2D *cam = Object::cast_to<Camera2D>(E);
+		if (cam->is_enabled()) {
+			new_camera = const_cast<Camera2D *>(cam);
+			break;
+		}
+	}
+
+	_camera_2d_set(new_camera);
+	if (!camera_2d) {
+		set_canvas_transform(Transform2D());
+	}
+}
+
 void Viewport::_update_canvas_items(Node *p_node) {
 	if (p_node != this) {
 		Window *w = Object::cast_to<Window>(p_node);

+ 1 - 0
scene/main/viewport.h

@@ -511,6 +511,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 gui_set_root_order_dirty();