godot: The position of a node is not _ready when used inside any "Container" node
Tested versions
- Reproducible in Stable 4.2, Windows 10
Issue description
Any type of “Control” node, when used within any type of “Container” node, fails to provide correct node.position when _ready
is called. However, _process
is able to print the correct position, implying there’s something happening between _ready
and _process
that makes thenode.position
correct.
If a node calls _ready, I think it’s fair to assume that the Node’s data, including it’s position
, is ready, which in this case it is not. There’s no mention in the docs that a node would call _ready, but not actually be ready, so I can only assume this is a bug.
It might also be worth noting in case it’s not clear, but it also affects @onready variables too. If you do something like @onready var panelposition = self.position
, it’ll return (0,0) even if it actually does have a position set manually.
Steps to reproduce
- Create a new project
- Create a
CanvasLayer
, and set it to full-rect to fill the screen - Add any type of “Container” node (found under
Node > CanvasItem > Control > Container
). I personally used aMarginContainer
- Add any other type 2D node as a child. I personally used a
PanelContainer
, but you can use anything; a TextureRect, Panel, whatever. - Make sure you move position this node out of the top left corner. I personally just anchor it to the middle of the parent.
- Attach a script to this new child (from step 4), and in the
_ready
function print the position of the node. There are several methods, but I usedself.position
. You’ll find that it will return (0, 0) - Upon right-clicking the MarginContainer, and changing it’s type to something other than a Container node, that the console will output the correct value for the child node now. Equally, you can also add a line to the top of the
_process
function of the script we made in Step 6 that returns the position, because as soon as the first_process
is called, the data is somehow correct.
Minimal reproduction project (MRP)
About this issue
- Original URL
- State: closed
- Created 6 months ago
- Comments: 18 (10 by maintainers)
In the future remember the code of conduct and remain constructive, this is not the place for venting frustration 🙂
Note that it shouldn’t be surprising that a node can’t know its position before all the siblings are added, as they affect the container, though in this case the
_ready
of the container itself isn’t enough as it is deferred, though even then you can’t know it, because the container might itself resize based on its siblings, and so on, so there is no possible way to know this at_ready
for the node itselfThis is for a very valid and good reason, performance, sorting should only be done once per frame unless specially ordered, otherwise every little movement in a script would slow things down, right? It would also cause bugs with a node suddenly being moved while you’re still manipulating it
This would be good to document further, but it’s far from as unreasonable as you present it, regardless of your inappropriate tone
@tocruise As a 3rd party who has been seeing this pop up in my feed, I can’t see how you keep saying AThousandShips is not constructive (nor can I tell why they thought you were just “venting frustration” at first - before the thread was closed)
Thread was closed as a duplicate of another issue, not because of “frustration” or anything like that. AFTER the thread was closed, two of your comments are just rants, “crazy how that can happen” and similar passive-aggressive things.
One final note: As someone who spend a lot of time with bug evaluation and identification, volunteering my time with no reward other than helping people and making this a better engine, it’s not very helpful or enjoyable to see people vent their frustration that things don’t work or that things are bad
I understand that it can be frustrating when things don’t work as you expect, but that’s no reason to vent this frustration here when people are here to help and to explain things
I’m not saying this as a “oh you have to love this engine!”, but considering the enormous time of our spare time me and so many others give to this project it’s tiresome when people come into these channels with frustration, especially in cases where that frustration is actually not due to anything not working correctly, as in this case
There’s a reason why the code of conduct asks that you don’t vent frustration but remain constructive, I ask that you respect that
I am sorry that you took my response this personally, but that is genuinely none of my fault, so I ask you to take a step back
Again, have a good day
This doesn’t seem to be exposed to GDScript. There are
pre_sort_children
andsort_children
signals that might be useful though (https://docs.godotengine.org/en/stable/classes/class_container.html#signals).About using deferred calls, a cleaner way to do it is to use
await
:Can you share your use-case for needing to know the node’s position? The
Container
’s job is to handle all positioning of it’s child elements, so it could be argued that a reliable way to know a final node’s position is not needed, and that you might be using the wrong node for what you’re doing.Please, take a step back, all I did was tell you to be constructive and not vent your frustration but be constructive, and explained to you in calm and clear ways why this makes perfect sense and how what you expect simply isn’t how things do or could work, how you turn this into me attacking you or being passive aggressive I can’t understand
I simply stated that your literal expression of frustration has no place here, and yes, saying “confusing” instead of “infuriating” would be more constructive
You could just have responded to this by saying that you understand that this isn’t about your frustration over things, but instead you turned this into two enormous walls of text decrying that I explained and asked you to be constructive instead of venting your frustration, or accusing me of closing this issue to silence you, instead of it being a duplicate of another issue that covers this exact topic
Good day
Closing as a duplicate of:
Which is the same issue, thank you for reporting
Okay, so another day of experimenting and I’m getting there…
I first attempted to use deferred calls, which had it’s own set of inconsistencies. For some reason, deferred calls are able to set some variables and not others. For example, if I had a
node.position = x
and amove_now = true
statement in the same deferred fucntion call, theprocess
function would know themove_now
bool had updated totrue
(which is correct), but not that theposition
also had (which doesn’t make sense because they’re happening in the same function. Super weird stuff. I’ve yet to find an answer as to why that is.get_tree().process_frame.connect(function_name, CONNECT_ONE_SHOT);
seems to be the answer to the question above. It’s a roundabout, hacky way to get information that should be available at the get-go, but oh well, here we are. For some reason, this has also introduced it’s own set of problems, like theposition
of nodes not being correct if their parent is not immediately visible from application launch. As for why that’s happening, I have no idea. Another one for the docs, I guess. Maybe it’s just me, but “visible” surely just means not visible, as in, simply not drawn on the viewport. The fact that in the process of not drawing it that it also just neglects to do a ton fo other things is really unfuriating - infuriation that wouldn’t exist if the docs actually explained what functions did in detail. The “visible” method under CanvasItems in the docs says nothing about data inconsistencies when a node is not visible. This is like the whole_ready
discussion above, where ‘ready’ doesn’t actually mean ‘ready’, it just means ‘kinda-ready’.It’s getting a bit tiresome at this point that so many of these functions work in ways you don’t expect them to, and the docs mention nothing of it, so I’m just left to sift through hundreds of github issues and reddit posts, looking for some other unlucky developer who’s had the misfortune of trying to do something so basic and primitive in this engine and has not been able to pull it off. Anyway, my answer is here for anyone who stumbles on it. This is how I got around it. I think this’ll likely be my last comment until it’s picked up and tagged as a bug/improvement. Cheers
Maybe it’s just me, but that seems like a huge oversight. The
_ready
function, which is arguably the main function of nodes, cannot recall the position of a container node under any circustmances? I feel like the general user assumes that when_ready
is called, the node has already reached that position, especially when the node editor shows that position in the inspector. You definitely don’t expect it to not be in the position that it’s been set to by the time_ready
is called. Sorry, maybe I’m repeating myself here, but I’m just trying to be clear in case this does become part of the docs.@rsubtil I guess at this juncture, the only thing I can do is work around it. Is there anyway to access that sorting function you mentioned, so that I could include new code? So that, for example, I’d be able to save the position or set the position of a node after it’s been re-positioned. Or would the only real way of doing this involve setting up some kind of bool switch in the
process
function that runs once and then switches off for futureprocess
calls? I ask because if this is genuinely intended behavior, which as you describe it it sounds like it might be, how did the developers of these functions intend for people to get positions of their nodes when they’re inside containers? I mean, surely they thought about that. I don’t think it’s a huge ask to want to to be able to set/get the position of a node when it exists within another one of the most common nodes. I can’t imagine that’s going to be a rare occurance at all given that Container nodes are so prevalent. I’m genuinely baffled this hasn’t been raised before (or maybe it has and I just can’t find the thread).Yeah, but what’s really happening is that
Container
s defer node sorting (the process of re-positioning the children nodes) to the next frame, so you’re not able to know the node’s final position at that stage. I agree that this should be documented better.