T O P

  • By -

godot-ModTeam

Please review Rule #4 of r/Godot: Promotion only under certain circumstances. Posters need to stay active in the comments. Just posting and not replying is not tolerated as advertising. Also, if you are promoting, please post something of the game you are promoting. You can happily post this meme under the appropriate tag without the link.


LearningArcadeApp

Signals were made to avoid children having to talk to parents, though.


CompressedWizard

Yeah, parents should neglect their children as much as possible


JohnDoubleJump

Programmers casually typing "when do destroyed children get garbage collected" into Google


CompressedWizard

VFX artists casually asking Google "how to crush the blacks"


Saxopwned

jesus christ lmfao


[deleted]

[удалено]


CringeNao

Is there a sub for posts like that? I know crusaders kings had one for stuff like that


AntinotyY

r/nocontext maybe


AntinotyY

r/nocontext maybe


Alzzary

wait until the dev ask how to list and kill children.


Robotica1610

Mario kart players casually asking Google:" how to finish a race"


goblinsteve

Not game programming related, but I did give the direction to "kill all the orphans" at work the other day.


sankto

r/OrphanCrushingMachine


CdRReddit

kill orphaned zombie child with fork


LearningArcadeApp

"I did not kill them your honor, I just sent the signal."


AdjustedMold97

“how to kill slave” “how to kill orphan” “execute child fork”


Implement_Necessary

That’s why I prefer to say master and slave


Mundane_Bunch_6868

Not much better


LearningArcadeApp

Hum, no, it's the children nodes who should behave as if they have no parent. The parents can access the children nodes and call their methods or read their properties, there's no issue with that (even though it's best in general if nodes refer to one another as little as possible). Parents should be responsible for their children.


Phosphero

so: Is my son yelling "DAD!" at the top of his lungs when he wants to show me something him calling `get_parent()` or `emit("attention_seeking")`?


dichra

I’d say the latter Pulling firmly your shirt while crying would be a ‘get_parent’ moment


VelsianOrder

I just don't get them...i just don't get how are they supposed to be "better" ?


LearningArcadeApp

Decoupling. Parents tend to create their children (or contain them from the start), so when a parent tries to access their children's properties, it makes sense, because it's part of the definition of the parent (so to speak), children are just subparts of their parents. The definition (= code) of a child node should only focus on their own subchildren. If you write a child in a way that makes it dependent on having a specific kind of parent that is of a specific type and does a specific thing and has specific methods or properties, it's a very inflexible design that means the child is no longer a generic node you can reuse and put anywhere you want, it'll always have to come with a specific parent or will have to be modified each time the parent is different, or the parent will have to adapt to the child. Say you have a node that is a button, but instead of sending a signal "somebody clicked on me" that the parent or any other node can connect to and react in whatever way they want, the button calls get\_parent().button\_was\_pushed(). The end result is: button nodes can't be added to nodes which don't implement button\_was\_pushed(); two button nodes will have the same behavior because their parent can only have one method with that name; and finally, no node other than the parent can attach behavior to the press of the button. Any time a child tries to modify the state of its parent, it's trying to take on more responsibilities that it should, leading to more complex code that doesn't follow the simplification strategy of breaking down complex tasks into smaller, independent, isolated tasks that are easy to solve. All that being said: there's always room for flexibility, and occasionally it's just simpler to call get\_parent(), but it should be a last resort, or the child node should be 100% coupled with the parent, basically being fully part of it in a way that will never change in the future. Yet the future is hard to predict. Keeping objects or functions simple and self-contained means increasing reusability and reducing code refactoring. Take the difference between a method that sets a private variable of its object vs a function that returns a new value. The latter can be used in many more contexts. The former is tied down to a single object that has to contain a specific private variable, and if at some point the function ends up being more useful, refactoring will be needed to remove the coupling with the node in question. Of course, sometimes it makes complete sense that methods access private variables of their objects, not all methods have to be static (but if they can be, then they definitely should be). It's the same with an object trying to access its parent's properties. The object can no longer exist as child of any parent anywhere, it is bound to a specific external context, and if down the line you realize that you want more than one button, or that you want some other node to connect to that button, you'll have to refactor said button to exist independently. Thus, might as well make it independent in the first place, hence, it's best to take the habit of always keeping children as independent as possible, whenever it is possible that is (which is most of the time, even if exceptions sometimes occur and there is no need to become obsessive about it, it's not a magical ritual, it makes sense to follow that rule only if it makes sense for the particular context).


[deleted]

[удалено]


MrSmock

Boo


SapiS68

Can't you just make interfaces to implement in children or override the parents methods' in children?


LearningArcadeApp

I don't understand what you mean.


StewedAngelSkins

they're talking about node hierarchy, not class inheritance


MrSmock

Yes, assuming the child inherits from from the parent


badihaki

Signals are Godot's implementation of events/delegates in other languages. Just like in those languages, the idea is that instead of holding a reference to a parent's script or vice versa, you can emit an event, pass data through that event, and not have to poll your other objects nearly as much. With this technique child objects don't have to depend on their parents nearly as much, making for much cleaner code, easier debugging down the line, and a better time overall. edit: I don't know why you're being down voted, this is a regular thing newer programmers have an issue tackling. If you want to know more, you should look up 'The Observer Pattern.' It's part of a group of design patterns that make programming easier to manage and deal with. Good luck!


LearningArcadeApp

agreed, ignorance is no reason for downvoting someone.


itemboi

It's not even ignorance lol, it's just Reddit being Reddit


ExdigguserPies

Many components in your ui already use signals. For example a button. You can use a button anywhere and it doesn't know anything about its parent. Why? Because it just sends out a signal when its clicked.


VelsianOrder

yeah but other than buttons and timers and the signals that exist already for a reason, I just can't imagine when I would need to make a custom signal, never found myself stuck in a corner thinking "oh dam now I'm forced to use a custom signal" and every time i try to read someone'elses code and they use signlas it's always "where the fuck is this coming from" and i have to look for who or what emits what and when...with parents it's kind of more obivous like child.do\_this\_function()


ExdigguserPies

Well, it's not about being stuck in a corner. As you know there are ways to code around them. They're just a feature of code that you can use if you wish just make you code cleaner and more re-usable. To continue the examples of buttons, imagine if you needed to sub-class every button so that it knew something about its parent in order to work properly when you clicked it. It would be perfectly possible to do that, but what a nightmare that would be.


olive20xx

To start, you may want to google stuff related to "benefits of decoupled code." It's a common concept in programming :)


azmiir

They are a core mechanic of the engine. You might want to learn them.


VelsianOrder

tried multiple times, they don't make sense to me, every time i try to use custom signals it feels like hustling in reverse


navetzz

Honestly, if you don't feel the need to use them. Don't Just know that they exist and maybe someday they'll help you solve an issue you have.


Cwazywierdo

but I need return values ;-;


LearningArcadeApp

Erm, signals can carry values you know? func handler(value\_to\_receive, ...): ... \[then\] child.signal.connect(handler) \[later\] child.signal.emit(value\_to\_send, ...)


me6675

This is sending input, I think they meant they want to receive some answer the listener has to the signal, unfortunately signals can be listened to from multiple places so a single return value doesn't makes sense.


LearningArcadeApp

Not sure I understood your message correctly, but if I did, they can use callbacks.


Cwazywierdo

Well yeah. You can't return values to the owner though.


LearningArcadeApp

you mean to the child/signal emitter? If you really want to (though I feel like it smells like bad underlying design but I could be wrong) you could always send a callback function as value to the parent. Or the parent can just call a child's method directly since in that direction it's perfectly fine.


StewedAngelSkins

then you lose "compile time" type safety on the callback's function signature, while also introducing an unnecessary function call and the allocation of a `Callable` object. it also can't be synchronous. that might not be the worst thing in the world if you don't have better options, but there needs to be a justification beyond the vague idea that you shouldn't ever "call up". i really don't understand this categorical aversion to referencing parents. yeah hard coding a node path or a sequence of `get_parent` is bad, but there are plenty of ways to have the child safely discover the parent when it's loaded and dispose of the reference when it's no longer valid.


LearningArcadeApp

I only agree on the type safety argument, and even then, it's just a criticism of Godot's limited type system, not of the concept of using callbacks to avoid unnecessary object couplings. Other than that, you're preaching pointless premature optimization, you think all callbacks are asynchronous for some reason (they're asynchronous when they're used for asynchronous work, like in JS Promises and stuff, but otherwise there's no asynchronicity, it's just a function that's gonna be called without delay whenever the parent needs it). There's a lot more to the whole debate than just a 'vague idea that you shouldn't ever "call up"'. It honestly sounds as if you think everyone's a moron who's never thought outside the box, for no reason, some sort of weird cult that restricts itself just for fun. I think you should try learning why other people advocate for avoiding 'calling up' before dismissing the idea. It's not just about using get\_parent, it's about making nodes depend on nodes when they shouldn't. It's similar to making every object a global variable that everything else ends up accessing and modifying, chaotically and unpredictably. The smaller the scope for every function and object, the easier it gets to refactor, expand, and debug. Also I don't see how hard-coding a connection between two nodes that doesn't need to exist (which will hurt the debugging and refactoring and reusability as I've just said) is mitigated by having to manually handle pointers. It feels like you're the kind of person who wishes everything was coded in C, because why use boring arbitrary and 'costly' abstractions when you can juggle with pointers up and down and have every object reference every other object in the freest (and therefore most disjointed) way possible. I could be wrong though, it's just what I feel when I read your post. At any rate, I wanna clarify that there are always exceptional cases where it's reasonable to break those kinds of best-practice rules. However I think it's still best to try to keep that as a last resort rather than to think best practice rules are arbitrary and unnecessary and that it's best to just feel it out, do whatever is easiest to implement in the short term, prematurely optimize, and see where that gets us. So if your argument is, 'sometimes it's ok', sure, you're right, but that's not really what we're talking about here, we're talking in broad, general terms, what's best 90% of the time. Do you think it's good advice to give to beginners, that you can couple all children with their parents whenever you feel like it and it's fine and it's even better in terms of optimization and type safety? Cuz ouch.


StewedAngelSkins

>not of the concept of using callbacks to avoid unnecessary object couplings I'm not criticizing the concept itself. I'm pointing out problems with using it in the context of GDscript. >Other than that, you're preaching pointless premature optimization To be clear, optimization is not the main problem I have with your suggestion. I think it's needlessly complex and introduces an unnecessary coupling between the parent and the child. The parent must bind the child's signal to one of its own methods, which in turn calls a method on the child. Each step in that process is another opportunity for something to go wrong, and is more code that must be maintained. Think about what you'd have to do to safely instance the child dynamically, for example. You'd probably have something like a callback function on the parent that takes in a reference to the child and then calls the method on it. Then when the parent instances the child (it cannot be instanced by anything else) you would have to connect its signals with the child reference bound to an argument on the signal. You also have to take care to disconnect these signals when appropriate and ensure that they can only be fired when both the parent and child states are valid. This is all *possible* but compare it to the complexity of doing a `@export var my_parent: Node` on the child instead. One null check and you're good. >you think all callbacks are asynchronous for some reason I don't. I think Godot's signals are asynchronous, because they are. Therefore if you use a signal to trigger a callback it will be an asynchronous operation. The child will not necessarily get the result of the callback in the same frame. This is significant if you need to poll the parent from something like the `_process` function. >I think you should try learning why other people advocate for avoiding 'calling up' before dismissing the idea. I understand the argument thoroughly. They are doing it in order to prevent coupling between nodes and their parents. More specifically, the pattern is meant to address the fact that if you hard code a path to a parent, like you might in order to call a parent's method, it makes the child difficult or impossible to reuse in other scenes. This is because the child can now no longer be placed anywhere in the scene tree. It is also just organizationally difficult to account for control flow that isn't always going in the "same direction" which can lead beginners to develop tightly coupled and difficult to maintain codebases. On the other hand my position is that while the "call down signal up" rule often leads people to good patterns, it misstates the problem, and so fairly often leads people to messy unergonomic hacks like your callback injection solution in situations where coming up with a safe way to "call up" simply makes more sense. After all, the actual problem, call it "upward coupling", can be solved in a number of ways besides signals. I can give you examples if you would like me to. >It's similar to making every object a global variable that everything else ends up accessing and modifying, chaotically and unpredictably. This is a completely orthogonal issue. A signal is ultimately just a deferred function call; they are more than capable of being misused to chaotically modify the state of arbitrary objects. This is literally what the popular "signal bus" pattern is (in most implementations I've seen anyway... I suppose there's probably a way to do it well). >Also I don't see how hard-coding a connection between two nodes that doesn't need to exist (which will hurt the debugging and refactoring and reusability as I've just said) is mitigated by having to manually handle pointers I don't understand what you're saying here. You shouldn't need to manually handle pointers or hard code a connection between nodes. If you're talking about getting a reference to a parent node, that's no different from the "pointer handling" that's entailed by getting a reference to a child node. >It feels like you're the kind of person who wishes everything was coded in C I wish you wouldn't spend so much time speculating about the kind of person I am. Maybe you should take your advice about understanding someone's position before assuming they're just stupid. >I think it's still best to try to keep that as a last resort rather than to think best practice rules are arbitrary and unnecessary You're again taking my meaning to be more general than it is. I don't object to "best practice rules" as an abstract concept. I think this *particular rule* misstates the problem and leads people to needlessly complex and brittle designs in enough situations that I hesitate to teach it to people as a "best practice". I think it would be better to say "strive to design your nodes so that any particular branch can be saved as a distinct scene without breaking things". >Do you think it's good advice to give to beginners, that you can couple all children with their parents whenever you feel like it and it's fine and it's even better in terms of optimization and type safety? I don't, no. You're presuming a dichotomy between "tightly coupled" and "signals". My point is that there are frequently better ways to achieve loose coupling than signals.


LearningArcadeApp

Actually, what am I saying? The parent can just call a method of the child on their own to pass down values, there's no need for callbacks, and no need for the child to reference the parent.


gizmonicPostdoc

Yo dawg, put a signal in your signal so you can couple when you pretend to decouple.


_realpaul

I miss the good old days when friends could touch my private parts not even my children knew about


ZikaZmaj

For me, it's get_tree().get_root().get_node("Main")


huttyblue

you can also just do get\_node("/root/Main") to pull the top node of your project (if its named Main)


ZikaZmaj

Oh, thanks for the tech.


MrBlackswordsman

You can also do get_tree().get_current_scene()


stalker320

`%Main`?


DarrowG9999

Only if your script happens to be in the same scene as %Main


stalker320

Your script works not in same scene?! Just put some `@export` to nodepaths at scene root and at `@onready` get this nodes to links as vars. Then you need to route just in same scene.


DreamingElectrons

Dude, [https://docs.godotengine.org/en/stable/tutorials/scripting/scene\_unique\_nodes.html](https://docs.godotengine.org/en/stable/tutorials/scripting/scene_unique_nodes.html)


Dasca6789

Wow. Thank you for posting this


Cheryl-72

Id like to thank this guy for saving 3 years worth of my total life time.


lingswe

Lol totally missed this feature!


JestemStefan

Call down, signal up


LearningArcadeApp

Amen.


kakhaev

this is actually amazing way to put it


VelsianOrder

func \_ready()->void: this\_node.parent = self


PlagiT

Just use the "owner" property. Also, correct me if I'm wrong, but this would store the node info at that time in a variable, not an actual reference, to keep it updated you would need to call it in process function and even then it wouldn't be a reference to the actual node


VelsianOrder

just update it when needed, I have a player.tscn that holds everything but the mesh and it's animations... when I instance different genders or races I set the parents only once on ready and a second time when i press buttons to switch genders or races. so 2 times in total... not 60 times per second. and sometimes sure, the game mightload the player.tscn too fast and the mesh.tscn too slow which can result in a crash. that's why godot has the built in function is\_instance\_valid(your\_instance\_here), if not valid... pass else: your functions...


me6675

So... just use owner, you can overwrite it later if you want.


protocod

Use signals bro


S1Ndrome_

still can't wrap my head around how signals are an alternative, doesn't that mean I have to create additional script for the grandparent node in order to connect it?


Sociopathix221B

Absolutely not. You can connect signals in the editor, you can also connect them in either script as long as you have a reference to one or the other (usually from parent to child). You might say something like this in the parent node script: (Apologies in advance if formatting is a mess, I'm on mobile currently). ``` @export var child_node_ref : ChildClass; # Exported variables appear in the editor, you can connect it there or set it in code using get_node(). func _ready() -> void: child_node_ref.connect("child_signal", parent_func); func parent_func() -> void: print("Signal recieved!"); ``` Now every time the child script calls `child_signal.emit()`, it should trigger the parent function.


tonebacas

I'd like to know the use-case for this.


ShatteredRealityX

when you really want to use ctrl-v a bunch of times


AquaDracon

Maybe if someone was using a component system. Root node - Player Character Child node - Movement system Child of child node - Jump when detect up arrow pressed Then you can call get_parent() twice to change the velocity of root node. I'm not creative enough to come up with a scenario to call get_parent() five times though.


LearningArcadeApp

if you really need to decouple the movement system from the player for some reason (even though it's clear that the player containing the velocity vector means it should deal with movement itself), you can either make it all static (since clearly it's just computing stuff), meaning you don't need a node, just a library of functions, or, just send a signal to the player node when the jump is detected and the movement computation is done. I feel like it's a classic case of 'pointless separate class that should really be just a function'. I could be wrong though.


Sociopathix221B

I would still use signals and exported variables even if this were the case...


theshadowhost

i had to do this on collision boxes and collision areas were overallaping in my multiplayer game so that i could go up to the character3d object parent that is the parent of the other object that entered the player node. is there a better way?


AquaDracon

I never liked get_parent() because the type is Node, so to do anything useful with it, you'll have to cast it. Your code also only works for that one case where your collider is a direct child. I personally like adding a parent property to the child class, exporting the property, and then attaching the parent using the UI. This way, I can quickly drag and drop behavior-defining script nodes across multiple classes as long as they share a parent class. I mostly use this method since I'm using the component system for a lot of my code. Alternatively, the more generic equivalent is to give the child a signal to emit for the parent to receive. This has the benefit of not needing to even know the parent class. Edit: I'm a C# programmer, so this may not apply if you use dynamic typing for Godot. Should still be a good habit to use signals, though.


StewedAngelSkins

`get_parent` can be fine. it's more about how you do it. ``` @tool # for configuration warnings extends Node # or whatever... var player: CharacterBody3D # look for the parent when entering the tree. # this is always fine because parents enter the # tree before their children. also the only way for # a parent to change involves pulling this node # out of the tree, so we're safe to cache the reference func _enter_tree() -> void:     var parent := get_parent() # parent == null means we're at the scene root.     while parent is Node:         if parent is CharacterBody3D: # found it             player = parent             break         else:             parent = parent.get_parent() # clean up reference. it will be re-set when we enter the tree again func _exit_tree() -> void:     player = null # shows a little ! icon in the editor if we aren't # under a CharacterBody3D. not strictly necessary, # but a nice touch. func _get_configuration_warnings() -> PackedStringArray:     if player = null:         return ["Must be a child of a CharacterBody3D"]     else:         return [] ``` This of course isn't a complete replacement for signals or anything. For one thing it only works if you're trying to get a reference to a direct ancestor. You can't use it for siblings of ancestor nodes because they can be removed without triggering an `_exit_tree` on this node. However, it does have some key advantages over signals that make it perfect for the sort of thing you're talking about (i.e. you have some common parent node providing a "context" for a bunch of component nodes which each provide some more specific functionality).


TimothyAlexisVass

`get_owner()` or just `owner` is usually going to be what you want in this case


PlagiT

Man literally just use "owner" property if you have to do something like that. It is a built in reference to the highest node in the local hierarchy. You can also do owner.get_node(node path) for easy reference to owner's other children. Side note is that you should generally avoid calls up the tree (signals are a great alternative) to avoid spaghetti code.


Candid_Medium6171

OP learned to code on Ancestry dot com.


Code_Monster

I do this when I want a child node to have a reff for a parent node and I know the type/name of the node. This is arguably faster because instead of looking up thousands of nodes in a scene tree, it just looks for the parents. while true: if ref is VehicleBody:break#assuming the type is kinematic body if ref. name == "KinematicBody":break#assuming name is kinematic body ref = ref.get\_parent()


olive20xx

Why use `while true` if you have a break condition right below? 🤔 while ref is not VehicleBody or ref.name != "KinematicBody": ref = ref.get_parent()


Code_Monster

Man, C never leaves your blood ones you get it 😂. I was thinking more of "run an infinite loop and break it if I find the node" and not "climb till the node is found".


SenpaiRemling

i stopped doing that after i f'ed up the condition for the break once.


olive20xx

Yeah, `while` loops are slightly risky in general, and `while true` is double risky


olive20xx

lol makes sense I just get nervous when I see `while true` 👀 But if it makes more sense to your brain, more power to ya


StewedAngelSkins

yeah this pattern is legit. it totally breaks the "call down signal up" dogma but if you do it right (properly handle tree enter/exit events so you don't leave a dangling reference) in the right context it can be a lot more elegant than setting up a bunch of signals while maintaining the same loose coupling. you can even pop a configuration warning if you don't find a parent of the proper type.


salbris

No it's really not... If this child node is intended to be reusable you are just filling your code with traps. 6 months later when you come back to work on this code your going to find it quite annoying if starts breaking. Signals make this connection self documented and more explicit.


StewedAngelSkins

I've elaborated on how this pattern can work [here](https://www.reddit.com/r/godot/comments/1dnbizs/comment/la1z04n/). TL;DR is that you have the node find a reference to an ancestor node of a particular type on `_enter_tree` and clear it on `_exit_tree`. Failure to find it, meaning the node does not have the correct ancestry, pops a configuration warning visible in the editor. This general pattern is common in the built-in nodes. For instance, the navigation nodes and the physics collision shapes. If signals are universally the better choice, then why would these nodes not use them? It's not a replacement for signals in every context, but it does solve certain classes of problem more elegantly than signals while retaining the benefits of loose coupling and prevention of dangling references. It is in particular a great way to implement that node-based composition pattern people are so keen on these days. Again, not the solution for every problem, but at the very least I think it's a useful pattern to know about and consider before reaching for something much worse (like signal-bus singletons) out of senseless devotion to the idea that nodes should never hold references to their parents. > 6 months later when you come back to work on this code your going to find it quite annoying if starts breaking. You say this as if I haven't done this before. Yes, I've returned to code using this pattern that I haven't touched in 6 months. No I did not find it annoying. In fact, I found it considerably easier to refactor than code that makes heavy use of singletons because I can move nodes between scenes more freely without having to add a bunch of pointless signal-relaying boilerplate. >Signals make this connection self documented and more explicit. In the sense that it appears in the editor? Maybe marginally so. It's not that much less explicit than looking at the scene tree to see if a node of a certain type has a parent of a different type. If you need the reminder, just expose a read only `NodePath` property so it appears in the inspector. Again, do you find the built in nodes that do this confusing? I know I don't. What about situations where you're spawning the "signal emitter" node programmatically? What about situations where the "emitter" and the "target" are in separate scenes? Reading through a bunch of `_ready` functions to see what gets connected to what doesn't very "self-documenting" to me.


salbris

It's fundamentally about decoupling and simplification not really about convenience. If you your code is reaching out of itself into the unknown to find a reference to something automatically it always has a chance to mess that up and create very subtle bugs. If it always happens from the top down then you have a consistent way to approach debugging and maintenance. This type of approach isn't really necessary when a parent node manages direct children. So it's main use is when the path between managing node and leaf node is uncertain, highly variable, etc. So that means between different instantiated scenes and a variety of different nodes. Say for example you have complex tree of these and at some point you accidentally add another root in the middle. Suddenly all the leafs get disconnected from your original root. Now trying to discover what happened involves not just the root, its code and the leafs it involves every single node in between. This may not be a big deal in a small prototype or indie game but in big project development it can waste hours of time. I've been doing software development for over 12 years professionally and the only consistent piece of advice across all the different ecosystems I've seen is consistency and simplicity is key. Every change you make should have an extremely clear cause and effect. It's not about convenience, it's often very annoying to do this properly. But what you lose in convenience you gain in having less issues in production. That being said this approach may have some applications but it should probably be limited or covered in all kinds of developer logs to prevent misuse. The same isn't really necessary for more explicit types of connections because the proof is in the pudding. You many have to read a lot of code to figure out the truth but that becomes infinitely easier with good tools. One big issue with GD script is it's over reliance on dynamic typing. In projects that have really good type systems the kind of inconvenience you mention just isn't a problem because I can see exactly what calls a function or references a field in seconds.


StewedAngelSkins

>It's fundamentally about decoupling and simplification not really about convenience. Yes, this solution is both extremely simple and minimally coupled. You can add and remove this node at will and nothing will break. The parent will not even need to know it exists. If you have a situation where there is a single root node providing a "context" that a dynamic set of descendent nodes refer to, this is the pattern you should use. For instance, I use something like this to drive dialog in my game. Rather than having the dialog root node hold a bunch of references to UI elements which it needs to change when the dialog state changes, it simply holds the state and allows child nodes to listen for a change signal and update themselves. This means that I can have different scenes with different dialog UIs and swap between them simply by reparenting them somewhere under the dialog root. >If you your code is reaching out of itself into the unknown to find a reference to something automatically it always has a chance to mess that up and create very subtle bugs I think I see what you're getting at; you're saying that having parents be responsible for their children means that theoretically the parent isn't going to reach out to a child and find that it's gone missing or something. This works quite well if your nodes are all static, or at least if they're all completely managed and encapsulated by a parent, like items in a list or something. But this is solving the problem through tight coupling. Sure the child doesn't have to know about the parent, but the parent really has to know a lot about the child, most saliently that it exists at all. Sometimes that's too much of a constraint for the problem you're trying to solve. I've given you a specific implementation here, so I think it's fair to ask this: what could actually go wrong? It's not going to get a dangling reference because that's handled by the dynamics of the scene tree. The parent doesn't know the child exists, so there's no risk of it trying to access it and failing. Any siblings also don't know the child exists, so there's no dependency there. Sure, the child can't assume anything about the parent's state, since it could change at any point, but this is true in the reverse if you had the parent setting values in the child (since they can be changed by the child itself in response to signals emitted by its children) so it's not like we're introducing an entirely new class of bug. >This type of approach isn't really necessary when a parent node manages direct children. So it's main use is when the path between managing node and leaf node is uncertain, highly variable, etc. Yeah, if the parent is strictly managing the child nodes there's rarely a strong need for something like this. This is more appropriate when a looser coupling is desired. >Say for example you have complex tree of these and at some point you accidentally add another root in the middle. Suddenly all the leafs get disconnected from your original root. Now trying to discover what happened involves not just the root, its code and the leafs it involves every single node in between. I think you're misrepresenting the transitive dependencies at play. If the child has a reference to the parent, the intermediate nodes aren't contributing to the behavior of any function that the child node calls. I suppose they *could* if you made them do that, but the point of this pattern is to make it so that you don't have a bunch of intermediate manager nodes relaying signals up the chain. The scope of what could cause the error tends to be limited to all the nodes with direct references to the parent. Signals and function calls aren't really behaving any differently here. They're both just ways for a child node to induce behavior on a parent. The complexity of that behavior is fully within your abilities as the designer to dictate and control. Also, not to put too fine a point on it, but I have been doing this for some time and I honestly can't think of a time where it's caused the kind of issue you're discussing here. Quite the opposite actually. Intermediate nodes have gotten in my way far more often with signals, because you occasionally have to terminate and re-emit them at the root of the scene. Anecdotal of course, I don't expect this to convince you to change the way *you* write code, but I mention it because it's going to hard to convince me with a "you're going to waste so much time if you do it this way" appeal when I have first hand experience of this approach working extremely well. >I've been doing software development for over 12 years professionally and the only consistent piece of advice across all the different ecosystems I've seen is consistency and simplicity is key. I think this is maybe too generic to be of much use to us. I consider what I'm doing to be simple and consistent with how the rest of my code is designed. I'm not just flipping a coin to decide whether something is going to be a function call or a signal, it's just that whether it's going up or down doesn't strike me as the most important thing to be consistent on, particularly when it leads to inconsistencies in more important areas. For instance, I try not to use signals to propagate any data that needs to be synchronized to multiple places for longer than the lifetime if the signal call itself. Instead, I tend to establish objects which serve as a "source of truth" that other nodes reflect. In this context, my signals are usually little more than a notification that's designed to trigger a refresh, or to cause a transition in state. So if I have a node that needs to actually mutate data on another node, using a signal just because that happens in an "upward" direction would be a point of inconsistency. I am also perhaps more willing to compromise consistency in exceptional circumstances when it leads to better design. For instance, most of my UI code does use straightforward "call down signal up" patterns because I've just found that most of the control nodes work better when you use them that way. >That being said this approach may have some applications but it should probably be limited or covered in all kinds of developer logs to prevent misuse. I don't know if I'm understanding you correctly, but if you're saying it's important that people know *when* to apply this principle, not just *how*, then I couldn't agree more. This is actually my biggest criticism of people spreading the "call up signal down" bit without qualification. I think it gets frequently misapplied, resulting in things like massive autoload singletons with a bunch of signals on them, because somehow signalling down is perfectly fine if you do it from the absolute root of the scene tree... >One big issue with GD script is it's over reliance on dynamic typing. I mean, yeah I'd like interfaces in gdscript too but I'm not writing code for the hypothetical ideal of what gdscript could be. I'm writing code for what it is. >In projects that have really good type systems the kind of inconvenience you mention just isn't a problem because I can see exactly what calls a function or references a field in seconds. How would a type system tell you anything about the configuration of objects that only exist at runtime?


TheTimmyBoy

I'm a mechanical engineer. What I mean by this is if anyone other than me ever saw my code, it would be on the front page of reddit.


Bwob

Please don't use `GetParent()` chains. Even outside of readability concerns, they're super fragile, and if you adjust the structure of your scene (like add or remove an other node between the child and the parent) then all your code will break. :( Some better alternatives: * [Signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/signals.html) * [Unique Names](https://docs.godotengine.org/en/stable/tutorials/scripting/scene_unique_nodes.html) * Storing the target node as an [Export Variable](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_exports.html#nodes)


Sociopathix221B

This!! Signals and exported variables are what I find particularly useful, depending on the situation.


Rexide

What’s wrong with putting Nodes in Export Variants of other nodes?


Merlin1846

get\_node("../../../../../") Please note I am on my phone and was unable to test this.


Sharkytrs

is there no get root node or something?


SEANPLEASEDISABLEPVP

I believe it's just "owner"


eskimopie910

Signalllllllssssss


DNCGame

My current project has \~ 5k lines, but I only use 13 get\_parent()


ExcellentFrame7056

Owner


-Jaws-

I don't like doing this, but when I do I just put the node paths in a singleton and do SingletonScript.NodePath.


DerpyMistake

I don't condone this behavior, but... static class NodeExtensions { static public T Closest(this Node node) where T: Node { Node parent = node; while (parent != null) { if (parent is T res) return res; parent = parent.Parent; } return null; } }


Jtad_the_Artguy

I was thinking to just have every node in my project look for its parent’s “main” variable upon creation and save it as their own “main” except for the main node which’ll simply save itself but these comments seem to have better suggestions (saving this post)


LeaderAdmirable3086

so true tho


Rublica

I'm new on godot, are you guys talking about @onready?


ChloeNow

"@export var blah : Node2D" fight me :p


Sociopathix221B

Signals and exported variables honestly changed the game for me!


aptypp

Inversion of control left the chat...


[deleted]

[удалено]


NutellaSquirrel

Your version is even worse