this post was submitted on 30 Jul 2024
17 points (94.7% liked)

Godot

5662 readers
18 users here now

Welcome to the programming.dev Godot community!

This is a place where you can discuss about anything relating to the Godot game engine. Feel free to ask questions, post tutorials, show off your godot game, etc.

Make sure to follow the Godot CoC while chatting

We have a matrix room that can be used for chatting with other members of the community here

Links

Other Communities

Rules

We have a four strike system in this community where you get warned the first time you break a rule, then given a week ban, then given a year ban, then a permanent ban. Certain actions may bypass this and go straight to permanent ban if severe enough and done with malicious intent

Wormhole

!roguelikedev@programming.dev

Credits

founded 1 year ago
MODERATORS
 

I am coming from a Unity background and there I just had a component of some custom class in the scene which I could then easily get by calling FindInScene<CustomComponent> or something like that. Not in Godot this doesn't work, because I didn't find a way to get the actual class of an attached script. I always just get GDScript as the class name even though I did specify a custom one.

The information I want to save are things like: where to spawn players, how many laps will this race have, maybe save references to the spawned players, etc.

So how would I save this "meta" information to get by another script in Godot?

EDIT: here is an example: I have a main scene which can load different levels. When loading a level I need to get some information about that level, like: the available spawn points. Inside each level I have a node with a script attached to it that defined class_name LevelMeta and holds the meta information that I need when loading the level. How do I detect this script and the associated meta information?

top 21 comments
sorted by: hot top controversial new old
[–] Bougie_Birdie@lemmy.blahaj.zone 5 points 1 month ago (1 children)

You may find some value in Groups. This lets you assign a node to a group by name, then later get the nodes in the group by searching for that name.

In your specific example you mention being able to fetch the spawn points. I'd add each spawn point to a group called "spawn" and then later retrieve them with:

var spawn_points = get_tree().get_nodes_in_group("spawn")

[–] BentiGorlich@gehirneimer.de 2 points 1 month ago (1 children)

Interesting. I heard about groups, but I didn't really look into them, yet. Seems I gotta read up a little more :D

[–] Bougie_Birdie@lemmy.blahaj.zone 4 points 1 month ago (1 children)

I find them very handy. I also came to Godot from Unity, and groups almost work identically to Unity's FindAllInScene()<> method. You just have to do a little setup to give them a string instead of searching for class type, but they behave very similarly.

[–] unexposedhazard@discuss.tchncs.de 3 points 1 month ago* (last edited 1 month ago) (1 children)

Im not really sure i understand. A scene is just a node with some children, if you want to store and read information from it then you just attach a script to the root node and declare some variables in it no?

If you add some custom node or instance to it, then you just get_node that by its path and access its variables.

[–] BentiGorlich@gehirneimer.de 1 points 1 month ago (1 children)

Yes exactly. but how do I detect a specific script in my scene view? Or in other words: how do I find the source of my meta information in a scene?

[–] unexposedhazard@discuss.tchncs.de 3 points 1 month ago* (last edited 1 month ago) (2 children)

Oh you want to know the name of the script that was previously attached to a node?

get_script().get_path() should return the filepath to the script that you used, not sure if thats what you want tho.

[–] BentiGorlich@gehirneimer.de 1 points 1 month ago (1 children)

I added an example in the thread

[–] unexposedhazard@discuss.tchncs.de 4 points 1 month ago* (last edited 1 month ago) (2 children)

I see, looks like that is actually an issue.

https://github.com/godotengine/godot/issues/21789

Seems like you have to overwrite the get_class function if you want to detect custom classes.

extends Node2D

class_name CustomClass

func get_class(): return "CustomClass"
func is_class(name): return name == "CustomClass" or .is_class(name) 


func _ready():
	print(get_class())
	print(is_class("CustomClass"))
	print(is_class("Node2D"))
[–] BentiGorlich@gehirneimer.de 1 points 1 month ago

Ah good find, I will read through that shortly, thanks :)

[–] BentiGorlich@gehirneimer.de 1 points 1 month ago (1 children)

But is my solution actually a good one?

[–] unexposedhazard@discuss.tchncs.de 2 points 1 month ago* (last edited 1 month ago) (1 children)

Defining a unique class name gets you the same thing as giving each script a unique filename and then differentiating between the get_script().get_path() but i can see how its not as clean for comparison.

Another solution would be to just give all your custom classes a var called "class_id" or something and then you can read that out if you need it.

[–] BentiGorlich@gehirneimer.de 1 points 1 month ago (1 children)

Oh I meant the general solution for getting level / scene meta data 😅

[–] unexposedhazard@discuss.tchncs.de 4 points 1 month ago* (last edited 1 month ago) (1 children)

Im assuming you have a predefined level scene, which you instantiate and add as a child to your main scene. If i were to save a bunch of metadata about that level scene, i would add a dictionary named "level_data" to the script of the root node of that levels scene.

extends Node

var level_data = {
"spawn_point": Vector2(x,y),
...
}

After you instantiate that level from your main scene with:

var level1_tscn = load("res://path/to/tscn")
var level1 = level1_tscn.instantiate()

You can then get or modify the metadata from that instance reference.

print(level1.level_data["spawn_point"])

When you are done you can then add it as a child to the main scene with add_child(level1).

You can also do that right away and access the data later ofcourse, but if the values are needed in the _ready function of the level, then you need to modify them before adding it to the main scene.

[–] BentiGorlich@gehirneimer.de 2 points 1 month ago (2 children)

That seems very nice. Thanks for the input :) I am very much new to Godot and I gotta say most Unity systems in my head still work, but some just let me run against a wall, like the one I described here XD

Added something to the previous comment.

Im also not super experienced, i just make unsuccessfull attempts at making games from time to time :) But i do love godot a lot.

You generally use the same logic for literally everything in godot.

Spawning a bullet, enemy, item, ui component?

Instantiate, set values, add_child

[–] BentiGorlich@gehirneimer.de 1 points 1 month ago

not the name, the class_name I set inside of the script

[–] butitsnotme@lemmy.world 2 points 1 month ago

I would create separate nodes for each piece of metadata within the scene you are loading, you can use a Node2D (or Node3D) to store a position (such as a spawn point) and there is a Timer node which can hold the time for a level.

Alternatively, under the node inspector there is an option to “Add Metadata”, which might be more along the lines of what you are looking for. It can be read with the get_meta function.

[–] domi@lemmy.secnd.me 2 points 1 month ago (1 children)

Do you use C# since you're coming from Unity?

You can use GetNode<CustomNode>() or GetChild<CustomNode>() to find the node you need just like in Unity. CustomNode will be the type of your script or if there is no script attached to your node you can use the builtin types as well (e.g. Node3D).

Once you have the node you want, you can either use Godots builtin functions SetMeta() and GetMeta() to set and get metadata on a node or use the C# way and access the public properties set on that CustomComponent class directly.

I don't use GDScript but I assume you have the same methods available there.

[–] BentiGorlich@gehirneimer.de 1 points 1 month ago

I am using GDScript :(