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

Phantom Camera disappears when re-adding a scene to a tree #253

Open
Paul-Griffin-1517-1 opened this issue Apr 18, 2024 · 6 comments
Open

Comments

@Paul-Griffin-1517-1
Copy link

Paul-Griffin-1517-1 commented Apr 18, 2024

Issue description

In my game, there is a PhantomCamera3D attached to the player and saved as a variable. At one point, the player is removed from the tree, but not freed. At a later point, the player is re-added to the tree.
At this point, the variable that referenced the PhantomCamera3D becomes null, and it becomes difficult to re-assign the variable PhantomCamera3D.
At the very least, it would be good to have an easy way to reassign the variable, since using the node's path (like in the @onready declaration) doesn't work at this point.

Steps to reproduce

Add a node with a PhantomCamera3D child. The PhantomCamera3D should be set to "ThirdPerson" so that it becomes a child of a SpringArm3D at runtime.
In a script on the node, create an @onready variable called phantom_camera that equals the PhantomCamera3D.
EDIT: Make sure the node requests ready(), so that the @onready variable tries to be set when it re-enters the tree.
Remove the node from the tree.
Re-add the node from the tree.
The phantom_camera variable will be empty.

(Optional) Minimal reproduction project

https://github.com/Paul-Griffin-1517-1/PCamBreaker

@ramokz
Copy link
Owner

ramokz commented May 25, 2024

Am not sure if this is an addon issue?

Based on your description, it suggests that you're using remove_child() to remove it from the tree, rather than queue_free(), but it's tricky to give any guidance without knowing exactly how you're removing and readding the nodes.

In any case, have you tried creating a reference to the PCam3D using groups instead? Basically, by adding / removing the PCam3D to a group whenever it enters / exits the tree, from the manager script that removes and adds the node, and then reference the group.

@Paul-Griffin-1517-1
Copy link
Author

I have not tried groups. I might give that a go next time it comes up!

@Paul-Griffin-1517-1
Copy link
Author

Paul-Griffin-1517-1 commented May 29, 2024

UPDATE: After several hours of testing, I found the exact step things break. It seems to be an issue with the @onready variable in conjunction with request_ready(); since the phantomcamera path changes when it's set to ThirdPerson (it becomes a child of a springarm3d), it is unable to find it using the original node path. Edited the original post to compensate.
Also added a minimum reproduction project. (Main branch uses the version of PhantomCamera that was newest when I originally posted the bug report. There is also a branch for the latest version of PhantomCamera.)

@ramokz
Copy link
Owner

ramokz commented May 29, 2024

Had a look at the MRP, and the issue isn't related to the addon.

The issue is also present if you were to add any other node as a sibling to the PCam3D node and do the same thing.

Have added a generic Node3D as a sibling:
image

Also included in the playeer.gd script:
image

And you get null references still once it re-enters the tree:
image

image

What you're doing is that you're referencing a node using @onready which grabs a reference to the instance of the node that is referred to, in this case PhantomCamera3D, the moment that node is ready in the tree. The problem you're facing is that the referenced node is moved from the scene tree, so the property value becomes null at that point. Combine that with how the Third Person follow reattaches the PCam to a SpringArm3D node, and you've got a fair bit going on.

You would probably be interested in the addition of #288, as that would simplify finding a given PCam instance.

@Paul-Griffin-1517-1
Copy link
Author

Paul-Griffin-1517-1 commented May 30, 2024

The problem you're facing is that the referenced node is moved from the scene tree, so the property value becomes null at that point.

The value should not be null up until the request_ready() causes the @onready variable to be set again. (Printing out the value while it's not in the tree won't return null until it re-enters.)

Regardless, the linked features (and also the "group" solution) definitely handle the situation! Thanks for pointing those out!

@ramokz
Copy link
Owner

ramokz commented May 30, 2024

The value should not be null up until the request_ready() causes the https://github.com/onready variable to be set again. (Printing out the value while it's not in the tree won't return null until it re-enters.)

This would be an issue you would run into for any node type that you reference using the scene unique identifier, i.e. the % that you add and remove from a scene. Under normal circumstances where you're adding / removing a reference like that from the tree, you would be better off using the relative NodePath, shorthand $PathToNode/NodeName, reference instead. The idea behind scene unique identifier is that, like the name implies, it's unique within the tree it's in. Once you remove it from the tree and readd it, it's now no longer considered the same node, hence why the % wouldn't work, but where a $ would as it cares about the relative path rather than a specific identifier.

That said, even by using the $ shorthand, the issue you're then running into is that you're using a Third Person follow. What it does behind the scenes is that when the PCam3D enters the tree, it will instantiate a SpringArm3D node and reattach itself to that SpringArm3D. It will still have the scene unique reference, as it hasn't left the tree — just re-parented itself.

When you then tell the player node group to leave and then re-enter the scene tree, you're removing the SpringArm3D with the PCam3D nested inside of it. When you readd the player node group, you're then readding the PCam3D nested inside the SpringArm3D node. Which would make referencing $PhantomCamera3D in the @onready declaration invalid, since the PCam3D is now a child of the SpringArm3D, which itself is a child of the player node. It works the first time because you're grabbing the reference before the PCam3D reattaches itself, but consequent references after reentering the scene tree will be invalid and would need to have a specific path referenced.

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

No branches or pull requests

2 participants