How do I "Include" a Script Into Another Script?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Atlas

Hi there!

I’ve created a class/script, “Date.gd”, which simply stores 3 int’s representing a date, i.e. 03/09/2020. This script is located at “res://assets/utils/Date.gd”. I’m trying to ‘include’ it in my Character script, that way I can declare a var _birth_date: Date as a variable for the Character. I’m coming from a Java background, so I’m wondering if there’s similar to “import res://assets/utils/Date.gd” since the Character.gd and Date.gd scripts are in two separate packages/folders.

Any help is appreciated!

(Here’s the code in Character.gd. I’m wanting to replace the “include” with the correct syntax.)

extends Node
class_name Character

include("res://assets/utils/Date.gd")

var _name : String
var _age : int
var _birth_date: Date

oops. Accidentally added an answer here and can’t delete this comment :confused:

hungLink | 2022-12-04 05:45

:bust_in_silhouette: Reply From: Zylann

You can import the script using the following syntax:

const Date = preload("res://assets/util/Date.gd")

Then you can start creating it with Date.new() etc.

Note: if you use class_name on top of Date.gd, you don’t have to explicitely include it, Date will be defined anywhere as if it was imported by default.

Note 2: if you used the class keyword, that actually makes an inner class (which means you’ll need to type Date.Date). Scripts are unnamed classes already by default (unless named with class_name).

Hey, I appreciate that. I saw the preload keyword earlier when looking through the Docs, but I don’t think that’s what I’m looking for. I’ll pass the Date in the Character’s constructor when I initialize it. Would I still use preload even if I instantiate that Date by an argument passed into the constructor?

Atlas | 2020-03-09 23:24

preload (or load) makes the resource available so that you can write it as a “type” to qualify arguments, or use it to create a new instance with new(). GDScript is a dynamically typed language: types can be omitted, so you don’t have to preload everywhere your date is used, unless you really want to write the type everytime (or, you could name it with class_name, which does the same). The syntax with : and types is only arrived recently in the language, and has yet progress to make.

At least, if you want to create an instance of Date, you really have to use either load, preload or class_name.

Would I still use preload even if I instantiate that Date by an argument passed into the constructor?

I’m not sure to understand what you mean by that.
Here is an instancing of a character class, with a date as constructor argument:

var date = Date.new()
var character = Character.new(date)

To be able to write Date and Character like that, you have to have access to the scripts Date and Character represent. In Java, it’s like every class has been declared with a globally accessible name (at least when the package is imported). In GDScript, it’s optional. So you either give a name with class_name, or you import explicitely with load, or preload.

Now considering your character’s constructor, it can be written without specifying the argument type:

func _init(date):
    ...

Or, it can be written with the type:

func _init(date: Date):
    ...

But again, being able to write Date means Date must be referenced in the same way, either with an explicit, or global import.

Zylann | 2020-03-10 01:47

Hey, I appreciate the help. I’m confused still, though. In my Dateclass, I am using class_name Date, so how do I “import” or “include” that in my Character script so that I can use references and functionalities of Date? Even if I use the class_name keyword, do I still have to preloador loadit? Or is there some way in which I can import a script that has a class_name? I’ll include both the Dateand Character scripts below.

extends Object

class_name Date

var day : int
var month : int
var year : int

func _init(d, m, y):
day = d
month = m
year = y

And now the Character script:

extends Node
class_name Character

var _name : String
var _age : int
var _birth_date = preload("res://assets/utils/Date.gd")

func _init(date):
_birth_date = date

I suppose why I’m confused is because, lets say I want to have multiple Dates, such as _birth_date, _date2, _date3, I would have to set each of those = preload("res://assets/utils/Date.gd") rather than there being some general “import” or “include” statement that would allow me to reference any Date functionality I want wherever in that script. Just coming from Java “import” statements, this has me scratching my head.

Atlas | 2020-03-10 22:02

Hey, I appreciate the help. I’m confused still, though. In my Dateclass, I am using class_name Date, so how do I “import” or “include” that in my Character script so that I can use references and functionalities of Date?

I told you how to do that in my initial answer.
If you mean “include” as in “copying the insides of the script in the place of the include”, this is not possible in GDScript. It’s all done by referencing the script, not copying it.

Even if I use the class_name keyword, do I still have to preloador loadit?

If you use class_name, preload or load are not needed.

Or is there some way in which I can import a script that has a class_name?

As I explained earlier, scripts with class_name already are available everywhere as this name, as if they were imported by default.

I suppose why I’m confused is because, lets say I want to have multiple Dates, such as birthdate, _date2, _date3, I would have to set each of those = preload(“res://assets/utils/Date.gd”) rather than there being some general “import” or “include” statement that would allow me to reference any Date functionality I want wherever in that script

But this is exactly what I try to explain^^ You only need the preload once:

const Date = preload("date.gd")

func _ready():
    var date1 = Date.new(10, 3, 2020)
    var date2 = Date.new(11, 3, 2020)
    var date3 = Date.new(12, 3, 2020)

and if you used class_name, you don’t need to use preload at all.
I still mention it, because you might see others use this, and some rare times it is necessary (as circular references can happen, unlike Java).

Just coming from Java “import” statements, this has me scratching my head.

In GDScript, the pattern of writing const Date = preload(...) is equivalent to import Date; (more or less).
class_name makes this automatic so the import is not even needed.

Some extra note about your date script:
You made it extend Object. In Java, all objects are automatically freed when no longer used (garbage collected). But in Godot, Object is not, and has to be freed manually once you no longer need it (using the .free()) method. It’s the same for all classes inheriting Object, like Sprite or Button. In the case of nodes, their parent can also take care of that.
However, anything that inherits Reference will be automatically freed when it gets out of scope (like all Resource classes). By default, if you don’t specify extends, a script will inherit Reference.

In your character script, you wrote:

var _birth_date = preload("res://assets/utils/Date.gd")

This assigns the script (i.e the Date class) to _birth_date. You may want to assign an instance of that class instead, or just specify its type, like so:

var _birth_date : Date

Zylann | 2020-03-10 22:49

:bust_in_silhouette: Reply From: hungLink

Hi there! I’m a bit of a Godot newbie, so feel free to tell me if this is bad practice or something.

What I do is create a node called “Includes” and then a child node for each include that I need. I associate the nodes with the scripts in the editor, and then call them in the script like this:

var includeFoo = $Includes/Foo