Create a Reusable Relationship System in Godot 4.5 - Under 15 Minutes!
345 segments
Have you ever wanted your NPCs to
actually remember how you treat them?
Today, we're going to build a clean,
reusable relationship system in GDO 4.5,
and you'll be able to drop into any game
in no time. Welcome back to GDAU dev
checkpoint. I ran a poll recently asking
what systems you wanted to see most, and
the relationship system won. But don't
worry, we're going to do all of them.
We're going to cover all these topics in
separate videos in the order they were
voted for. Now, creating social systems
can get messy if you hardcode them into
every single enemy or shopkeeper. So,
today we're going to build a
relationship component, a single brain
that manages friendship, hatred, and
everything in between. First, we'll
build our component. Instead of just a
script, we'll make it a scene. This lets
us drag it and drop it into any
character in our game instantly. All
right. I'm here in a brand new project.
I'm going to create a new scene. I'm
going to use other node. Just use
regular node. And I'm going to rename
this node to relationship
component.
Then I'm attach a script to this. The
green icon there. I'm going to make a
new folder. I'm going right click new
folder. Call it scripts.
And I'm going to save relationship
component GD in that and create.
Then I'm going S and save the scene in a
new folder called scenes.
Then save it. Now, let's define what a
relationship actually is. At its core,
it's just a number. We need a starting
value, a maximum value, and a way to
tell the rest of the game when that
number changes. Now, back in our
relationship component script, I'm going
to get rid of the boilerplate code.
Going to add in some signals. So, the
first signal we're going to use is going
to be called affinity changed, and it's
going to have a new amount passed into
it. The second signal we're going to
want to use is a relationship
status changed. This how we're going to
track our friend and foe status or
neutral. We're going to pass status into
that. The new amount into the affinity
change. And we need some export
variables. First one we're going to use
is current affinity.
And we're going to have that to be int.
We're going to start at 50. So neutral.
The next export variable we're going to
use is max affinity.
We're going to set that in to be 100.
So if we're at 100 or friends, then we
need a minimum affinity. So if this is
zero, we're going to be enemies. And we
also need to set the
friend and foe thresholds. So when to
become friends, when to become enemies.
So we're going to set that at 70 to be a
friend.
And for enemies, we're just going to go
to 30. So foe or enemy threshold,
set that in to 30. So it goes below 30,
we're going to be enemies. Then we need
a a function here. And we're going to
call change affinity and we're going to
change it by an amount. And int is going
to be that amount. So say if we give a
gift or if we insult them, we're going
to change that current affinity by that
amount we're passing into this function.
Well, then we also need to emit this
signal to say this happened. So affinity
changed. This is a signal. We're going
to emit it. And what we're going to emit
is the current affinity
right there. So then we need to check
for status changes. Let's check for
status change. So if current affinity
right there is greater than or equal to
our friend threshold, well we need to
change our relationship status.eit
to friend
just like that.
But if it's not if the current affinity
is
less than or equal to the enemy
threshold, well say the relationship
status has changed again to enemy.
But if it's neither of these things,
well, it's going to be right in the
middle. So the relationship status there
is going to be emitted as neutral.
Just like that. Go and save the script.
Now you've reached your first
checkpoint. Stop and look at the code
what we just wrote. Current affinity
plus equals amount. What happens if we
add a thousand to it or subtract a
thousand? We don't fix this. Your player
could have 5,000% love with a goblin or
negative infinity with the merchant
breaking your game logic. We need to
clamp it. So this variant here, clamp
value variant minimum to maximum. That's
what we want to use to clamp our
affinity. So, back in our project, right
below our current affinity here, we want
to set our current affinity
to equal a clamp. We want to set it
between a variant, which is what we want
to set to a minimum and a maximum. So,
go ahead and give that a try. Clamp our
current affinity between the max and the
min affinity. Give that a go and pause
the video now.
How'd that go? Did you get it? Let's go
and do it together. If you didn't, that
is just fine. So, all we need to put
here is our current affinity. We're
going to clamp it between our min
affinity
and our max affinity.
Just like that. Make this bigger. So, we
should also have something that says,
hey, what is our current and old
affinities?
So, our new affinity, we're just going
to print it to a debug console here.
We're going to point out our current
affinity
and that's going to be a debug check. So
you make sure this is going up and down
as intended. The key takeaway here is
always sanitize your data. Using clamp
ensures your values never escape the
boundaries you set, preventing
gamebreaking bugs later. Now for a
little bit of magic. Because we saved
our component as a scene, adding it to
an NPC is effortless. And a number in
the console is boring. So let's make
that visual. We'll add a progress bar
that updates automatically whenever our
relationship changes. Going to make this
smaller here. I'm going to create a new
scene. Scene. New scene.
It's going to be a 2D scene. I'll rename
the root node to NPC.
Go back to my 2D scene here. I'm going
to add a child node of sprite 2D.
I'm going use the GDO icon that comes
with every project as my character. We
also want our new relationship component
in here. the relationship component
scene. We're going to drag and drop that
onto NPC. Now we have it on our NPC.
What we're also going to do is add a
progress bar to see the results. So add
child node NPC, which means the progress
bar so we can see how friendly or faux
we are. Now with the progress bar
selected, I'm going to go over to the
inspector here. I'm going turn off the
percentage. I'm going to set the current
value to 50. So neutral and go down to
layout. set the custom minimum size to
100 on the X so we can see it. I'm going
change the anchor presets to center.
Now I'm going to go into my window here
and zoom in a bit. I'm going use my move
tool. I'm going to drag this straight
up.
There we go. Right above our character's
head. And we're click on our root node
at PC. We're going to add a new script.
We're going to put it in our scripts
folder. Make sure scripts open scripts
create. I'll make this bigger. I'll go
ahead and delete this boiler plate code.
Once that's gone, I'll make this smaller
again so I add some onesies. I need a
relationship component reference. I'm
going to click and drag and hold down
control and drop that. Now I have that
in my script. And I also need the
progress bar. Click, drag, controll,
drop. All right, now I have those. I'm
going make it bigger. Enter down a
couple times. I'm going to create the
ready function
right there. And then I may click pass
real quick as a placeholder. Enter down
a couple times and create a function.
It's going to be called on affinity
changed.
And then we're going to take in a new
value into this function. New val.
And then what this is going to do is
change the progress bar
value
with a new value.
So when this function is called, it's
going to change our progress bar. Then
back in our ready function, we need to
commit to this signal from the ready
function
in the relationship component. The
signal we want to commit to is the
affinity changed. and we want to
connect. And we want to connect with our
function we just wrote on affinity
changed. Now we have the brain and the
visuals. Let's create a fake interaction
to test it. We'll bind the space bar to
give a gift and escape to insult them.
Our component also shouts out friend or
enemy whenever the value crosses those
lines. Let's make our NPC listen to it.
Now we're going to go back to our NPC
script and save it. and the NPC scene.
We also need to save that. And back in
our NPC script and create a new function
underneath on affinity changed. That's
going to be on status changed.
Our new status for our friend or foe.
Now we're going to use we'll just print
out to the console as well. So our
current status
is going to be
our new status.
It helps if you do a underscore in
between. There we go. And then after
that, well, we want a simple visual
feedback so we can see on the screen
what's happening as well. So if new
status
is ren,
well, we're going to change the progress
bar to green. We just do progress bar
modulate
and we're going to change the color to
green.
Just like that. And then well for enemy
of course I'm going to use red. So enemy
progress bar
modulate
to red.
There we go. And also if for neutral
neutral usually runs the gray gambit. So
we'll do the progress part. Modulate
colors gray.
There we go. Notice going to connect
this function to our relationship
component. So back in our ready
function, I'm going to connect the
relationship component, the relationship
status
relationship status changed function.
Connect that to our new function of pod
status changed
and save that. Now we add some input
function here. So underneath the on
status change, we're going to do an
input event function to listen for our
space bars and our escapes. So if event
is action pressed, there we go. We want
to look for UI except that's going to be
our space bar. By default, GDO has a UI
accept in it already, so we don't have
to set that up. So space bar. Now if
that's pressed well this is going to be
the give gift.
There we go. Then we need to change our
relationship component change affinity
change affinity
to 10. And then well if we press escape
we want to do the opposite. So the vent
is action pressed. The cancel is the
escape one. Here I cancel. There we go.
And then we want to set that to be the
it's going to usually the escape button
escape button. And if we do that, well,
we want to print insulted,
right? But we also want to change our
relationship component. Change affinity.
And we want to do that to minus 10.
We're going to go and save that. Make
this smaller. Go back to our 2D scene.
I'm going to zoom out here. I'm going
grab the NPC. Use the move tool. And
this is our viewport window. I'm going
to drag our NPC to the middle so we can
see them. Save. We're in the current
scene.
All right. Now, I'm going to drag up so
we can see the console. I'll press
spacebar. And we go up up. Now we're a
friend. We go up up to 100. Then we stay
at 100. Then escape. Back down. Down.
Down. Now we're neutral. We're back to
gray. Now we're red. Enemies. Down.
Down. tab. Now we stay at zero. And just
like that, you have a fully functional
relationship component. The beauty of
this is that the NPC script doesn't need
to know how the math works. It just
tells the component add 10, remove 10,
and the component handles the signals,
the clamping, and the logic.
You can drag this specific node onto a
shopkeeper to determine prices or a
quest giver to unlock secrets. It's
completely reusable.
expanding this, we can take this a step
further and use resources to give our
NPC specific likes or dislikes. So, you
can't just spam the same gift over and
over. Let me know in the comments if
that's something you'd be interested in.
Now, if you found this helpful at all or
fun, leave a comment what your GDO game
dev goals are. 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 really keeps the channel moving.
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 am Spaghetti Syntax, and
remember, always stay curious.
Ask follow-up questions or revisit key timestamps.
This tutorial demonstrates how to build a clean, reusable relationship system in GDO 4.5, allowing Non-Player Characters (NPCs) to remember player interactions. It covers setting up a relationship component as a scene, defining affinity values and thresholds for friend/foe/neutral statuses, and using signals to manage changes. A key aspect is clamping affinity values to prevent game-breaking bugs. The video also shows how to visualize relationship status with a progress bar and integrate simple player inputs, emphasizing a modular design for easy reuse across various NPC types.
Videos recently processed by our community