+8 votes

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!!!

in Engine by (46 points)

3 Answers

+2 votes

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.

by (7,910 points)

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.

_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).

+14 votes

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!

by (46 points)
edited by

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

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)

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

+1 vote

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/

by (488 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.