-
-
Notifications
You must be signed in to change notification settings - Fork 21.5k
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
Refactor Camera2D to separate property and display updates #63773
base: master
Are you sure you want to change the base?
Conversation
poke poke? |
This looks great. 👍 I'm wondering whether it would be possible to have separate commits (or separate PR, and then build on it in this one?) for the existing forward ports of the 3 PRs from 3.x, then a separate PR for the improvements here? That might make it a little easier to review. |
If you plan on reviewing them, I don't see why not. cc @madmiraal Can you split your work into forward ports and enhancements? |
scene/2d/camera_2d.cpp
Outdated
if (current) { | ||
clear_current(); | ||
} | ||
clear_current(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the point of this that if current
is false, there's no need for clear_current()
to call_group
etc?
i.e. should there be a noop check at the top?
if (p_current == current) return
or something like that? Or must it be bypassed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, call_group doesn't need to be called. In fact, it will remove any current camera, which is probably not desired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I've updated the PR with a refactored set_current()
to make things simpler and clearer.
Basically, when calling set_current(true)
it now calls _clear_current()
on all cameras in the Viewport
, which just sets current
to false
and redraws
it; It then sets this camera to be current.
When calling set_current(false)
it just sets this camera to not be current.
Generally it looks pretty good I think. Probably would benefit from @KoBeWi or anyone else having a look through too. Will require a bunch of testing with 2D projects in 4.x, and I can't really do this easily, I'm presuming @madmiraal has done this as much as possible. I suspect ultimately it will probably have to be tried as one of those YOLO merges, and then watching for regressions, as the logic and order of operations are quite fiddly. But I agree it is worth refactoring and cleaning up Camera2D at this stage, before it becomes too difficult to change. 👍 |
Needs rebase to make testing easier. EDIT: |
// Separate the logic between enabled and active, because the smoothing | ||
// cannot be active in the editor. This can be done without a separate flag | ||
// but is bug prone so this approach is easier to follow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could just add an inline method is_smoothing_active()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine too. (That was ported from my PR actually lol 😁 ).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is from the forward port of #46717.
95df941
to
cae78d5
Compare
6f6eb6f
to
5d3da8f
Compare
5d3da8f
to
19d2bdb
Compare
Would be good to reach consensus on whether this can be merged soon for 4.0. There have been a few other minor compat breaking changes to the Camera2D API in the meantime (rotation smoothing, possibly further renaming of (follow) smoothing: #65779) which would need to be integrated too. Feedback welcome from more users and contributors too to make sure this is what we want the Camera2D API to be like in 4.0. From a cursory look it seems to make sense to me but I'm no expert nor heavy user. |
We sadly didn't really reach further consensus on this and it's too late to assess/merge now for 4.0, which is close to RC stage. Let's aim to review/address those issues for 4.x, and see how to handle compatibility breakage (either accept to break compat anyway in a future 4.x release, or preserve it somehow if it doesn't make the API too awkward). |
This doesn't fix #44358, but it shouldn't need to. |
Currently, almost any property change to
Camera2D
and almost all internal notifications call_update_scroll()
which updates theViewport
transform by calling_get_camera_transform()
. However,_get_camera_transform()
is responsible for:Viewport
's newTransform2D
This causes updates and recalculations to occur not only unnecessarily, but also undesirably. For example, changes to
Camera2D
's properties shouldn't cause updates to the current screen position. Therefore, currently, every time a property is updated, the changes to the current screen position need to be undone (see #2764, #39567, #63580 required to fix #2074, #16323 and #63083 respectively). Furthermore, making_get_camera_transform()
responsible for everything results in various difficult to troubleshoot bugs (see #44358, #56336, #63330, #63572, #63738, etc.). To make matters worse, users callforce_update_scroll()
or even the hidden, but bound, method_update_scroll()
to try workaround bugs.This PR refactors the
private
methods_update_scroll()
and_get_camera_transform()
and adds:void _update_viewport()
void _update_size()
void _update_position()
_update_position()
is used to update the camera's target position based on theNode2D
position and adjusted for drag margins and limits. It is called every time the position is updated or any of the properties (drag margins and limits) that affect the target position are changed._update_scroll()
is now only called by the internal process notifications and only does anything whensmoothing_enabled
istrue
. It is used to close the gap between the current camera position and the target position in a consistent manner._get_camera_transform()
now only calculates theViewport
transform based on the current camera position, zoom and, ifrotating
istrue
, rotation._update_viewport()
is used instead of_update_scroll()
to update theViewport
or the editor._update_size()
is used to update the newscreen_size
variable when the screen size or zoom changes; instead of recalculating it every time it is needed.This PR also includes forward ports of:
In addition, some internal variables have been renamed to make them easier to understand:
camera_pos
->target_position
smoothed_camera_pos
->current_position
smoothing
->smoothing_speed
(along with its getter and setter)first
->initialised
(and reversed the logic)And unneeded methods have been removed or unbound:
_get_camera_screen_size()
: removedforce_update_scroll()
: removed_update_scroll()
: unboundFixes #44358
Fixes #49747
Fixes #63572
Fixes #63738
Closes #56336
This PR also includes some additional enhancements:
Viewport
size is larger than the camera limits, which can happen when zooming out, it interpolates the camera position between the limits; instead of the current arbitrary behaviour (Camera2D limits don't clamp camera position #62441 (comment)) of locking it to the top-right corner due to the internal order of calculation.smoothing_speed
between 0 and 60 and drops the incorrectpx/s
suffix.smoothing_speed
to describe it as the speed is in pixels per second when it isn't, it also makes some minor documentation updates to hopefully make other methods and properties clearer.