What's the best way to "get" nodes in Godot?

แชร์
ฝัง
  • เผยแพร่เมื่อ 26 ธ.ค. 2024

ความคิดเห็น • 42

  • @queblegamedevelopment4143
    @queblegamedevelopment4143  หลายเดือนก่อน +13

    Here's the info on Unique Names, since quite a few people mentioned this :)
    Unique Names are similar to exported references (in the sense that the scene tree position can change while retaining the path), although they still need to be accessed with the % symbol (the same as using the $ sign or get_node()).
    Pros of using Unique Names:
    - Similarly to exported references, you won't need to update your code when moving the node around in your tree
    - More readable paths inside your script
    Some Cons of using Unique Names:
    - For the best performance, it's still essential to store unique nodes inside of @onready variables, since they do still need to be obtained, and aren't properties
    - Uniquely Named nodes can ONLY be retrieved by a node inside the same scene. This means that instanced scenes with exported node references are much more flexible, especially when working with component systems.
    - If you have multiple nodes with similar names (especially in larger scenes), Unique Names can get tedious, and end up being more confusing than other methods.
    Performance of Uniquely Named nodes:
    - The performance is slightly faster than using static paths, but is still slower than using exported references
    Hope this helps! :)

    • @goranovs
      @goranovs หลายเดือนก่อน +1

      I will realy enjoy video of how this performance is mesured. Can be a short. I'm really curious. I'm not a Godot Pro or anything like that. As far as I know the % does all the chaching for you. The main benefit for me is that I often need to re-position nodes in UIs and % names saves you all the renaming.

  • @Arisilde
    @Arisilde หลายเดือนก่อน +21

    Just a minor note, you don't really lose runtime flexibility with exported variables, and they don't have to be assigned in the editor. You can set default values in the script declaration, so if you forget to set them in the inspector it'll still work, and you can still set them again during runtime, nothing prevents it. The only downside is they will revert to the exported value when the game is rerun, so you'd need to save the value, and load it after to get the prior runtime value. Most games with save/load do that anyway, so it's not a real issue.
    Also, export is basically the same as onready + inspector access. There's not really a performance difference. Export does process before onready though, as it's more in line with _init(), while onready is with _ready().

    • @IterationFunk
      @IterationFunk หลายเดือนก่อน

      Also, the majority of nodes you access in Godot is part of the same scene as the script. It's how you structure logic, actions, reusability and everything in godot.
      So most child nodes that you export a reference to have the exact same lifecycle as the parent node/scene where you attach the script.
      When outside of that use case, groups are often very useful. For example if you have a PlayerHUD scene that reads back health etc from the player I usually just pick the first element of the player group and set the reference in onReady, and throw an error if a player cannot be found. I use c# so I haven't used unique names a lot, maybe that's preferred approach, but groups worked very well for "outside" dependencies in c#.

  • @comradecid
    @comradecid หลายเดือนก่อน +1

    honestly one of the best things i ever learned in programming was to look for/keep in mind the hidden 'costs' of every line of code, in terms of processing, lookups, memory, etc. when i was a kid, computers were grossly underpowered, slow as shit, and memory was precious; if your code didn't take all this into account, it either ran poorly, or not at all. modern systems tend to obscure this (both a good and bad thing), but the fundamentals haven't changed.
    i'd love to see more developer content taking quick asides to explain "ok... so look at what's happening here *every single processing cycle*..." etc.

  • @andrewgrinn3435
    @andrewgrinn3435 หลายเดือนก่อน +8

    I didn't know get_node had such an performance impact. Thanks

  • @DUHRIZEO
    @DUHRIZEO หลายเดือนก่อน +5

    Great video idea with these short clarifications! If you haven't done it already, an explanation between some of the other virtual methods would be awesome.
    Like _process vs _physics_process or _input vs _unhandled_input. Stuff like that.

  • @mojeime3
    @mojeime3 หลายเดือนก่อน +2

    I was just wondering this a couple days ago. Thanks for sharing.

  • @JasonLothamer
    @JasonLothamer หลายเดือนก่อน

    There's probably no difference between the performance of export and onready. If you look a the scene file and find the export property you'll see that a NodePath() is saved and not a reference. So, both export and onready use nodepaths. However, the export value is evaluated early and you can access it in the _enter_tree() function while the onready value is set later and available by the time _ready() is called. (Note: all nodes in a scene are created from the get go and then added to the tree from root to leaf. To verify add an _init() override that prints _init() was called for a node. Do likewise for _enter_tree() and _ready() to get a sense of the sequence.)
    Personally I use onready variables with unique names and just rename nodes to match what they are being used for making it less likely I'll rename them. Then moving them around wont break anything. I also don't like having extra exports hanging around when I child the scene into a level or something. This is especially true for very complex scenes where a lot of extra exports would be added and visible.
    But to each their own! If you like exports, by all means enjoy! While I personally don't do it, there's nothing really wrong with it.

  • @GordoFriman
    @GordoFriman หลายเดือนก่อน +4

    As usual, the more static or predefined some info is, the faster it will be processed

  • @Kry0000
    @Kry0000 หลายเดือนก่อน +1

    Thanks for sharing this information.

  • @MalbecGames.
    @MalbecGames. หลายเดือนก่อน +1

    Thank you for creating this content.
    I like these kinds of videos: short, to the point, and covering the basics.
    As it was mentioned in other comments, I'd have liked to see an example using %unique_names, perhaps that could go in another video.
    Best regards.

  • @AndreezyDev
    @AndreezyDev หลายเดือนก่อน

    I use a mix of exports and onready,
    The exports i use for scripts that are shared between scenes. For instance, my playable characters all use a stats script that houses their health, stamina etc.
    I this allows reuseability, for logic thats shared between characters but not necessarily needing the exact same things like running speed etc.

  • @jumpsneak
    @jumpsneak หลายเดือนก่อน

    It's just a guess, but onready nodes should be worse because godot still calls get_node to get the reference while with export, it seems, you directly assign the reference via the editor

  • @panampace
    @panampace หลายเดือนก่อน +1

    I never use $ or node paths in code. Always export variables.

  • @vrabo3026
    @vrabo3026 หลายเดือนก่อน +2

    Is there a difference between exporting nodes and setting them to "% Access as Unique Name"?

    • @queblegamedevelopment4143
      @queblegamedevelopment4143  หลายเดือนก่อน

      Yes there is!
      Using Unique Names is still slower than setting exported references, although it is faster than using static paths.
      For the best performance with Unique Names, you should still store the reference inside of an @onready var.
      The only drawbacks of using Unique Names, is that node references will only be able to be accessed by other nodes inside that same scene, meaning that if you instance a scene with an exported node reference, it'd be a lot more flexible.

  • @Derfaverse
    @Derfaverse หลายเดือนก่อน

    Great video 👏 with the export method, would there be a significant performance difference if you dragged a file from a folder rather than creating a node in the scene tree for that variable?
    Example: an mp3 file.
    Do I have to create an audiostream node inside my scene tree or is it fine to just drag the file from my sounds folder?

  • @beludobeludo
    @beludobeludo หลายเดือนก่อน

    Great job

  • @pity4657
    @pity4657 หลายเดือนก่อน +1

    The missing one is %cached_name
    Those are cached so are fast

    • @queblegamedevelopment4143
      @queblegamedevelopment4143  หลายเดือนก่อน

      I've added a pinned comment that explains the pros and cons of unique names in a bit more depth :)

  • @goranovs
    @goranovs หลายเดือนก่อน +5

    Just use @ready with %unique names. Why would you want to drag n drop your whole node tree in export vars :D

    • @shinoneiluj6995
      @shinoneiluj6995 หลายเดือนก่อน

      that's exactily what I was going to say.

    • @MalbecGames.
      @MalbecGames. หลายเดือนก่อน

      I was looking for this by the end of the video.

    • @SuperPuperCode
      @SuperPuperCode หลายเดือนก่อน

      Использовать уникальные имена желательно тольок для обьектов которые уникальны или в единственном экземпляре иначе будут ошибки

    • @queblegamedevelopment4143
      @queblegamedevelopment4143  หลายเดือนก่อน

      I've added a pinned comment that explains the pros and cons of unique names in a bit more depth :)

    • @NexNoctis
      @NexNoctis หลายเดือนก่อน

      There is one big issue with using @export assignment on Label-nodes : more than once it happend to me that Godot removed all label references from the scene, giving me null pointer during runtime. Therefore I had to re-assign every single one of them. Imagine the fun if you have a lot of labels in your bigger szenes 😅

  • @studiotoby9952
    @studiotoby9952 หลายเดือนก่อน

    DANG!! now I must rewrite 500 lines

  • @SneakyBanditStudios
    @SneakyBanditStudios หลายเดือนก่อน

    It depends a lot on the type of project you're making and what it is you're doing with that node, what it's interacting with. Exporting some nodes can lead to issues with serialization and there are some other potential issues. For smaller projects this may be fine. But it is NOT something you should be doing with 100% of your nodes, at any and all times. And most certainly not something you should do with larger games.

  • @rumariomusic
    @rumariomusic หลายเดือนก่อน +1

    It is still inefficient. The str() function should not be in _process

    • @sweatyeti
      @sweatyeti หลายเดือนก่อน +2

      True. The code example in _process function should have been something else, since the point of the video was about referencing Nodes.

    • @queblegamedevelopment4143
      @queblegamedevelopment4143  หลายเดือนก่อน

      How would you go about improving that line?
      The only thing I can think of would be adding a condition to only update if the mouse pos is different than last frame?

    • @sweatyeti
      @sweatyeti หลายเดือนก่อน +2

      @@queblegamedevelopment4143
      Glad you asked. Based on what I understand, converting the mouse's position to a string with str(...) is the most time-consuming function in question, so reducing the number of times we call it is ideal.
      What you suggested is correct. We'd use the Node's _input(event) function to check if the mouse position has changed, and if it did, we'd assign str(get_global_mouse_position()) to the label's text. As far as I know, _input(event) is only called when user input is detected, so first checking for a UI change and then checking if it was the mouse position significantly cuts down on how many times str(...) is called.
      That said, for most games, this kind of optimization is likely unnecessary. Yes, it can add up, but performance drops are typically caused by rendering a lot of textures or poorly managing large amounts of data or memory, as opposed to calling a str(...) conversion each frame.

  • @michaellee2786
    @michaellee2786 หลายเดือนก่อน

    No one should give performance advise without measurements.

    • @queblegamedevelopment4143
      @queblegamedevelopment4143  หลายเดือนก่อน

      Measurements were taken :)

    • @michaellee2786
      @michaellee2786 หลายเดือนก่อน

      @@queblegamedevelopment4143 Hey, just rewatched to double-check, but I don't see any figures for the performance differences you're mentioning. Knowing the cost and benefit of multiple approaches helps people make the choice. Saying "faster" and "slower" is not engineering.

    • @queblegamedevelopment4143
      @queblegamedevelopment4143  หลายเดือนก่อน +3

      There were no figures shown in the video, as I assumed the efficiency boost was obvious.
      Using "faster" / "slower" is a great way to give viewers (especially less experienced users) the information they need in a quicker format :)
      Aside from that, the benchmark project I used to test these theories showed the following results:
      Figure A: Using $ to access nodes when you need them:
      - 20 nodes, having 2 properties accessed each, 10,000 times per frame | average of 120ms frames
      - 10 nodes, having 2 properties accessed each, 20,000 times per frame | average of 121ms frames
      - 20 nodes, having 2 properties accessed each, 100,000 times per frame | average of 1204ms frames
      Figure B: Storing nodes in onready variables for access:
      - 20 nodes, having 2 properties accessed each, 10,000 times per frame | average of 80ms frames
      - 10 nodes, having 2 properties accessed each, 20,000 times per frame | average of 83ms frames
      - 20 nodes, having 2 properties accessed each, 100,000 times per frame | average of 819ms frames
      (As you can see, the method I promote in this video is clearly more efficient than the alternative)