I'd like to build a reusable library in GDScript. When building libraries in the other languages I'm familiar with, JavaScript and C#, I typically utilize two features that GDScript doesn't seem to have:
In GDScript, (1) seems to be solved by underscoring private methods. While I find this less useful than explicit private functions, I did find the Godot proposal where adding this feature is being discussed.
This question is about how to work around (2), which allows large and complicated libraries to be split up into an arbitrary number of files. The two options I can think of are:
class_names
to split the functionality into multiple files. For example, having one script that exports the public API which specifies the library class_name
. For example class_name MyLibrary
. Then, the other files would specify class names like class_name MyLibrary_UtilA
, MyLibrary_UtilB
, and so on. The documentation would only refer to MyLibrary
, and users would hopefully not tinker with the internals.I dislike (2) because it pollutes the global scope, while the solutions to this problem in JS/C# don't have this side effect.
Am I missing any GDScript functionality that would be better suited to organizing large/complex libraries, or are these two options the best approaches?
The specific project I'm working on now is a port of a large library that in C# or JS would be split up into maybe something like 50+ different files.
Yes, there another way, which might work for you.
You can use preload
with a relative path to reference your scripts. For example:
const MyClass := preload("my_class.gd")
You can then use that constant as the class. For example:
var obj := MyClass.new()
This is because:
GDScript
(which is a Resource
) are GDScript classes. That is, GDScript
is a meta class.const
and preload
are resolved during parsing (i.e. preload
is a constant expression). So - unlike using load
- the type information is available while writing the code.This way:
class_name
, so you do not pollute the global name space. Addendum: You can still use class_name
, for example you might use class_name
only on classes that are intended to be instantiated by client code.