Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invert Camera2D zoom back to Godot 3 behavior #5525

Closed
ettiSurreal opened this issue Oct 1, 2022 · 13 comments
Closed

Invert Camera2D zoom back to Godot 3 behavior #5525

ettiSurreal opened this issue Oct 1, 2022 · 13 comments

Comments

@ettiSurreal
Copy link

ettiSurreal commented Oct 1, 2022

Describe the project you are working on

Nothing major at the time of rewriting.

Describe the problem or limitation you are having in your project

godotengine/godot#57392, inverted the zoom behavior. While more intuitive with the term this introduces several problems.

  • Lower precision for zooming out, although I'm not sure if it's at all practical.
  • Can be harder to work with, for example when making a camera that zooms out with velocity.
  • Is now always exponential. This makes problems like the above worse, and makes precise control impossible in AnimationPlayers or Tweens without using an inverse script like the one provided.
  • Is now inconsistent with Orthogonal Size in Camera3D.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Revert the zoom change or add a built in workaround.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Potential solutions:

  • Revert the zoom to the old behavior. Possibly rename to size since that might be more telling how the property works.
  • Add a toggle that switches between behaviors.
  • Have two properties that control the camera zoom, size and zoom, which are inverse of each other but are applied additively.

If this enhancement will not be used often, can it be worked around with a few lines of script?

This script creates a new property that controls zoom, and it's functionally identical to how zoom worked pre-4.0. Note that changing zoom directly will not update size to be equivalent, so you should avoid that.

@tool
extends Camera2D

@export_custom(PROPERTY_HINT_LINK, "size") var size: Vector2 = Vector2.ONE:
	set(incoming):
		size = incoming
		if incoming.is_zero_approx(): # can omit this if you can make sure size is never zero
			incoming += Vector2(0.00001, 0.00001)
		zoom = Vector2.ONE / incoming

Is there a reason why this should be core and not an add-on in the asset library?

Changing the functionality of a built in node.

@Mickeon
Copy link

Mickeon commented Oct 1, 2022

Very important proposal. This is one of those times where being technically accurate and intuitive harms the because of how difficult it is to make use of.

I concur. Although, the property should have its name changed to make sense. zoom_scale could be ideal.

@Calinou
Copy link
Member

Calinou commented Oct 1, 2022

camera.zoom.x = 1 - abs(linear_velocity.length()) * 0.0002
camera.zoom.y = 1 - abs(linear_velocity.length()) * 0.0002
Zoom out code in 4.0 Beta2, it really is the inverted code i mentioned above, although i have to work with very small floats to achieve a similar result.

This is not the inverted zoom. The inverted zoom would be setting the zoom to 1.0 / (abs(linear_velocity.length()) * 0.0002).

@ettiSurreal
Copy link
Author

camera.zoom.x = 1 - abs(linear_velocity.length()) * 0.0002
camera.zoom.y = 1 - abs(linear_velocity.length()) * 0.0002
Zoom out code in 4.0 Beta2, it really is the inverted code i mentioned above, although i have to work with very small floats to achieve a similar result.

This is not the inverted zoom. The inverted zoom would be setting the zoom to 1.0 / (abs(linear_velocity.length()) * 0.0002).

That causes a division by zero as the rigidbody velocity starts as it.

@Calinou
Copy link
Member

Calinou commented Oct 2, 2022

That causes a division by zero as the rigidbody velocity starts as it.

You need to use clamp() to clamp the divisor to reasonable values 🙂

@ettiSurreal
Copy link
Author

Since some users seem to prefer the 4.0 behavior, i tried making a solution that hopefully gets the best of both worlds :)
#5532

@tivtag
Copy link

tivtag commented Nov 6, 2022

Agree on this proposal.

As a newcomer trying to port a Godot 3.5 2D game to Godot 4 this change didn’t make it easier. Before trying to port my game again, I will wait on what is decided about this task.

Any more opinions? Cheers :-)

@kleonc
Copy link
Member

kleonc commented Nov 6, 2022

camera.zoom.x = abs(linear_velocity.length()) * 0.2 + 1
camera.zoom.y = abs(linear_velocity.length()) * 0.2 + 1
Zoom out code in 3.5, the effect can be easily inverted by just inverting the absolute of the velocity or subtracting it from 1 instead.

camera.zoom.x = 1 - abs(linear_velocity.length()) * 0.0002
camera.zoom.y = 1 - abs(linear_velocity.length()) * 0.0002
Zoom out code in 4.0 Beta2, it really is the inverted code i mentioned above, although i have to work with very small floats to achieve a similar result.

@ettiSurreal What you're saying is not true, that's not how you invert a value.

This is not the inverted zoom. The inverted zoom would be setting the zoom to 1.0 / (abs(linear_velocity.length()) * 0.0002).

@Calinou That's also not correct.

The inverse of a non-zero v value is 1.0 / v. It's as simple as that.

So for:

camera.zoom.x = abs(linear_velocity.length()) * 0.2 + 1
camera.zoom.y = abs(linear_velocity.length()) * 0.2 + 1

which is guaranteed to be non-zero and which is equivalent to (as the length of a vector can't be negative):

camera.zoom.x = linear_velocity.length() * 0.2 + 1
camera.zoom.y = linear_velocity.length() * 0.2 + 1

the inverted zoom would be:

camera.zoom.x = 1.0 / (linear_velocity.length() * 0.2 + 1)
camera.zoom.y = 1.0 / (linear_velocity.length() * 0.2 + 1)

which can be rewritten as:

camera.zoom = Vector2.ONE / (linear_velocity.length() * 0.2 + 1)

So if that 0.2 is a value exposed for tweaking then nothing would change from the "what I need to tweak" point of view. Inverting or not, the parameters for the formula used to calculate the zoom will remain the same, they won't suddenly become a very small floats.

The final Camera2D.zoom can become very small indeed but this will always be the case, whether the zoom means zoom_in_factor or zoom_out_factor.

To me it seems like this proposal is a result of inability to invert the calculations and that's pretty much it. Now such inability caused problems when trying to zoom out but the same problems would occur in 3.x when trying to zoom in.

And making the property's name (zoom) match the intuitively expected behavior was already discussed in #3888 and the result is the current state of things.

@WhalesState
Copy link

WhalesState commented Mar 27, 2023

i also report that this is so hard to work with, why don't we have both ? Camera2D.zoom_scale which behaves like the new zooming algorithm and the old zoom which remains as Camera2D.zoom to not break the old projects zoom system ?
look at how hard is it to manage zoom to mouse position now

func cam_zoom(v: float):
	var old_zoom := zoom.x
	var new_zoom := old_zoom + v
	new_zoom = clamp(new_zoom, 1, 64)
	var cur_pos = -get_viewport_rect().size / 2 + get_viewport().get_mouse_position()
	zoom = Vector2(new_zoom, new_zoom)
	offset -= cur_pos / new_zoom - cur_pos / old_zoom

while in godot 3x we used to do this

func cam_zoom(v: int):
	var old_zoom = zoom
	var vp_size = get_viewport().size
	zoom += (Vector2(0.1, 0.1) * zoom) * v
	var mpos = get_viewport().get_mouse_position() 
	offset -= (-vp_size/2 + mpos) * (old_zoom - zoom)

anyway, I'm ok with both behaviors, but the old zoom behavior was easier to work with, also the new behavior seems to be a scale behavior more than a zoom one.
why don't we have both that affects each others ? Camera2D.scale, and Camera2D.zoom ?.

@Mickeon
Copy link

Mickeon commented Mar 27, 2023

why don't we have both that affects each others ? Camera2D.scale, and Camera2D.zoom ?.

I want to note that it can't be Camera2D.scale because the scale property is already inherited from Node2D with a whole different usage.

@WhalesState
Copy link

I want to note that it can't be Camera2D.scale because the scale property is already inherited from Node2D with a whole different usage.

Camera2D.zoom_scale and Camera2D.zoom ?

this will help to keep Godot 3 projects compatible with Godot 4.

@ettiSurreal
Copy link
Author

ettiSurreal commented Nov 10, 2024

To anyone stumbling onto this having similar problems, after having one too many issues with this behavior (like the zoom now behaving exponentially) I had a light bulb pop up above my head and just made a simple script that effectively brings back the old behavior under a different property. I love setters.

@tool
extends Camera2D

@export_custom(PROPERTY_HINT_LINK, "size") var size: Vector2 = Vector2.ONE:
	set(incoming):
		size = incoming
		if incoming.is_zero_approx(): # can omit this if you can make sure size is never zero
			incoming += Vector2(0.00001, 0.00001)
		zoom = Vector2.ONE / incoming

@Mickeon
Copy link

Mickeon commented Nov 10, 2024

Should this issue be closed then, or should it be kept open for future reference? Closing an issue doesn't mean it can't be referenced.

@ettiSurreal
Copy link
Author

I believe so, I'm personally satisfied with my workaround for the time being (the one issue that might pop up is if I need a Camera2D to have a script that doesn't inherit from it, but that shouldn't be too hard to avoid.
Regardless if this becomes a topic of discussion again this can always be re-opened, and if it does I'm still in full support of it. In case it does I rewrote the original proposal to be more "to the point" (and also because I'm now kind of embarrassed by the way it was originally written).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants