fix: Avoid accidental PCam3D.up_target invalidation - #673
Conversation
| # else: | ||
| # _follow_target_output_position = target_position + transform.basis.z * follow_distance | ||
| # var unprojected_position: Vector2 = _get_raw_unprojected_position() | ||
| # var viewport_width: float = get_viewport().size.x | ||
| # var viewport_height: float = get_viewport().size.y | ||
| # var camera_aspect: int = get_viewport().get_camera_3d().keep_aspect | ||
| # var visible_rect_size: Vector2 = get_viewport().get_visible_rect().size | ||
|
|
||
| # unprojected_position = unprojected_position - visible_rect_size / 2 | ||
| # if camera_aspect == Camera3D.KEEP_HEIGHT: | ||
| # # Landscape View | ||
| # var aspect_ratio_scale: float = viewport_width / viewport_height | ||
| # unprojected_position.x = (unprojected_position.x / aspect_ratio_scale + 1) / 2 | ||
| # unprojected_position.y = (unprojected_position.y + 1) / 2 | ||
| # else: | ||
| # # Portrait View | ||
| # var aspect_ratio_scale: float = viewport_height / viewport_width | ||
| # unprojected_position.x = (unprojected_position.x + 1) / 2 | ||
| # unprojected_position.y = (unprojected_position.y / aspect_ratio_scale + 1) / 2 | ||
|
|
||
| # viewport_position = unprojected_position | ||
| # _set_follow_gizmo_line_position(follow_target.global_position) |
There was a problem hiding this comment.
Good catch! Did a interpolation refactor recently, but must have missed this part.
It's fine to delete entirely rather than just commenting it out.
| if not Engine.is_editor_hint() or \ | ||
| Engine.get_singleton(&"EditorInterface").get_edited_scene_root() == owner: |
There was a problem hiding this comment.
Wouldn't Engine.is_editor_hint() suffice here given EditorInterface is only accessible in the editor anyway? Cannot seem to repro the issue when just using Engine.is_editor_hint() at least.
There was a problem hiding this comment.
It doesn't quite help, at least on my end. It's not a matter of being in editor or not, it seems to be the fact that the node is "exiting tree" when you change tabs. Attaching an example of trying three different approaches on my end.
Could it possibly be device/OS specific? My Godot's v4.7.1.stable.arch_linux. Any other information I could provide to help?
2026-08-08_02-32-04.1.mp4
There was a problem hiding this comment.
Sorry for the delay, I think the most sensible thing would be to do the same as how the _follow_target_tree_exiting does it, which is just:
func _up_target_tree_exiting() -> void:
_has_up_target = falseThat should address it?
There was a problem hiding this comment.
That addressed it, but also happened to print out the following error on save if the node's been deleted (though this did not happen again if the scene was closed and reopened).

I added a NOTIFICATION_EDITOR_PRE_SAVE check in _notification() so that it clears out the variable too if it finds it's both set and outside the tree, essentially moving the original up_target = null there. (1f6d2d4)
This fixes the issue on my end: the up_target persists on scene change, and it no longer prints this error.
Would this be a preferable approach?
The
PCam3D.up_targetproperty was getting invalidated when changing scenes in the editor.Added a check to determine if the node is actually in the process of exiting the scene or if its
tree_exiting()signal fired as part of a scene change in editor.We began using this feature a decent amount for trippy scenes in our game and noticed we had to keep setting the property over and over. Thought it was an inherited scene or extended script issue but was able to replicate the issue in dev_scene_3d.tscn too.
I also took the liberty to comment out a portion of the script that was making the script unable to parse (I assumed it was an older implementation).