Godot 4.6: Master Classes & Inheritance (Build a Droid Factory!)
466 segments
Stop copying and pasting code. If you
want to make a game with 50 different
enemies, you don't need 50 completely
different scripts. I'm going to show you
how to write code once and then use it
to spawn an army of unique droids.
Welcome back to GDO Dev Checkpoint.
Today, we aren't just writing scripts.
We're building an architecture. We're
going to build a droid factory. And
thank you to our new Patreon member,
Elon. Your support helps keep the lights
on. Now, let's open up GDO 4.6 six and
get to work. First, we need to
understand what a class actually is.
Think of a class as a blueprint. A
blueprint for a house isn't the house
itself. You can't live in the paper, but
you can use that one blueprint to build
10 identical houses. The first thing
we're going to do is we're going to
create a new folder. Rightclick our root
folder in our file system. Create new
folder. We're going to name this folder
scripts.
In this scripts folder, we're going to
create right click, create new script.
We're going to call it droid. Create.
Now, we're going to delete all this
boiler plate. We don't need it. Up on
top here, what we want to do is write
class name. I'm going to call this class
name droid. Now, this class name droid
line is the magic. It tells GDAU, hey,
this isn't just a script file anymore.
This is a global type called droid. And
you're going to be able to now use this
droid anywhere in your project just like
you use node or sprite 2D. So in this
class, what we're going to have is a
variable serial number for a droid and
it's going to be of type string
and we're just going to set it initially
to x
00 x-0000
just a base default name. And then we're
going to have a battery level for our
droid. Let's set that base level to a
type int of 100. So fully charged. Now
when we build our droid, we're going to
initialize it with the initialize
function function underscore init.
You can tab to autocomplete,
but we're going to add
a parameter here in the parenthesis
called new serial.
We're going to change the serial number
and give them all unique serial numbers.
It's going to be of type string.
Perfect.
Enter down into the function. And then
we're going to set the serial number to
the new serial number. So then the
serial number we pass into this
initialize is going to become this
droid's new serial number.
Enter down. And then we're going to have
a print statement for the output. It's
going to be droid space,
comma, serial number,
comma, another quotations, has been
assembled.
So, this is going to say the droid, and
it's going to take the serial number
that's been assigned to it, and say it
has been assembled. Now, a robot needs
to do something. Let's give our droid a
job. Now, still in our droid script
here, I'm going to enter down a couple
times, create a new function. I call
this function perform task no
underscore.
In the beginning, it's going to be of
return type
void. So, we're not going to return
anything. And in this, we're going to
have a battery level that we're going to
minus saying
this task has been performed. Now, let's
take some battery away. Take 10 battery
away. So, 10%. Then we're going to print
in the output the serial number of our
jury comma quotation
colon space we're going to say idling 1
2 3 battery
at
comma after the string we're going to
pass in the battery level and then we're
going to add a percentage sign at the
end.
There we go. And then a parenthesy.
Make this bigger so you see it. There we
go. Save the script.
Now, this class is going to be the
default behavior for any generic droid.
I'm going to highlight the parameters in
this print statement here. So, it can be
a little confusing sometimes. Now, this
is the safe mode for printing. If you
tried to use the plus signs instead of
these commas, well, this wouldn't work.
It would actually crash. As you can see
here, you can't actually just put an int
into a strict language like GDScript.
So the only way you can do this is you
actually have more syntax with the str
and then take this battery level and if
you highlight it, you can press the
parenthesy
and then it puts parenthesis around it
and then it's okay to print just like
this. However, instead of doing it so
much like this, a lot less syntax just
to use a comma.
So, when you use commas, GDO says, "I
got you." It automatically converts
those numbers into text. It stitches
everything together into one nice debug
message and strictly type languages like
GDScript.
This throws an error because it's
ambiguous. It's addition versus
concatenation.
And this just saves us from having to
type string every time. Now to quick
side note, you might be wondering why in
it has an underscore, but our perform
task does not. Well, in GDAU, an
underscore at the start of a function
name like in it or ready even usually
means it's a life cycle function, which
means GDAU calls it automatically for
you. You don't have to tell the droid to
in it. The engine's going to do it for
us the moment that this droid is born.
Functions without the underscore are
custom. Those are the ones we have to
trigger manually in our code. Now,
you've reached a checkpoint. I want you
to add a function called recharge. And
it should set the battery level back to
100 and then print a message saying the
Droid is fully charged. Maybe want to
try this without the hint. Go ahead and
pause now and give it a try.
Now, for those who might be a little
stuck, that's okay. Maybe a little bit
of a hint. What we need here is we're
going to create the recharge
function
and then we're going to set the battery
level to 100. And then we're going to
print a message saying the droid is
fully charged.
And that's it. If you want to take a
look at the perform task function here,
it can help you out quite a bit. Go and
pause now and give it a try.
All right, hopefully you gave that a
try. What we're going to do here is I'm
going to create the recharge function.
It's going to be function recharge.
That's going to return nothing. So, it's
going to be a void. It's not going to
take any parameters in. So, we're good
there. Now, we want to set the battery
level to 100. So, we're going to take
the battery level and we're going to
equal that to 100. And then we want to
have a print statement saying, "Hey,
we're fully charged." So, we're going to
take our serial number of the droid that
we're saying anything about, comma,
separate
quotation, colon, and then recharged to
full power.
Right? That's it. Then save the script.
Now the key takeaway here is classes
hold both data variables and actions
functions. They are self-contained
packages. Now we need a security droid.
We could copy the code from droid.gd
but that's messy. Instead we're going to
use inheritance. I'm going to make this
smaller. Then in my scripts folder we're
going to rightclick and then create new
script. We're going to call this script
security
droid.
There we go. Create. Now, in our
security droid here, get rid of this
boilerplate code here. And then, instead
of it extending, instead of extending
node, we're going to extend droid. And
because we write extends Droid, this new
script automatically has the serial
number and the battery level and all the
functions in Droid itself without having
to write them in the Droid script
itself. Right now, above this extend
droid, we're actually going to make this
a class
name as well. This is going to be our
security dur.
Great. Then below extends, I'm going to
actually add some laser power
in case our
security droid needs to secure things.
Type in make it 50. Now we're going to
do something called overwriting
functions. I'm enter a couple times. I'm
going write the function perform task.
And if you see it actually will
autocomplete because we have this in our
Droid function. We're going to write
this function as well. And in this
function, we're actually going to use a
keyword called super,
which basically means do the things in
the Droid class that the perform task
already does. So back to Droid, it's
going to do all this stuff
before it does anything else. So we do
super.perform
task. So I'm just calling that function
basically.
Droid call this function. do this stuff
and then what I'm going to do after that
is I'm going to do anything else which
for this guy I'm going to say the serial
number which I have access to because I
extended droid
I'm going to say scanning for intruders
intruders. Yeah, I spelled that right.
If I find them pew pew. There we go. So
this once again the super.perform
perform task is just calling that
function to do the basics. So we're
going to do do the default droid stuff
which is drain battery
because once again go back to droid this
perform test does not have an
underscore. So in order for this to run
we have to call it which we're doing
here. So once we drain the battery we
drain the battery because we're scanning
for intruders.
So now we know the super actually calls
our parent version of the function. So
we still drain the battery and then we
can actually add in some logic to blast
the lasers. For now we're just going to
do the print statement. In the future
you can actually use this laser power
for something else. Now a common
question is I want to attach this script
to a character body 2D so it can move.
Can I extend that as well? Well the
answer is single inheritance. You can
only pick one parent. You cannot say
extends droid and character body 2D. But
we can use something called a chain. Now
if we go back to droid.gd
and change the first line to extends
character body 2D. So back in our droid
script and under class name we say
extends
character body 2D.
Then save that. So now because security
droid extends droid, it inherits
everything droid has which now includes
all the physics and movement from its
parent which is the class stuff in droid
and character body 2D. It's a package
deal. So the droid gets a serial number
from droid and the move and slide
functions from character body 2D. For
example, if I go back to security droid
and under here just for testing, we're
going to delete this, but just to look
at it function, the move and slide is in
the physics process. If I enter there,
type in move and slide. You see it
autocompleted and I can save that and I
have that in my security droid now. But
if I go back to Droid and then I get rid
of this character body TD and then I
save it. Notice then we'll get an error
saying move and slide not found in base
self because this does not have access
to character body 2D anymore. If for
example you cannot do this
that's not a thing. So you have to only
extend one thing. If you want to chain
things has to come from above to the
parent. I'm gonna delete this.
Save the script. Now there's an
alternative method. It's a little more
intermediate. It's called the brain
method. Now if you don't want every
droid to be a physics object, maybe some
are just UI data, you would keep the
droid as a data class and just use
something called composition.
So what is composition? Well, script A
would be droid. which has the data, the
health, and the name. And script B, your
security droid. When we change that,
I'll comment this out here real quick.
And then we extends
character body 2D in here. And then we
can enter down. And how do we get this
perform task back? Well, what we have to
do is do something called a link, which
is creating a variable base droid stats.
Stats
is going to be of type droid, it's going
to equal droid new.
And you'll notice we need to actually
put in an argument. If we go in our
droid, what the initialize is looking
for is a string. So, what's the droid's
name? So initializing we just put an
empty string. So just quotation marks
that solves that. And then we would have
to copy this base droid stats and put it
instead of super
base droid stats perform task instead of
serial number base droid task or stats
dot serial number. And that's how we
access that.
We'll go and keep it the way we had it.
More cleaner I think. and actually
is more readable in the end. And if we
do it that way, we'll have to change how
we're giving it in our next part. So,
we'll do it just this way in the end. It
just shows there's multiple ways to do
things. I'm going to save that how we
had it. Our class name droid, a class
name security droid, and we're going to
extend droid and use the super keyword
and then use it just like that. But that
is composition.
Now we have the blueprints. Now let's
build the factory and actually spawn
them. All right. Now we're just going to
create a standard 2D scene. We're going
to rename the node 2D. We're going to
create a factory.
We're attach a script to this factory.
And we're going to put it in a scripts
folder. Not the root folder. Double
click the scripts. Open. Then create.
I'm going to get rid of the process
function. We don't need that. And then
in the ready function, we'll use that.
We're going to do first is create a
basic droid.
How do we do that? We're going to put in
a variable worker type droid. It's going
to equal droid new. Just like we kind of
saw earlier, we're going to name this
droid. We'll name it W1.
Perfect. Now, we're going to create a
security droid.
They have two different kinds of droids.
And then it's going to be the guard,
but it's still going to be of type droid
because says security droid extends
droid, it is still a normal droid. And
that'll be important in just a second.
So equals security droid. And we're
going to make a new one. We're going to
name this security droid 900.
There we go. So, we have our welcome and
our security droid. So, now what we're
going to do is put these droids in an
array and put them in an array.
We're going to use factory units. These
are our factory units in the factory.
So, all of our droids and be of type
array. And in this array is going to be
droid.
And the droids we're going to put in the
array are well the ones we just made.
the worker and the guard.
Since our security droid extends droid,
this array only has to be of type droid.
Doesn't care if it's a security droid as
long as it's a droid. Now we have our
array. Well, let's run them all so we
can see them in our output. And how do
we do that? Well, we use a for loop for
and all the unit in factory units has to
go through the array. And when it does,
well, we're just going to perform the
task. Unit perform task. So that's our
custom function. So our regular droid is
going to do perform task here in the
base class. And in our security droid,
it's going to perform task here, which
does the basic one, but also the extra
stuff we put in there. Great. So, in our
factory, going to save that. We're going
to save this factory scene. Right click,
new folder, scenes folder. So, it's good
to stay organized. And then we're going
to call it factory.
Save.
Right. Now, press F6 or run the current
scene here. and start. And now you see
here the Droid 101 has been assembled.
Droid S900 has been assembled. 101 is
idling. Battery is at 90%.
Idling battery at 90%. They both
performed a task. And this one actually
the security bot scanned for intruders,
found one. Keep it. Notice the magic
there. The array that's typed array
droid, but we put a security droid
inside it. Well, that's called
polymorphism.
The factory doesn't care what kind of
droid it is as long as it is a droid.
Then it can call perform task. So to
recap, we created a class name to define
a global type. We used extends to
inherit all that functionality into a
specialized version. And we used super
to keep the original logic while adding
new flavor. Now to take this further, we
could take these scripton classes and
turn them into resources. So we can edit
their stats in the inspector without
writing code. We can make them visual in
a 2D or 3D atmosphere. And you let me
know in the comments if that's something
you'd like to see in a future video or
do it yourself and I would love to see
your results. Now, if you found this
helpful at all or fun, leave a comment
on what your GDAU gamedev goals are. And
please like, subscribe, and hit that
notification bell. It really helps out
the channel. And thank you to all our
current and past Patreon and coffee
members. Your generous support keeps the
channel moving. Now, if you want early
access to tutorials, source code, or
suggesting future tutorials, please
consider becoming a member yourself. The
links are in the description. I
Spaghetti Syntax, and remember, always
stay curious, and I'll see you at the
next checkpoint.
Ask follow-up questions or revisit key timestamps.
The video demonstrates how to efficiently create various game entities using GDScript classes, avoiding repetitive code. It begins by explaining classes as blueprints, then walks through creating a base `Droid` class with properties like serial number and battery level, and functions for initialization and task performance. The tutorial introduces inheritance by showing how a `SecurityDroid` class can extend the `Droid` class, inheriting its base functionality and adding specialized behavior using the `super` keyword to augment parent functions. It also briefly discusses single inheritance versus composition. Finally, the video showcases polymorphism through a "Droid Factory" that spawns both basic and security droids into a single array, demonstrating how they can be treated uniformly despite their specialized functions.
Videos recently processed by our community