epic man
epic man

Reputation: 35

_get_property_list: Dynamically create / store variables from child node into script

Within Godot, I am attempting to create a function that would basically dynamically create a property list based on the children nodes (to allow maximum composition). Currently though, I am stuck on one single issue. When I updated the _get_property_list, I don't want to have to hard code a variable to store an int for an enum for every single node. Instead, I want the variables for each node to be created dynamically, i.e., I don't know what variables I will be using within the class until I run the editor.

I tried making a dictionary that will hold all of the variables, but when I overrided the _get and _set funcs as follows:

func _get(key): return propertyHolder[key]

func _set(key, value): propertyHolder[key] = value

I got never ending errors, which tells me that I've gotten something wrong. I couldn't find any _get_variable_list funcs, like the _get_method_list, and so I am stuck. I also considered each node holding their own variable locally and passing it to the parent, but I ultimately ran into the same issue that since the number of nodes is dynamic, I somehow need to dynamically receive these nodes in the parent class. Any advice would be much appreciated.

Upvotes: 1

Views: 1924

Answers (1)

Theraot
Theraot

Reputation: 40295

I got never ending errors, which tells me that I've gotten something wrong.

From the code you shared, I see that you are not considering the case where the dictionary does not have a key. You could read it with get:

func _get(key): return propertyHolder.get(key, null)

Here if the dictionary does not have a key, it will return null.

If that is not the issue, I'd need to see the errors you got.


I got never ending errors, which tells me that I've gotten something wrong. I couldn't find any _get_variable_list funcs, like the _get_method_list, and so I am stuck.

The "_get_variable_list" is what you are trying to provide in _get_property_list: get_property_list.

Of course, do not call get_property_list from _get_property_list of the same object, as calling get_property_list will result in calling _get_property_list. Last time I tried this resulted in a crash.

Instead, you can read the variables from get_script_property_list from the script. For example, if you want to automatically export all variables, you can do this:

func _get_property_list() -> Array[Dictionary]:
    var result:Array[Dictionary] = []
    var script := get_script() as Script
    for property in script.get_script_property_list():
        if property["type"] == TYPE_NIL:
            continue

        property["usage"] = PROPERTY_USAGE_DEFAULT
        result.append(property)

    return result

Here I'm checking the type to skip groups and categories (they are exported as null properties). But you could use them to limit it to only properties defined in the current script:

func _get_property_list() -> Array[Dictionary]:
    var result:Array[Dictionary] = []
    var script := get_script() as Script
    for property in script.get_script_property_list():
        if property["type"] == TYPE_NIL:
            if (
                property["usage"] == PROPERTY_USAGE_CATEGORY
                and property["name"] != script.resource_path.get_file()
            ):
                break

            continue

        property["usage"] = PROPERTY_USAGE_DEFAULT
        result.append(property)

    return result

I somehow need to dynamically receive these nodes in the parent class

You can connect to these Node signals: child_entered_tree, and child_exiting_tree (you might also be interested in child_order_changed).

Upvotes: 2

Related Questions