Create a new script. Each script is a class (optionally named with the class_name keyword).
Use the class keyword in a script. It creates an inner class.
Here's an example with two inner classes:
class Person:var name :=""var age :=0class Superhero extendsPerson:var power :=""
Inner classes have a limitation compared to creating scripts: you cannot instantiate them from the editor, so you can't use them for nodes and resources that you'd like to interact with in the editor. You can only use them for data containers and helper classes.
But inner classes offer at least two benefits:
They allow you to keep related classes grouped in a single file. It makes it easy to read and maintain related code.
Their names are scoped locally, which helps to hide them from the rest of the project.
In this example, I define an inner class with a leading underscore, _Power to share code between the Flight and Fire classes and hide it from the outside world:
class_name Powers:class _Power:var name :=""class Flight extends_Power:var duration :=10class Fire extends_Power:var strength :=5
With a script like this, anywhere in the project, you can call Powers.Flight.new() to create a new instance of Flight.
Grouping related classes together like this is something we call "namespacing". It compartmentalizes the code and helps to avoid naming conflicts. Imagine that you want a power named Fire and that you also need to define the magical element Fire in your game.
Because the Fire power is an inner class, you access it as Powers.Fire, and you can have two inner classes named Fire in the same project without conflicts.
Using inner classes for strongly typed data containers
Another feature of inner classes is to create well-typed objects to store data. Suppose I have a complicated function to get user properties for a web server connection. I could return a dictionary:
But then to know what keys are available, I need to look at the function's documentation or the source code. If I try to access a nonexistent key, I won't get any error until the game runs. It's a common source of bugs.
Instead, you can use an inner class to define the data structure: