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:
- Public/private functions to clearly define the public API
- Explicitly linking two files together (imports in JS, classes in C#)
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 around 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:
- Don't split the library at all, and write everything in one file. While this works for simple libraries, it doesn't scale to very large libraries.
- Using a naming convention built on top of
class_namesto split the functionality into multiple files. For example, having one script that exports the public API which specifies the libraryclass_name. For exampleclass_name MyLibrary. Then, the other files would specify class names likeclass_name MyLibrary_UtilA,MyLibrary_UtilB, and so on. The documentation would only refer toMyLibrary, 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
preloadwith a relative path to reference your scripts. For example:You can then use that constant as the class. For example:
This is because:
GDScript(which is aResource) are GDScript classes. That is,GDScriptis a meta class.constandpreloadare resolved during parsing (i.e.preloadis a constant expression). So - unlike usingload- the type information is available while writing the code.This way:
class_name, so you do not not polute the global name space. Addendum: You can still useclass_name, for example you might useclass_nameonly on classes that are intended to be instantiated by client code.