Godot 4.5 Tutorial: Interaction System & Physics Doors (Backrooms Part 4)
742 segments
We are a ghost in a shell. We can walk,
we can look, but we can't touch. To make
this a game, we need to interact with
the world. Welcome back to GDO Dev
Checkpoint. In the last video, we nailed
that VHS look. Today, we're going to
make it functional. We need a way for
the player to tell the game, I want to
use this object, whether it's a door,
light switch, or an item. Today, we're
going to build a universal interaction
system using Raycast and GDAU's tweening
engine. and we're going to learn two
things. How to bake custom grid map
tiles using CSG and how to write an
interaction system so we can open them.
Now, in a firstp person game, your mouse
cursor is the center of your screen. We
need a laser beam shooting out from our
eyes to detect what we are looking at.
Now, back in our project here, we're
going to go into our player scene.
Then we're going to go into the head
section into our camera 3D. And our
camera 3D, we're going to right click
and add a child node.
We're going to add a raycast
3D
right here. Create. And rename this
raycast to interaction
ray.
Just like that. And we're go into the
inspector with the interaction ray
selected in our target position here.
We're going to set this to zero on the Y
and then -2 on the Z. Now, if we go back
down here, we can see we have our camera
here. We have our ray cast is this blue
line here. Now, if I was a control Z and
redo undo what I did right there, you
see our raycast here is pointing down
towards the ground. Now we want it if I
Y zero, it's going to bring it up to the
middle here. And then if I redo the -2,
now we have this raycast pointing out
from our center of our camera, which is
our eyeballs. So whatever we're looking
at, that's we're going to be able to
touch. And always make sure this enabled
is true. If it's disabled, you can
disable the interaction. Turns gray. And
if it's a blue, means it's on.
It's also nice to have some sort of
reticule which also hopes helps with
motion sickness for people too if they
have something to look at in the middle
of the screen. We go to our camcorder UI
right here. We're going to right click
and add another child node, a label
right there. And we're going to rename
this label to aim dot.
Now we're going to do the same thing we
did on the record label. Now you can
just go to the
record label and the dot here. We can
copy this. Crl C and then the aim dot.
Ctrl +V.
Perfect. And if you don't remember how
to get that, remember it's at our
character map and the unit code for in
the advanced view is 25 CF. That's a
little dot here and you can copy it from
here.
After we have that dot in there, we're
going to change the aim dot
anchor full wreck. It takes up the whole
screen.
So that way when we change our
alignment,
we're going to change it to center
vertical alignment center. Now we have a
dot right in the middle of the screen to
help us aim just right where our raycast
is. or make the dot a little smaller and
scroll down to theme overrides,
font sizes. Just going to change it to
eight. A little less intrusive that way.
Go ahead and save that and take a look
at it. Go back to our world scene. We're
on the current scene.
We see a little dot in the middle.
Turn off my highlighter to make it more
visible. Now, this little dot will help
with selecting things when we get things
into the level. Now, we need to update
our input code a little bit. When we
press interact, we check the laser. If
it hits something, we ask, do we have an
interact function? First of all, we need
to add an interact function, or not a
function, but an interact setting in our
input map project. Project settings.
I'll bring back my highlighter here.
And then we go to the input map. And
then we need to add a new action called
interact.
Press enter and scroll down. An interact
function we just made or action we just
made. Add new event. And we're going to
use well, let's use E. There we go.
Press. Okay. And we also add left mouse
button. There we go. So E or left mouse
button. Those are pretty standard. Pick
up or interact.
Go and close that. Now we're going to go
back into our script and our player
script. I'll make this bigger so you can
see. Make this down. We're going to go
into our unhandled input function here.
Click that in my filter methods.
Now we're going to keep all our mouse
look and our flashlight logic. from
enter down below the flashlight toggle
here. And this is going to be our
interaction logic.
So we just need to check for an event if
the action is pressed like we did with
the toggle flashlight here. So if event
is action pressed
and we're going to check for the event
of the one we just made interact.
And if that happens, well, we need to
check if our array that we just made is
colliding with anything that has an
interact function. So if the interaction
interaction
ray, which we actually need to put in
our variables, we need to actually have
access to it. So I'm going to minimize
this. We go back into our layer scene
here and we need to get our interaction
array right here. And right in this
onready right below all our other
onreies, we're going to take this
interaction array, click, drag, and
drop. And now I have access to the
interaction array in my player. I go and
make this bigger. Scroll down back to
where we were. if interaction array now
that we have it.get
collider.
There we go.
And then once we know if it has a
collider, we can get it. We need to
store that collider. So var collider.
Then we're going to get that
interaction.
Ray get collider.
Now that we know it has one. There we
go. We don't want to try to get it if we
don't know it has one.
We get an error that way. And then after
we have the collider, we want to check
if that collider
has
a method.
Has method. Uh yeah, we'll do this. Has
method. There it is. Interact.
And if it does have that method, well,
we're going to use our interact function
that we know it has. So if a door has
the interact function, which it will if
you want it to be opened,
to say it has a locked door, you can
make it so it doesn't do anything. Or
you can change the interact method if
locked do this other thing. So I put a
little comment above that saying if the
object
has
an interact function
I could spell
call it.
So funny out this is something called
duck typing.
So duck typing.
So basically that just means if it
quacks like a duck,
it's a duck.
Now it's a programming concept.
And how the definition goes, it's an
object's suitability for a task is
determined by its behavior, methods, and
properties it has, functions, rather
than its explicit type. A lot of the
programming concepts are pretty fun to
read about. You can find a lot of it on
Wikipedia, Stack Overflow, even a
gdotutorials.com
has a whole section on it. So, if you
want to deep dive into that, there's
plenty info there. In our context for
this tutorial, well, it just means the
player's interaction raycast. It doesn't
need to know exactly that the object is
like a door, tape, or light switch. It
only needs to know the specific function
method is available.
This means we can add this interact
function to anything we want. The
monster even and we never have to come
back and change this again. Very
flexible. As long as the object has
interact function, the player can use
it. Now, before we make the door, we
need somewhere to put it. We don't want
to manually place walls with the grid
map or light can leak through and the
Z-index thing can get weird. So, we need
a specific doorway tile. We'll build
this out of one piece with use a cookie
cutter for our door shape. So the
texture stays consistent. So going to
use the CSG subtraction method. Now we
need to go to our mesh pallet scene 3D.
Make this smaller.
Okay.
Now right click the mesh palette, add
child node. It's going to be a CSG
combiner
node here.
Create. I'm going to rename this to door
frame
builder.
doorframe_builder.
I'm going to add a child node to that.
The CSG box right there. Then the size
in the inspector, I'm going to change it
to four four 0.2.
That's the same size and width of our
wall. I'm go and hide these floor wall
ceilings for now. So, we just have our
door here. And I'm add another CSG box
to the door frame builder there.
Then I'm going to change this operation
here in the CSG shape 3D from union to
subtraction. So now we have a cookie
cutter. It's going to cut a hole in this
wall we have. I'm going to change the
size for this to a door size. We use
1.25,
2.5,
and 1.0. Thick enough to cut through the
wall itself. I'm going to change the
position of this to the door spot. So,
back in our transform here, position
we're going to use zero Y0.75.
And now we have it down on the floor.
So, we have the doorway.
Great. Now, we take our door frame
builder. So, select the CSG combiner
node. What we're going to do here, we're
going to select this CSG section here in
the toolbar. We're going to bake this
mesh instance.
And now we have an instance of our
doorway. I'm going to rename this new
mesh to wall door.
Now we can hide this for now with this
wall door here right above it. And this
needs a collision shape just like our
other ones. So with the wall door
selected, the mesh, we're going to
create a collision shape and not a
sibling. We want it to be a static body
child mesh. Create. And now this has
collision just like our other ones. We
also need to change the position because
we save the transforms when we export.
So our position for this is just going
to be just where the wall is. So
position Y 2, Z2.
There we go. We also want it to look
like our
other walls and all that. So with our
wall door selected, scroll down to
surface material override or scroll up.
There it is. right there. Go into where
our materials are and our wallpaper and
our wallpaper color. Drag and drop. And
then we also need to set in the
resource. Scroll down to roughness
wallpaper rough.
And then in our normal map, select that
on wallpaper normal.
We also don't want to forget our UV UV
one. And then the trip planer on. And
we're set the scale of the trip planer
to 0.5.
Perfect. Now it matches exactly our
wall. So if our wall shows up, you can't
even tell the difference.
Great. Now minimize that. And we don't
need our door frame builder anymore.
Could delete that. Delete door frame
builder. We have our wall door. We'll
turn our ceilings and the walls back on.
Now they're all in there. Position
correctly. Save the scene. Now we need
to export scene.
Export as mesh library.
And in our resources, we're just going
to overwrite this mesh pallet here.
Apply mesh instance transforms. If you
don't do that, they won't be in the
right spots. Save.
Overwrite.
Perfect. Now back in our world. Now,
sometimes GDAU needs a little help
finding
new meshes we add to our mesh pallets.
We go to our walls here. It looks like
it found it just fine. Perfect. If it
doesn't, yours doesn't come up. You can
just delete this mesh pallet,
clear it from your mesh library,
uh, restart the project, and then
do the same export as, and then put it
back into the grid map in the world.
Your positions will be saved
um, after you drag and drop your mesh
pallet back in your mesh library, but
then your new mesh will show up. At
least that happened to me a couple
times. Hopefully it doesn't for you and
it works just like it did right now.
Let's build a door. But we can't just
rotate the mesh or we'll spin around its
center. We need a hinge just like a
normal door. Now let's make a new scene.
So scene new scene. Then make a root
node 3D scene. Going to change this node
3D name to door. And then we're going to
add a child node of node 3D.
create. And we're going to change this
node 3D name to hinge. Now, the hinge is
going to need to be where the hinge
should be on the edge of the door. So,
we're going to take this transform of
this hinge and divide it by half or at
least. Yeah. So, our door is going to be
1.25. So, we want our hinge to be minus
0.625, 625,
which is half of 125.
And then after we have that set proper,
we could add a child node to our hinge
static body 3D.
Then we're going to add a mesh instance
3D as a child node to our static body
3D. Mesh instance 3D. The mesh we're
going to use is a in the inspector,
we're going to use a box right here.
Our box mesh, we click on the resource
here. The size of our box mesh is going
to be 1.25,
width or height 2.5, width of 0.1.
So it fits in our door frame of 0.2.
Then we need to add collision or static
body 3D. We're going to right click, add
child node, collision
shape 3D.
Our collision shape is going to be a box
and it's going to be the same size as
our door. So you select the box shape 3D
after we select it in the shape and the
collision shape 3D. Change the size to
just the same size as the door. 1.25,
2.5, 0.1.
There you go. that matches the door
perfectly. We also, if you look at our
hinge,
you'll see that it is in the center of
the door. So, we need to change our
static body 3D, the root. And then we're
going to go to our transform.
And what we're going to do here is
change the X to the opposite of the
hinge. So, instead of minus06.25,
it's going to be just positive 0.625.
And then if you click on the hinge, you
can see it's right on the edge of the
door. So we have our door here in the
middle and our hinge on the edge. So
this hinge will be able to swing this
door back and forth.
Well, whichever direction you want it to
swing. Usually doors only swing one way.
Ours will swing out. Now you've reached
a checkpoint. We have the door
hierarchy. Now we need to get the door
to turn. How do we do that? Should we
use an animation player? Well, we could,
but there's a way easier way to do it. A
thing called twins. Now, twins are
perfect for simple movements like this.
They're lightweight and easy to control
through code. So, what we're going to do
here, we'll attach a script to our door.
Attach script.
No, we're not going to put our root
folder. We're going to put it in our
scripts folder. It can be called door.
That's fine.
and then create.
And I'll make this bigger. Then we can
delete our boiler plate code here. And
we need to have access to the hinge. I'm
going to make this smaller again. And
then take this hinge. I'm going to drag
and drop it with control held down. Now
I have my hinge. Make this bigger for
you. Now we need to check have a
inscript variable and ask if this door
is open. Well, it's not going to be. So
we'll set it to false first.
Now we need the function that we wrote
in our player script. So we know that
this is interactable. So our function
called interact because that's what
we're looking for from the player
script.
Enter down. And now we need access to
the tween. So, we'll store that tween in
a tween variable. And now we can use a
function called create tween. Now that
we have a tween that we've created,
well, we're going to check if that open
is true. So, if it is open, well, we
want to close it first of all. So, close
the door. So, we take the tween we got
and then we're going to change the tween
property
property. And the property we're going
to change is a property on the hinge. So
we're going to take that hinge and then
we're going to rotate it. So we want to
change the property of rotation.
So we look up rotation. We don't want
the whole rotation. We just want
rotation on the Y. We don't want to do
the X or the Z. We just want rotation on
the Y. So that way we can just swing the
door open and closed.
And then we want to say where we want to
go, which is the zero point zero. So we
don't want to be rotated at all. So go
back to its default position. And then
we want to say how long we want to take
to get there. But if it is not open,
well, we want to open it, right? So open
it. Open the door. And these are 90°. So
that helps. 90° angles. So how do we do
that? Well, we just get the tween that
we just made and the tween property.
Tween property.
And then we need the hinge again. And
we're going to rotate again along the Y
rotation Y.
And then we need to change the the
degrees of the door by 90. So how do we
do that? We take degrees to rad. Now if
you look into this, you can
control-click and look at the degrees to
rad. converts an angle expressed in
degrees to radians. Now, what are
radians? Radians are this default unit
of measurement for rotation in scripts
and code and like internal calculations
in game engines and other engines too.
Measurements for angular stuff. So,
without getting too far into it, anytime
you use rotation on a node or node 2D or
3D, you're using radians. So like 360°
is what they say two pi radians a full
circle. 180 degrees is a pi radian half
circle. 90 is pi / two. So it's a
quarter circle which is what we're using
the 90. So back in our door script here.
Now that we have our degree to radian
what we're going to use is the 90. So we
want to go 90 degrees. We just put in
90. Pretty straightforward. And then we
want to say how long to take to get
there to 0.5
just like we did up here.
And now we change the door. Well, we
need to set the is open to whatever it
is. So is open is equal to not is open.
So basically what that's going to do is
change it to whatever the opposite is.
So is open will become either open or
not open. Now for the items. Since our
player script just looks for the
interact function, we can make anything
interactable without changing any player
code. A generic cube isn't scary though,
so let's make this look like a real VHS
tape. We'll use realistic dimensions and
add a simple label trick, so we don't
need any external 3D software. All
right. First of all, let's save our door
script and our door scene in our scenes
folder. Save. All right. Like that. Go
down. We need a new scene. We new scene.
Scene. New scene. It's going to be a
other node scene. The scene we're going
to use is a static body
3D. Right there.
We'll go back to our 3D section so we
see what it looks like. Then we use a
right click add child node of it's going
to be a mesh instance 3D. So right here
and rename this to body.
I'll rename this static body 3D to tape.
That's what we're making. And our body
here, we're going to change the mesh to
a box mesh here. In the resource section
size, well the size I looked up for tape
is going to be 0.19,
03, and 0.1.
There we go. We zoom in. Now we got a
shape of a tape.
Now we scroll down to surface material
override.
We're going to click into the empty
section. Create a new standard material
3D. And then we're going to click on
this resource here. And then we're going
to change the albido. We're going to
change it to a dark gray. Now you click
on the color and the hex symbol here for
dark gray. 1 A 1 A
1 A.
There we go. And then we want to make it
not shiny, too shiny. So we'll change
the roughness a little bit to to point8.
Just like that. An old plastic look. And
we need a label of sorts. So right click
on the body and add child node. Another
mesh instance 3D. We're going to rename
this to label.
All right. Now, this is going to be
another box mesh here. Box mesh. And
then click on the resource area and then
change the size of this so it's slightly
wider and shorter but taller so it'll
poke out of the top of the tape. So for
this dimensions.14
for the X, then 031
for the Y, and then 06.
There we go.
Oh, you know, that's a little too big.
Let's make that a little more
rectangular. So, we're zero. Divide this
in half. 0.07.
And then the Y, let's go to 0.02.
Oh, we need to bring that up a little
bit. So, 0.04.
Let's pull this up a little bit. There
we go. So, on the Z, we'll do 0.04.
There we go. Now, we're Oh, slow down.
If you hold right click and use the
mouse wheel, you can change your zoom in
speed. There we go. Now we're slightly
poking through just like that. Just on
the front. Perfect. But all black on the
back. Now we have the label.
If you get real creative, we can do the
reels on the side, but we'll keep this
simple for now. You can even import a
actual 3D tape, but we'll we're going to
do this way for now. The last thing we
need is a collision shape so we have
something to interact with. So on the
tape, right click, add child node,
collision shape 3D. And this is going to
be a box mesh in the shape. And we
change the box shape 3D to the same size
as the tape, which if you remember was
0.19 03 01. So collision a shape we can
do 019.19
03 and then 0.1 there we go now size of
this tape go and save that or save this
scene as tape
and now we need the interact function so
all we need to do for that is click on
the tape attach new script not our
scenes folder and put it in our
scripts folder tape GD is fine
create. Let's get rid of this
boilerplate code. Make this bigger for
you. And then we just need that interact
function. So function interact.
For now, we're just going to make it say
something in the console because you
don't have an inventory system.
Say picked up tape. That's something to
do later in a polish section or
something you do on your own. Or if
you're interested, you can let me know
and we can expand on this tutorial
later. And then you can also just play a
sound here. Play a sound here later.
Just like we do with flashlight if you
want to play a sound when you turn it on
and off. And for now, we're just going
to delete it. And after we say the print
statement, say, "Hey, we did the thing.
Delete the tape.
Now, let's put it in the maze." So, I'm
going to make that smaller. Go back to
my world scene 3D. All right. Take my
level down. Then I'm going to take my
scenes. I'm gonna grab my tape.
Put in my world scene. Find my tape.
Where'd it go?
There it is.
Speed this up. I'll just put my tape
over here.
Just put over here in the corner or
something.
There we go. Save the scene and run the
current scene.
All right. I'm g walk over to my tape.
I should be able to click on it and it
disappears. If I look at my console
here, I picked up the tape. Perfect.
Also test the door. If you remember the
room I put over here, if I go to the
level again, our grid map walls, I do
select this door. Then I'm going to use
the paint here.
I'm gonna take this spot here. I got
rotate with S. Wait. Oh, yeah. There it
is. Rotate with S. Put it there. Oh,
deleted that door there. So, I have one
wall per
section. That's fine. We'll leave that
for now. But I also need my door. So, to
get the door scene,
I'm going put that in my world here. I
find my door
here.
I'm going to turn on this snapping here
so that way it snaps along the grid
line. Also going to rotate it
hole
here.
Pull it up so it matches.
I'll turn off the grid snap there.
Put this back.
Center that in the hole there.
There.
I think there's a way to get the grid
snap to work better. Oh, there we go. I
think that works.
Is that blocking?
I'll turn off the grid snap.
I think that's blocking. Perfect.
There we go. If I click out of there.
I think that's blocking the doorway just
fine.
I'll put my player into this room. Now I
go get my player past all these lights
here. Player.
Let's bring my player over here.
I'll turn the player to be looking at
the door when the game starts.
There we go. Now we start in this room.
Going to save. Let's try this scene out.
Run current scene.
Now we're in this room.
Go up to the door. Click on the door
and nothing happens. Well, that's not
supposed to happen. Let's escape out of
there. Let's go back to our door scene
and
oh,
take this script off of the door here.
This is not going to detect collisions.
The static body 3D is going to detect
collisions. Well, that was silly. So, we
can rightclick, detach script, static
body 3D, come back down in our file
system, scroll down to our scripts,
find the door script. I'll drag the door
script onto the static body 3D.
And since we changed the hierarchy of
the script, we need to go back into our
script and scroll back up to this hinge
node. Instead of money symbol hinge, we
need to do get parent. Now since our
hinge is the parent of our static body.
Now we can get parent which is our
hinge. I go and save that. Go back to
our world scene.
Go to 3D. Give it another test.
All right. Now when you walk up to it
should open right up. Perfect.
We go to where our tape was, which I
think is over here.
Get lost in our own maze.
And yep, there it is. The corner. Grab
that. We are good.
It works. We have a universal
interaction system. You can use this for
light switches, notes, hiding spots,
anything. Now, we have movement,
atmosphere, and interaction. We're
technically playing a game. And if
you're following along, take a
screenshot of your maze and tag me on
Blue Sky. I want to see your level
layouts. But we are alone. Or are we? In
the next video, we're going to add the
monster. We'll program a simple AI that
stalks you through the grid map. Now, if
you found this helpful at all or fun,
leave a comment on 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 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'm 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 building a universal interaction system for a first-person game in GDAU. It covers implementing a Raycast from the player's camera to detect objects and adding an "aim dot" reticule to the UI. The tutorial explains how to set up an "interact" action in the input map and write a flexible `interact` function using "duck typing," allowing various objects like doors and items to respond to player input without specific type checks. It details the process of baking custom doorframe tiles using CSG subtraction, building a functional door with a hinge, and animating its movement with GDAU's tweening engine, also clarifying the use of radians for rotation. Finally, it shows how to make a simple VHS tape item interactable, demonstrating the system's versatility before teasing the next video on adding a monster AI.
Videos recently processed by our community