Handling Classes in Godot

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By tmattoneill
:warning: Old Version Published before Godot 3 was released.

Sometimes Godot’s similarity to Python is deceiving. I’m really struggling to understand how to use classes.
I get that you build a class in a separate file and then preload or load that file into the script that you’re calling it from. But I don’t see how to pass in initial values or how to use the constructor.
In python I would just do:

class MyThing():
    def __init__(self, var1):
        self._var1 = var1

    def set_val(self, arg):
        self._var1 = arg

    def get_val(self):
        return self._var1

thing = MyThing(100) # create a new thing with a 100 value
print (thing.get_val()) # print out the value of thing
thing.set_val(50)  # change the value to 50
print(thing.get_val()) # print out the new value

How would I do a similar thing in Godot? I am mainly wondering:

  • How do I pass in the initial value when creating the instance of the object
  • How do I build the constructor

So imagine I’m using:

  • main.gd
  • object.gd

and I’m instantiating the object in main.gd with a var thing = new load(“object.gd”)
THANK YOU!!!

:bust_in_silhouette: Reply From: eons

With var thing = load("object.gd") you will get a GDScript resource.

var instanced_thing = thing.new() to get an instance of that resource.

Then instanced_thing.my_init_setter(a,b,c,d) to set initial values.

Ah. Useful but still weird. Normally you can pass in initial values when you create the instance, e.g.:

item = New Item("item name") 

and the purpose of the _init constructor is to take that value and add it to the object.

So I might do that like:

var Thing = load("res://object.gd")

var thing1 = Thing.new(100)
var thing2 = Thing.new(50)

print (thing1.get_val())  # will output 100
print (thing2.get_val()) # will output 50

Will that not work if I have a func _init(value): in my object file?

thing1.

tmattoneill | 2016-11-09 22:11

_init can be overriden but does not have any parameter.

Some default methods (like _init, _ready, _process) have implicit calls for superclass so is better to avoid them if making subclasses of your scripts too (this may change on Godot 3).

eons | 2016-11-10 03:10

:bust_in_silhouette: Reply From: tmattoneill

So I’ve gotten some conflicting advice and some that I don’t understand. However, I have figured this out so I thought I’d put the answer here.

There’s a few ways to do this.

First, there’s the way of doing it within one script. This works as expected and is the most ‘pythonic’ example.

my_script.gd:

class MyThing:
    var _var1

    func _init(var1):
        self._var1 = var1

     func set_val(arg):
        self._var1 = arg

    func get_val():
        return self._var1

func _ready():
    var thing = MyThing.new(100)
    print (thing.get_val()) # print out the value of thing
    thing.set_val(50)  # change the value to 50
    print(thing.get_val()) # print out the new value

The Second way is to manage classes in multiple files. Here I’ll have a file to define the class my_thing.gd and a main class file main.gd that calls and instantiates new items.

main.gd:

var thing = load("res://my_thing.gd").new(100) # create a new thing with a 100 value
print (thing.get_val()) # print out the value of thing
thing.set_val(50)  # change the value to 50
print(thing.get_val()) # print out the new value

my_thing.gd:

# Class my_thing.gd
# takes a value and allows you to view, update or change it.

var _var1

func _init(var1):
    self._var1 = var1

func set_val(arg):
    self._var1 = arg

func get_val():
    return self._var1

But I think the cleanest and best way to manage it is a slight variation of the above. The my_thing.gd remains the same but I manage the instances in main.gd differently.

main.gd

var Thing = load("res://my_thing.gd") # create a Thing reference object
thing = Thing.new(100) # create an instance with initial value of 100 of a Thing
print (thing.get_val()) # print out the value of thing
thing.set_val(50)  # change the value to 50
print(thing.get_val()) # print out the new value

I really like this as I can now do things like:

var things = []
for i in range(100):
    things.append(Thing.new(0))

and get a nice clean list of new things!

Why don’t you link to your cross-post at /r/godot ?

atze | 2016-11-10 08:43

I didn’t realize you could do the first one with classes. I was thinking of only nodes, and how they have to be instanced.

I checked it out, and you could also keep you classes in a separate GD script and use them as such:

class.gd

class my_class:

	var m1
	var m2

	func _init(parm1, parm2):
		m1 = parm1
		m2 = parm2

And called like:

extends Node2D

func _ready():
	
	var script = preload("res://class.gd")
	
	var thing = script.my_class.new(1,2)
	
	print(thing.m1)
	print(thing.m2)

avencherus | 2016-11-10 09:01

Yes, you can work with normal classes and inner classes that way, I thought he refered to Object subclases

eons | 2016-11-10 11:55

:bust_in_silhouette: Reply From: atze

Since tmattoneill doesn’t do it himself and there is some valuable information I just link to the same question he asked on reddit:
https://www.reddit.com/r/godot/comments/5c3qq5/managing_classes_in_godot_help_a_python_guy/