I’ve got a number of object class scripts (For example MyItem) that have functions like get_icon() and get_display_name() that I can use in list items and UI widgets when I want to represent these objects. This is fine in most cases, but it means that I need an actual instance of the object to call these methods on. As the icons and names in these cases will not change dynamically, but be different for each sub class this feels like a perfect situation for making these static functions on each sub class, and then use MyItem.get_icon() etc when I need to represent these instead of needing an instance of MyItem.
However, I can’t find any way to get access to such constant functions without hardcoding the class names. Is there a way to access constant functions like these on script classes based on having the name of the class as a String? Basically what I’d like is something like:
ClassFromString("MyItem").get_icon()
But GDScript doesn’t seem to have a class type so I’m guessing this will not be possible. My second guess would be to do this via Script, and I’ve managed to get the Script for the class_name, but I’ve not found a way from Script to access the class static functions without needing to create an instance of the class (which is what I’d like to avoid). Is there a way to do this?
If I got your question correctly, perhaps you can take a look at the Resource class. I personally haven’t used them this way for now, but I believe they can be used somewhat like the Unity’s prefab variant.
So assuming you have your MyItem class, extending Resource, which holds some attributes and methods, you can then have “different instances” leveraging the same logic.
I also don’t really get what you mean with this. If you have a list of MyItem that you need to display, then I guess you already have the instances you need. If you display an item I would assume that means the player has it, so most likely you already hold the instance somewhere (i.e. the afore-mentioned list).
Yes, you’re right, and these were the cases I originally used this for. However, there might also be other cases where there aren’t any instances yet. Consider for example a case like a shop or spawning ui, where you have a list of the types of items or objects available (as in the class names) but the creation of the instance will be after you’ve picked the item, so you can’t refer to instances for the icons in the list UI.
Yes, ClassDB looks quite promising. Especially there seems to be a ClassDB.class_call_static() that looks like it could be exactly what I’m looking for!
Unfortunately after some more testing this doesn’t seem to work. ClassDB and the ClassDB.class_call_static() appear to be designed for exactly this type of thing, but with the big limitation that it doesn’t work with custom script class_name classes, it only works for built-in classes.
I believe it would be a much cleaner and scalable approach if you just used resources instead. What I’d suggest doing is creating a custom Resource and bind to that resource the icon, prefab, and all you need.
So you can just have a generic MyItem resource that holds some data:
class_name MyItem extends Resource
@export var icon: String
@export var name: String
@export var your_other_var: Variant
then you can simply create a new Resource in your file system and use that as reference without the need to instanciate any object.
I used to use this approach in an old game of mine done in Unity. I saw this approach on a YouTube tutorial by CodeMonkey. I’ll try to attach the link here if I can find that (note: this is for Unity but you can apply the same logic, but leveraing Godot’s built-in):
Thank you for the suggestions for alternative approaches @hexgrid and @colelli, using a separate database/dictionary of sort with the display information for all the object subclasses is certainly one solution that I’ve considered to avoid needing to instance objects, but ideally I’d like the classes to be self-contained and keep all the information about themselves in one place with everything about each class in one file. This was why I wanted to explore the possibility of using static functions/variables on the classes for access.
Using a resource-based approach would probably be a better idea is these were simple game objects like items or such, but this description above was just a simplified example to illustrate the use case. In my use case they are subclassed modular component nodes used in a sort of generative system so I do not think a custom resource-approach would be possible for the full implementation, but perhaps setting up a parallel set of custom resources that just store the display information for the object classes could be a solution. I’ll have to think a little more about that if the class static function access isn’t possible.
After a little more digging I found a solution for this in case someone else wants to do something similar at some point. While it doesn’t seem to be well documented it turns out that basically the classes in GDScript code are just GDScript Script objects, and you can call static functions on them. So if you’ve got the script path you can just load them as a resource and call the static functions on it.
To get the script_path for a named script class you can use ProjectSettings.get_global_class_list() and then just go through that list to find the path for the class name you’re after. And then you can do something like this:
var class_script:GDScript = load(script_path)
class_script.my_static_function()