Currently _ready() is called every time the node enters scene tree.
People tend to use _ready as a constructor, but in some situations it can be harmful since sometimes there is need to reparent node or disable it (by removing it from the scene tree for some time).
My proposition is to add additional boolean parameter to _on_ready that will indicate if this is a first ready call for given node.
Potentially related issue: https://github.com/godotengine/godot/issues/1905
It would be better actually to add something different that can achieve this easily.
I would recommend adding a 'static' keyword that works the same as C++.
This way you can setup a flag that turns to true and skip portion of code accordingly.
This would be useful too, to count the number of scenes currently instanced by
making a static counter in the _ready().
AFAIK gdscript doesnt support globals scope in scripts (autoload is an exception).
But static variables have different scope than globals.
But if this is not gonna happen, I wonder if implementing something a kin to std::once_flag
Is feasible in GDscript. Or even something like call_once()
i think for the rare cases when you remove nodes from the scene you can add
a boolean, it's not that common to remove and readd nodes
On Sat, Jan 9, 2016 at 2:45 PM, RebelliousX [email protected]
wrote:
It would be better actually to add something different that can achieve
this easily.
I would recommend adding a 'static' keyword that works the same as C++.
This way you can setup a flag that turns to true and skip portion of code
accordingly.This would be useful too, to count the number of scenes currently
instanced by
making a static counter in the _ready().AFAIK gdscript doesnt support globals scope in scripts (autoload is an
exception).
But static variables have different scope than globals.But if this is not gonna happen, I wonder if implementing something a kin
to std::once_flag
Is feasible in GDscript. Or even something like call_once()—
Reply to this email directly or view it on GitHub
https://github.com/godotengine/godot/issues/3290#issuecomment-170264349.
I agree, a simple boolean would suffice for this.
Well it looks my project is quite specific since it's quite common situation for me in many places. I use it to disable some functions of a scene (remove some logic-component for some time), or change behaviour (like on FSM state change), by replacing some nodes with other ones. Also other unrelated to FSM situations like ability to define what a wooden chest should drop when it's opened (my wife is adding items/weapons in a child node of chests, they are cached by chest in ready, then thrown on the floor inside 'temporary rigid body holder', hero can pick them up, sometimes put in the backpack, from backpack to the hand etc). Some of the scenes in my project even serve as 'repository/prorotype factory' that stores/defines items and so we can calibrate parameters in the editor and duplicate them during runtime... (something similar to prototype factory pattern if I remember corretly).
As it seems to be to much specific on how I'm using the editor I will close the issue in a couple days if there will be no more interest in it.
I'm not sure that it is not common. It certainly depends on the workflow, since this question was raised a few times by different people. @kubecz3k's example makes the use clearer, and adding a boolean flag manually in all of the scripts seems wrong to me. You can't even use inheritance since there's no guarantee that all nodes will be of the same type.
As an alternative to the boolean parameter, there could be a _first_ready() virtual function that runs only on the first _ready().
The possible overhead of this is that the boolean flag will still have to exist and it'll be in every node, even of those that aren't making use of it.
I think the point is valid: a kind of constructor that runs when the tree below is already there. Just don't know the proper way to implement it.
maybe we could add a counter for how many times the node was added into a
scene?
On Sat, Jan 9, 2016 at 4:32 PM, George Marques [email protected]
wrote:
I'm not sure that it is not common. It certainly depends on the workflow,
since this question was raised a few times by different people. @kubecz3k
https://github.com/kubecz3k's example makes the use clearer, and adding
a boolean flag manually in all of the scripts seems wrong to me. You can't
even use inheritance since there's no guarantee that all nodes will be of
the same type.As an alternative to the boolean parameter, there could be a
_first_ready() virtual function that runs only on the first _ready().The possible overhead of this is that the boolean flag will still have to
exist and it'll be in every node, even of those that aren't making use of
it.I think the point is valid: a kind of constructor that runs when the tree
below is already there. Just don't know the proper way to implement it.—
Reply to this email directly or view it on GitHub
https://github.com/godotengine/godot/issues/3290#issuecomment-170273401.
While I do agree that a simple boolean can solve the issue, but I don't like the idea of
polluting the namespace, defining variables outside functions is really bad when projects get
bigger.
But I believe it all stands on the designing phase of the mechanics of the game you are implementing.
Each instance has its own state machine controled by a bigger state machine, how objects
interact with each other, modifying their state each frame. It gets hairy and scary with potential some hundred boolean variables and big if-else statements for the flags of the bigger state machine, saving and loading those flags when user want to resume the game at later time.
@reduz function that returns a counter would do the trick but I think it would be a good idea to give a strong hint to new users that _ready should not always be seen as an constructor. I remember my confusion many months ago when I discovered that I had bugs because _ready is called every time when node enters tree (I thought _enter_tree call was for that, and while currently I know they are slightly different I think it might be confusing for new users). But just like @vnen I'm not sure what is the best way to solve this issue. The idea with new _first_ready() is good and bad at the same time, since for new users it might be confusing on it's own that there are two ready functions... but maybe it could be minimized by changing _first_ready() to _init_in_tree() (since ordinary constructor is called _init()).
I'm not sure maybe I'm over-thinking this, and simple counter would be the best after all?
Or do everything and let user choose: add _first_ready() as well as function that returns counter..
See also the related discussion in #1949.
maybe related to #2657
Isn't there an _enter_tree() function for all Nodes? So if _ready() is called every time you enter tree is there a difference between the two function ?
EDIT: what abouton ready does it also run every time you enter a tree? That would seem like all those variables would get reset when a node is added and removed.
EDIT2: seems the only difference is _enter_tree() is called before _ready() according to docs
I support @kubecz3k 's idea. Seems according to the docs not only you have 2 redundant functions but also a really useful function like on ready is called every time you enter and re-enter the tree resetting your variables.
_ready() should be called only once and only if it has already entered the tree. In this sense it would become an "in-game constructor" function rather than a regular constructor.
Also the flaw with the custom boolean is on ready vars will still reset and there's nothing you can do about it unless you avoid it altogether.
A lot of people including myself seem to use these as constructors when your node is in the tree. Because there's no point in instantiating variables until your node is added to the game but there's deff no point in instantiating variables over and over every time you add and remove the node. I can just make brand new objects for that purpose if I wanna start fresh.
At this point I personally don't use _ready function at all. I'm also not using _init() either - because inside init it's impossible to use get_node to fetch internal nodes.
Instead I'm using following template in my scripts:
func _notification(what):
if (what == NOTIFICATION_INSTANCED):
#all internal initialization, you can use get_node here to get internal nodes and object will be to some degree usable even if not added yet to scene tree
#it's called after object construction, at this point object is not even inside scene tree
#also it's called only once
pass
elif(what == NOTIFICATION_READY):
#only parts that are dependent on outside world (on theparents etc/also called when reparented)
#usually it's quite ok to update external references if object is reparented so it usually works ok without any further thinking
pass
It's the only way for me to have more or less error prone code with my habit of spontaneous re-parenting nodes when after some time I decide it's easier this way for some cases :) The only problem with this approach is lack of auto-completion for internal nodes that were fetched during INSTANCED notification.
@trollworkout: [...]but there's deff no point in instantiating variables over and over every time you add and remove the node. I can just make brand new objects for that purpose if I wanna start fresh.
While you may want something to initialize only once, sometimes you need to reinitialize stuff when entering the tree again. E.g. if you have a Bullet node and your game have a lot of bullets flying all the time, it's better performance-wise to make an object pool rather than destroying/recreating everything.
_enter_tree() does not cut it as there's no guarantee that the children are initialized. Actually, I see no real use for _enter_tree(). If it performed like _ready(), then I'd agree with the change.
@kubecz3k maybe if we add a _instanced() virtual function that runs when NOTIFICATION_INSTANCED notification arrives it would solve all problems. Also an oninstanced keyword akin to onready. Though it might be still a problem if you need info from parent nodes.
@vnen oninstanced and instanced() would be fine with me
@vnen well it's not the most straightforward solution for new people (not sure when they should learn about the difference between ready and instanced). For me personally it would be nice, since this is what I'm doing currently and I would have auto-completion thanks to this. But in the end it's not about me, and I'm not sure if there is sense to add that kind of api when no-one else is doing stuff this way :) (not sure how many people would really benefit) From the other site maybe it's not so drastic change and some people would benefit after all? As I said, I'm not sure :)
This issue is addressed in #7138, but I don't think it's the right way
Not calling _ready when reinserting is confusing. In my opinion the Node class by itself has no need to expose the first insertion as a special case.
If one desires to remove and reinsert Nodes, some understanding of out-of-tree operations is required. Adjusting _ready to encourage ignoring this fundamental system will just lead to worse code.
Well written Node classes don't care how often they've been inserted or removed. They use callbacks to adjust their state, usually using _enter_tree, _readyand _exit_tree for in-tree operations and NOTIFICATION_PARENTED, _UNPARENTED and _INSTANCED to handle out-of-tree operations.
If this confuses new users, we should improve the documentation to explain that custom node state has to be cleaned up (prepared for reinsertion) in _exit_tree or NOTIFICATION_UNPARENTED if later reinsertion is desired. Also improve documentation for NOTIFICATION_INSTANCED, _PARENTED, _UNPARENTED and out-of-tree operations in general. Maybe even make some of the notifications available as callbacks
I don't think the system is so complex that we can't document and teach it but build crutches
I agree, I had just misunderstood @bojidar-bg's change in b6eab00 and thought it only addressed the double _ready() call when first initializing a node. This change should likely not have been made in the same PR as a bugfix - unless there's a strong argument for keeping it, I'd propose to revert it until it can be properly discussed.
@eska014 @akien-mga I agreed. _ready() should be called when it's enter tree again. but prevent to call _ready twice when enter tree.
Reverted b6eab00.
Closed by f3f4a11cfb9767e1d691aec431dd2f1a87a31977, since ready is called only once now (but you can use request_ready to get another one :smiley: )
For tool scripts, ready() seems to be called twice: once when adding the node in editor and once when the game runs.
@Zireael07 this is kind of inevitable, because it's added in the tree of the editor and later it is added in the tree of the game. If you want to run some code only in editor, you need to surround with an if get_tree().is_editor_hint().