HomeVideos

Godot 4.5 Tutorial: Nextbot AI & Enemy Pathfinding (Backrooms Part 5)

Now Playing

Godot 4.5 Tutorial: Nextbot AI & Enemy Pathfinding (Backrooms Part 5)

Transcript

865 segments

0:01

We built the maze. We built the

0:02

atmosphere. But a horror game is not a

0:04

horror game unless something is hunting

0:07

you. Welcome to the finale. You made it.

0:09

Today, we turn this walking simulator

0:11

into a survival horror. We're going to

0:14

build a nextbot style AI, which is an

0:16

enemy that knows exactly where you are

0:18

and just never stops coming. A nextbot

0:20

is popular term from the Garry's Mod

0:23

community that refers a specific type of

0:25

AI enemy. It originated as a system for

0:28

more complex NPC navigation but became a

0:32

massive meme mind men mind men mind men

0:32

mind men mind men mind men mind men mind

0:32

men mind men mind mena horror trope

0:34

first the enemy needs to know where it

0:36

can walk in GDAU we use a navigation

0:38

region to bake a map for the AI now back

0:41

in our project here in our world scene

0:44

we're going to level here which is the

0:47

parent of all our grid maps we're going

0:49

to right click on it and we're going to

0:51

change its type and we're going to

0:53

change its type to a navigation

0:56

region

0:58

3D.

1:00

Go ahead and change.

1:02

Now, it's important to note when we did

1:04

change that, go back to the change type.

1:07

You'll notice it is experimental. So,

1:09

this class may be changed or removed in

1:11

future versions. So, if you're watching

1:13

this in the future, this may be

1:15

different, but all we're really doing is

1:17

trying to get a nav mesh onto these grid

1:20

maps. So, how are they're doing that in

1:23

the future? That's what we're going to

1:24

do.

1:25

and change or cancel that. We already

1:27

changed it, so you can hover over it and

1:30

see what type it is. And then with our

1:32

level selected, our navigation mesh,

1:34

we're going to click on that, create a

1:36

new navigation mesh and go into the

1:39

resource there. And then we're going to

1:42

go into cells. And to get the cell size

1:46

or cell height, we want the cell height

1:47

to be as close to the floor as possible.

1:50

Since you're using a grid map, we don't

1:52

really have any width on our floor. So,

1:54

we want it really close to the floor,

1:56

which is going to be 0.05.

2:01

So, hug the floor. So, our enemy's feet

2:03

will look like they're touching the

2:05

ground. And then when we have that,

2:07

we're going to go up here in the

2:08

toolbar, click bake, navigation mesh.

2:13

Then, we see our floor as the navigation

2:17

mesh. You also see that our door blocks

2:22

the mesh itself as well. So, we click on

2:25

our door and we're going to temporarily

2:27

hide it for now. If you want your

2:30

enemies to be go through the doors,

2:31

which we do,

2:34

once our door is hidden, before we click

2:35

bake again, we're going to change the

2:37

size of our enemy so they can fit

2:41

through this door. And our enemies are

2:43

going to be the agents. So, with our

2:45

level map selected, agents, we're going

2:48

to change our radius of our enemies to

2:52

0.25.

2:54

That way, they can fit through the doors

2:58

after we click bake. So, click bake

3:00

again.

3:02

And now we have a line of nav mesh to

3:05

the door. Now, our enemies can follow us

3:08

through the doorways. Then we can bring

3:10

our door back right there. and the nav

3:12

mesh will stay just fine. Then save that

3:16

scene. Now, if that didn't work for you,

3:19

maybe try reducing your radius of your

3:21

agent a little further and see if that

3:24

helps. We also want to check how close

3:26

it is to our floor, which is good. It's

3:28

hovering a little bit, so you could

3:30

bring this down a little further, but

3:32

you don't want to get too close. You

3:34

might get some layering issues. That's

3:38

good for now.

3:40

Now, I'm sure you've noticed these

3:41

warnings here. Now, this is just saying

3:43

that

3:45

these settings in our project settings

3:48

do not match our settings that we've

3:50

customized over here. Now, to change

3:53

these throughout the project, instead of

3:55

just dealing with the warnings, we can

3:57

go into our project project settings and

4:00

our filter settings, we can search for

4:02

something called default

4:04

cell height.

4:07

Just like that. and it should be in the

4:08

navigation section 3D. Now, see our

4:12

default cell height is 0.25, but we

4:14

changed ours to 0.05.

4:17

So, we changed that to 0.05.

4:20

So, we're using grid maps and that's

4:22

where we want it to stay by default. So,

4:24

we can enter that and close.

4:28

Then we can clear these.

4:30

Let me try baking again. See if it fixes

4:32

it. It doesn't which means we need to

4:36

project reload current project. So that

4:40

setting takes effect. So once it loads

4:43

again after we bake after we click level

4:46

then bake navigation mesh you'll see

4:49

that error goes away.

4:52

The warning disappears because the map

4:55

now

4:56

agrees with with the mesh basically. So

5:00

that's all it was just a little

5:01

conflict. Now we need the monster. Now

5:04

we're going to keep it super simple.

5:06

Just a floating capsule of Doom. Now

5:09

we're say new scene.

5:12

New scene. It's going to be a other node

5:15

scene. Be character body 3D

5:19

right here. Create. And then we're going

5:23

to rename this to enemy.

5:26

Great. Now, we want to add a mesh

5:29

instance 3D

5:31

so we can see our enemy.

5:34

And one we're going to use in the mesh

5:36

is the capsule mesh there. Now, we'll

5:40

set the end into the resource here.

5:41

We'll set the radius to 0.25,

5:46

which is the same as our agent radius we

5:48

set in our nav mesh. So, now our nav

5:50

mesh and our enemy agree on the size it

5:53

is. Now, for the material, we can use

5:57

uh we could just use that tape material

5:59

we did last time.

6:01

Or we could give it a weird look, make

6:06

it look like the wallpaper.

6:09

Yeah,

6:11

a stretched out wallpaper. We can give

6:14

it kind of a weird glow. You really do

6:16

whatever you want with this kind of

6:18

stuff. Whatever feels creepy to you. Or

6:20

emission. Can make it like a red

6:22

emission.

6:24

Maybe a little darker though.

6:27

That gives a little pink look.

6:30

There you go. So, it kind of looks like

6:32

the wallpaper is chasing you. Spooky.

6:37

Great. Just something silly like that.

6:39

Whatever you want to do. And let's see

6:42

here. In the transform, we need to bring

6:44

it up by one. There we go. That way, our

6:48

enem is sitting on the floor. Then, as

6:50

you see from our node configuration

6:52

warning, we still need a collision

6:53

shape. Right click on the enemy,

6:56

collision shape 3D.

6:59

And we're also going to have it be the

7:00

shape of a capsule. Just like that. And

7:04

into our resource here, we change the

7:06

radius to match our capsule. We also

7:09

need to change the transform to match

7:12

the capsule itself. So, it hugs the

7:14

capsule as it is.

7:18

So, we need the brain of our enemy. So,

7:20

right click on the enemy, add child

7:22

bone. This going to be the navigation

7:25

agent redee.

7:28

This going to tell the enemy where it's

7:31

allowed to walk.

7:33

And that's all we need for that. So, you

7:35

can control S to save. We're going to

7:37

save our enemy in our scenes folder.

7:40

Save. So, the logic is going to be

7:42

simple. We're just going to find the

7:43

player when in range, get the next step

7:46

on the path, and move there. We're also

7:49

going to add a spooky glitch effect. So

7:51

when the enem is chasing us, it's kind

7:54

of glitching back to where it was at

7:55

some point on its path. So on our enemy

7:58

here, we're going to right click on our

7:59

enemy node. We're going to add a child

8:01

node. Audio stream player

8:05

3D right here. Now, this one's going to

8:08

make a sound when we're close to the

8:10

enemy. Not like the hum we did with the

8:12

lights. This one will do it everywhere,

8:15

but this one will do it when we're close

8:16

to the enemy with the 3D one. So, we

8:18

want that one. The sound I'm going to

8:21

use is going to be included in the back

8:23

rooms tutorial assets that I've linked

8:25

below in the description just like all

8:27

the other ones. But if you're

8:28

downloading them separately because

8:30

that's how you want to do things, that's

8:32

fine. I'll also include that link. And

8:34

it's from free sound. You'll see it's a

8:37

creative common. And you want to make

8:38

sure anything you use, especially sound

8:41

related or anything really, you want to

8:43

have a CCO license. That way you have

8:46

the right to use it unless you want to

8:48

pay for the rights. So we're just going

8:49

to use this static sound every time it

8:52

jumps. Just like that. So add a

8:55

atmospheric spooky effect every time it

8:58

glitches. So however you decided to

9:01

download that, I'm going to go back up

9:02

into my audio file here. Now I'm going

9:05

to drag in that sound and drop it in

9:09

there and import it. So now I have my

9:11

static burst sound. So, in my audio

9:14

stream player 3D, I am going to drag and

9:18

drop right into the stream here. Now, we

9:20

don't want to be able to hear this from

9:22

anywhere. If we keep the max distance at

9:25

zero, we'll be able to hear the enemy

9:27

moving from across the across the whole

9:29

level. We don't want to do that. So,

9:31

we'll change this max distance. We're

9:32

just going to use 10 meters. So, the

9:35

enemy gets real close. That sound's

9:36

going to get louder and louder. And if

9:40

the enemy decides to move once or twice

9:42

at the same time and the sound is still

9:44

playing, we don't want the sound to cut

9:46

off right away. So, we're gonna up this

9:48

max polifany, which as it says just lets

9:52

it nodes play at the same time playing

9:55

additional sounds. So, we're just going

9:57

to increase that to four. Be super safe.

10:00

And that's all we got to do for that.

10:02

Let's go and save that scene. And our

10:04

enemy here, we're going to add a script.

10:07

attach script. We don't want to save it

10:10

in our scenes folder though. We're going

10:11

to save it in our scripts folder enemy

10:14

GD or keep the default and create.

10:19

All right, I'll make this bigger for

10:20

you. I'm going to get rid of my output

10:23

and we're not going to keep any of this

10:25

stuff. So, let's get rid of the

10:28

boiler plate code. Now, we are going to

10:31

use a speed. So, our constant speed for

10:34

enemy, we're going to use it as four.

10:38

Good enough for now. And then we want a

10:41

distance to where the enemy can get us.

10:44

This is where you can add like a jump

10:45

scare, that kind of thing. We'll call it

10:47

jump scare distance. And we'll just make

10:49

it 1.5. So, when the enemy is 1.5 meters

10:52

away from us, it's going to game over

10:54

us. Then, we want a distance. And when

10:57

our enemy starts chasing us, we call it

10:59

the aggro distance.

11:01

So that could be anything you want.

11:03

We're going to set it to 20. So as 20

11:06

meters away, the enemy is going to start

11:08

chasing us. And then for the glitching,

11:12

this is going to be the glitch settings.

11:15

Now I'm going to use the

11:18

interval between the two. So export

11:21

bar minimum glitch interval.

11:25

Give it a kind of teleporting around

11:28

creepy look. Our float is going to equal

11:31

to 0.5 and that what is that just

11:33

minimum

11:35

I could type right minimum

11:38

seconds between the glitches

11:43

and then we need a match a match a max

11:46

max glitch interval

11:49

so that way it's not consistent it's

11:51

random and unpredictable and that's

11:54

going to be 1.5. So between 0.5 and 1.5,

11:58

that's how we're going to handle our

11:59

glitching back and forth,

12:02

maximum seconds between glitches.

12:06

There we go. There's that. So we need

12:09

some uh internal variables here. So we

12:12

need a timer to say when we can glitch

12:15

the glitch timer. We'll make that a

12:17

float and zero seconds to start. Then we

12:21

need a next glitch interval

12:25

interval there

12:28

float one. And that's the interval

12:32

between glitches that we're going to use

12:34

to say when you can glitch. And then we

12:38

need a safe position. We don't want our

12:39

enemy glitching into the wall or outside

12:42

it even because then it won't be able to

12:44

get back in. So, we need a safe

12:46

position, which is going to be a point

12:49

on the path that the enemy has already

12:50

walked. So, we know that's a safe

12:52

position to be in. Great. To get all

12:56

this stuff, we need to get access to our

12:59

enemy's hierarchy. So, I'm going to make

13:01

that smaller. What I'm going to bring in

13:03

here, I need the navigation agent 3D.

13:06

I'm going to drag controll drop that in

13:09

there so I know my path is correct. And

13:13

this is large. So I'm going to rename it

13:16

to nav agent.

13:18

There we go. What we also want is our

13:22

audio stream player 3D. So we can play

13:25

that sound when we glitch around. Drag

13:28

control and drop. And we have our audio

13:31

stream player 3D.

13:34

And make this a little smaller too. Just

13:36

call it audio player.

13:39

And save that. We also need to access

13:42

the mesh of our enemy so we can change

13:45

its transform and position when we do

13:47

glitch. So the mesh instance 3D control

13:52

drop control. There we go. All right.

13:55

Now we have all our variables. We're

13:58

going to make a ready function. So

13:59

function ready. And then we're going to

14:02

go into that. The first thing we need to

14:03

do is save the spawn point as the first

14:06

safe spot. So, if we glitch right away

14:09

and we haven't gone too far, we need to

14:11

be able to uh teleport back to the first

14:14

spot we were to our safe position.

14:18

Initially, it's going to be the global

14:20

position of where our enemy is. That's

14:22

it. And we need to set the first random

14:25

timer,

14:27

which is going to be the next glitch

14:29

interval

14:33

right there. And we're going to set that

14:34

to a random range, a random float range.

14:37

So rand f range, which is going to be

14:41

the minimum glitch interval

14:44

and

14:46

between the max glitch interval. So we

14:49

have our min and our max. We don't want

14:50

it to go above or below that. I'll make

14:53

this bigger so you can see that. So

14:55

basically this next glitch interval,

14:57

random float range between our two min

15:00

and maxes. Perfect. And that's all we

15:02

need in our ready function. Now we're

15:05

going to use our physics process. So

15:08

this could be our movement and tracking

15:10

our players and those kind of things. So

15:13

physics process.

15:15

All right. Now in this physics process,

15:18

we want to ensure that the mesh is

15:20

visible because we're going to turn it

15:22

off and on again of the enemy. First,

15:24

ensure mesh is visible

15:28

if it wasn't toggled back.

15:31

toggled back. So if not visual

15:36

mesh,

15:39

not visual mesh, mesh instance 3D

15:42

because that's our enemy. That's going

15:44

to be vvisible.

15:47

There we go. Just want to make sure that

15:50

that boolean returns false because if it

15:53

is false, we need to turn it back on to

15:56

our mesh instance 3D.

16:00

And we want to take visible

16:05

and we want to make it to true. There we

16:07

go. And that'll make our mesh back on if

16:11

it's off. And now we need to track the

16:14

distance to the player.

16:18

Now you've reached a checkpoint. Now we

16:20

need the enemy script to look for the

16:22

player. So we're going to add the player

16:23

to a group. But we've never added our

16:26

player to a group yet. Now, if you've

16:29

never heard of groups in GDAU, groups in

16:31

GDAU work like tags in other editors.

16:35

So, you can add a node to as many groups

16:36

as you want and then you can use in

16:40

scene tree, get the list of nodes in a

16:42

group, call methods on that group, set a

16:45

notification to all nodes in a group.

16:48

Now, how do you add nodes to groups? On

16:51

the node in the inspector node section,

16:55

you're going to have our group section

16:57

here. Now, this is where we add here.

17:00

And now we can add it like our player to

17:03

a player group. So, back in our project

17:06

here, so we can get our enemy to see our

17:08

player. Well, we can go to our world or

17:10

we'll go to our player because that'll

17:12

affect our player in our world as well.

17:16

So, our player with our player selected,

17:19

we're going to go to this node section

17:20

just like we saw. Then, we're going to

17:22

go groups. And then when we add this

17:25

plus button here, we're going to give

17:27

our player the player group. The name is

17:32

going to be the player. You can get add

17:35

descriptions and stuff, but we're not

17:37

going to do that with this. It's pretty

17:38

self-explanatory. We're also going to

17:40

make it global. So way this can be

17:42

accessed from anywhere.

17:45

Okay. And now we have the player and the

17:47

player group. And you can tell it's in a

17:49

group. It's a little square box with a

17:50

circle. The node is in this group.

17:53

player.

17:55

Now, back in our enemy script here,

17:58

we're go I'll make this a little bigger

18:00

for you. I'm going go ahead and save

18:02

this.

18:03

So, our player is saved in the group or

18:06

the asterisk there. So, once that

18:08

asterisk is gone in our enemy script

18:11

here, we're going to go back up to our

18:13

onreddies and we're going to get access

18:14

to that player group. So, we're going to

18:17

add another ready here

18:20

bar. We're going to call it player. Now

18:22

we use something called the get tree

18:26

here. Now the tree get tree gets the

18:29

scene that we're currently in. So our

18:32

enemy is going to be in the world scene.

18:34

So it's going to get that scene and then

18:37

from this scene it's going to make this

18:39

smaller for you. It has access to all

18:42

these hierarchies now. So we need to

18:45

access the player node in the world

18:47

scene. And we get the world scene by

18:49

saying get tree open up. Now I want to

18:53

get the first instance, the first node,

18:58

first node in group right here. I get

19:01

that group. The group I want to get well

19:04

is the one we just made called player.

19:07

And now we have our player in our

19:10

variable here. So, back down in our

19:13

physics process here, what we can do is

19:16

right when we enter this, well, first of

19:18

all, we want to check if it's not the

19:21

player, well, we don't want to do

19:23

anything. So, let's return. So, if we

19:27

don't have a player in our onready, we

19:30

don't want our enemy to do anything or

19:32

else the code be right down here is

19:34

going to break. So, after this,

19:38

make sure we're actually visible as

19:40

well. We want to check the distance to

19:43

the player. So distance to player

19:48

is going to be the global position.

19:52

And then we're use a function called

19:54

distance to

19:57

a built-in function. So we track how far

19:59

away our player is. But we need our

20:01

player's global position because the

20:05

player is going to be moving around

20:06

constantly. So we need to update this

20:10

physics process and the distance to

20:12

player every frame. All right. Now that

20:14

we have the player position and the

20:17

distance to it, we need to go down and

20:20

we need to check if the distance to

20:22

player is close enough to attack. So

20:26

it's less than our aggro distance.

20:29

Right? So then we go into that if

20:31

statement and then we want to have the

20:34

what's going to be the chase logic.

20:36

Okay. So, anything you want to have

20:38

happen when the chase begins, this is

20:42

where you would put that.

20:44

So, in this we want to first thing we

20:46

want to do is move towards the player.

20:49

Move towards player.

20:52

And we do that by getting the navigation

20:54

agent

20:56

which we have on our ready. And then we

20:58

want to set the target position

21:01

in that

21:03

or on that agent.

21:05

And the target position well is going to

21:07

be the player. So we have the player's

21:09

global position.

21:12

There we go.

21:14

And then we want to save our next

21:16

location.

21:19

Have our nav agent.

21:22

Nav agent

21:24

get next path position.

21:29

Now we have a nav agent and our nav

21:32

agent has a path control and that's

21:36

going to handle all of our pathing for

21:37

us. So they have path positions. If you

21:40

hold control and click on this, you can

21:43

dive deeper into this. But returns the

21:45

next position of where this enemy is

21:48

going to be allowed to move to. So all

21:50

that blue baking nav mesh we got before,

21:54

that's what this is calling. So it can

21:56

actually know it can get there.

21:59

But back at our enemy GD script, after

22:02

we have that next location, we want to

22:05

save our current location for our

22:08

glitching effect. Go back and forth. Our

22:10

current location, well, it's going to be

22:12

our global position at this time. And

22:16

then we need our how far or how fast we

22:19

want to go. So, our velocity, a new

22:22

velocity, we're going to use that. And

22:25

then it's going to track where we are

22:28

and where we want to be. So we need to

22:30

minus that. So our next location

22:34

and then our current location,

22:37

not comma, minus our current location.

22:41

So notice how far we need to be and how

22:44

fast we need to get there. We want to

22:46

normalize it. Normalized. What is

22:48

normalized? If we controlclick into

22:50

that,

22:52

normalizing is a consistent function. So

22:55

it it returns movement so it's always

22:58

consistent. Like if you don't moving

22:59

diagonal, those kind of things, you

23:01

don't want those different than if

23:02

you're moving horizontally or

23:04

vertically. You want everything to be

23:05

and look the same. Now, it's pretty

23:07

crucial for converting raw vectors into

23:12

movement or also look stitchy and faster

23:15

than you want it to or just not as good

23:18

as you need it to. Great. Now that our

23:20

movement is consistent

23:22

back at our enemy GDScript

23:25

after we normalize our movement so it's

23:28

all the same no matter which direction

23:29

we're going. We want to know how fast we

23:32

want to get there. So we're going to

23:34

multiply that by well the speed that we

23:36

want our enemy to go.

23:38

Go and save that. And last but

23:40

definitely not least, well we need to

23:42

say well move. So, our velocity that our

23:45

current enemy is going needs to equal

23:48

our new velocity.

23:51

Looks like my tabs are messed up.

23:53

Backspace to the wall. Tab forward

23:55

twice. These tab indentations are

23:59

finicky. You want to make sure they're

24:01

perfect.

24:02

And now after we know how fast and where

24:04

we're going, well, we need to have our

24:07

glitch timer

24:09

so we can have our glitching go back and

24:11

forth at random intervals. So our glitch

24:14

timer is going to equal the delta. So

24:17

it's going to count by proper seconds

24:21

and not dependent upon your frame rate.

24:24

So if the glitch timer

24:27

is greater than or equal to the next

24:30

glitch interval, so that random interval

24:33

that we set up earlier, well, we're

24:35

going to write a function called perform

24:38

glitch. We'll write this function in a

24:41

second. Enter down.

24:44

And after we've performed our glitch, we

24:46

want to reset the timer.

24:49

So our glitch timer back to zero.

24:52

And then we want to set a new random

24:54

time.

24:55

New random time.

24:58

And we're going to do that by saying the

25:00

next glitch interval

25:03

interval. There it is. And we want to

25:05

set it to another random F range. Random

25:10

float range. And we want to set that

25:12

between our just like we did before

25:14

minimum and maximum glitch intervals.

25:18

Great.

25:20

Then save that and enter down backspace

25:24

couple times. We're going to get into

25:25

our else

25:27

now in our if statement. And our else,

25:30

well, if we're not chasing, well, we

25:32

want to idle. So, I'm going to make sure

25:34

the velocity

25:36

is zero.

25:39

Vector 3

25:41

zero. Now, this will make our enemy stop

25:44

moving at all. So, save that. And after

25:48

that if statement, regardless of what's

25:50

happening, you want to use the GDAU's

25:52

move and slide.

25:55

You don't use move and slide. None of

25:56

this will happen at all. And the last

25:59

thing we want to check after our move

26:00

and slide in this physics process is if

26:03

we are close enough to the player, well,

26:06

we want to jump scare them or kill them,

26:08

however you want to handle that. We're

26:10

do something called the jump scare. So

26:12

you can add a jump scare later on, but

26:15

what ours is going to do is just reset

26:18

the player back to the beginning. So the

26:20

distance to player is less than the jump

26:22

scare distance that we set above. Well,

26:25

we're going to call another function

26:26

that we're going to write in a second

26:27

called jump scare. There we go. We're

26:31

going to save that. Now we have a couple

26:33

functions we need to write. The first

26:35

one we're going to write is the

26:38

perform glitch. So function

26:43

perform. Now I type perform glitch.

26:48

There we go. All right. Now, the first

26:51

thing we want to handle in the perform

26:53

glitch is the visual. So, the visual

26:55

flicker.

26:57

And then we need to get our mesh

26:59

instance 3D. And we're going to make

27:02

that false. This is where we're going to

27:04

hide that mesh. That's why we're going

27:06

to make it unhidden in the physics one

27:09

just in case it didn't get unhidden. Now

27:12

after we hide the mesh, well, we're

27:15

going to teleport. So the rubber band.

27:18

So we're going to rubber band teleport.

27:21

So we know it's a spot it was safe

27:24

because we saved it because it's a place

27:25

the enemy has already been. So first

27:29

we're going to do is save the current

27:31

spot,

27:33

current valid spot.

27:35

as the next

27:39

safe spot.

27:41

There we go. Says current spot. Well, we

27:44

just you get a variable. Our current

27:46

spot is pretty simple to get our global

27:50

position.

27:52

That's where we are. So, now that we

27:54

have another safe spot, well, now we can

27:57

teleport

27:58

back to the old

28:02

safe spot.

28:04

And we just need to change our global

28:06

position we're at now. And we're gonna

28:09

change it back to the safe position that

28:12

we set.

28:15

No, no, it's a dis dist player. Not we

28:19

don't want to disc the player. We want

28:21

to be nice to him. We just want the

28:22

distance to player. Okay, perfect. Our

28:25

current spot global position and

28:27

teleporting to the safe position. And

28:30

then we update the safe position. Update

28:35

the safe spot for next time.

28:40

All right. Now we got safe position is

28:43

now our current spot.

28:46

And now that we have all our

28:47

positioning, well, we're going to set

28:49

the audio now. So it's going to be the

28:52

audio static. How we do that? Well,

28:55

we're going to change this the pitch.

28:57

It's a pretty common thing for in game

29:00

development to have the same sound.

29:02

Instead of having multiple sounds, we

29:04

just change the pitch of the sound so it

29:06

sounds different every time, at least a

29:08

little bit. So, we use a random pitch

29:11

and a new variable. And we're going to

29:13

get the random float range and we're

29:16

going to set the pitch between 0.8,

29:19

so lower, and 1.2 higher.

29:24

So, not too much difference, but enough

29:26

to be noticeable

29:28

to the ears. Then we get the audio

29:32

player that we set and we're going to

29:34

change the pitch scale is what we're

29:36

looking for. So, if we go back to our

29:39

let's make this smaller and our enemy

29:42

here. If we go to our audio stream

29:45

player here, change the inspector back

29:48

on. What we're accessing here in the

29:50

inspector is the pitch scale. Now, if

29:53

you hover over it, it'll say the pitch

29:55

and tempo of the audio as a multiplier

29:58

of the audio's sample rate. So, the

30:00

lower

30:02

slower it's going to play. The more deep

30:03

it's going to sound. The higher faster,

30:06

the higher it's going to sound. So, we

30:08

don't want it too far up and down. You

30:09

want to sound like a chipmunk. You don't

30:10

want to sound like

30:12

just slowmo demon or something. So,

30:16

unless you want that. So, up to you, but

30:18

we're going to keep it pretty subtle,

30:20

but enough to not be annoying. So, make

30:23

this bigger again. Now, we have our

30:26

pitch scale. We're going to change that

30:28

to the random pitch.

30:31

Random pitch. Perfect.

30:34

We also need Well, we need to play it.

30:36

We don't play it. Well, it won't

30:38

actually play. So, we need to play.

30:42

There it is. That's all that is. And

30:45

save that. The last function we need to

30:48

write after this one. Enter down a

30:50

couple times. function jump scare.

30:54

That's going to handle all the resetting

30:56

of our player. You could also do a game

30:58

over screen here, but we're not going to

31:00

do that in this tutorial. We're just

31:02

going to do print

31:04

you died. There you go. And then we need

31:08

to set the physics process.

31:12

That we're going to set that to false.

31:16

What does that do? Now, this is simply

31:19

saying stop physics processing. So, we

31:22

want our enemy to stop. So, if true, it

31:24

enables, it's always true by default,

31:26

but we can set it to false and stop our

31:30

enemy from running into us after we're

31:32

already gone. All right. Now, back in

31:34

our enemy GD script, what we can do

31:36

after that, we need to set if the player

31:40

if player

31:42

to make sure we have the player, we also

31:44

want to stop our player. So the player

31:47

set physics process,

31:49

we're also set that to false. So now our

31:51

player can't move and our enemy stops as

31:53

well. We also want to uh change the

31:57

mouse. So if we are dead, we want to be

32:00

able to reset or if we have a menu pop

32:02

up, we want our mouse to come back. We

32:04

don't want our mouse to stay hidden.

32:06

So, our mouse mode like we did earlier

32:09

input or a couple tutorials ago, mouse

32:13

mode

32:14

visible

32:16

right there. So, it just pops up our

32:18

mouse again. And then after that, well,

32:20

all we're going to do here, this is

32:22

where you do the game over screen, but

32:24

we're going to wait for a couple seconds

32:26

after we get hit by the enemy. We're

32:27

going to get the whole scene tree that

32:29

we're in, which would be the world here.

32:32

So after we have the whole world scene,

32:34

oops, we're going to reset the whole

32:36

level. Let me just do that not right

32:40

right away. Create a little timer. So

32:43

after 1 second. So after 1 second, what

32:46

we're going to do, we're going to call

32:47

the timeout function on the timer that

32:49

we just created. And it's going to say,

32:52

hey, I'm done. So now get the tree. And

32:56

then we're going to reload the current

32:58

scene. This going to reload back to

33:00

where our starting point is. Easy way to

33:03

set, you know, checkpoints, too, if you

33:05

want to set checkpoints.

33:07

Perfect. Now, let's save that scene.

33:09

We're going to make this smaller.

33:13

Now, the big moment. Let's go back to

33:15

our world scene, back to our 3D tab, and

33:19

we're going to grab our enemy from our

33:21

scenes folder here.

33:24

right there and then drag and drop into

33:27

our world scene here. Now, you can set

33:30

the enemy wherever you like. I'm going

33:33

to go ahead and set the enemy over here,

33:36

right past this tape section here,

33:42

right there. So, when the player

33:45

theoretically gets right here into these

33:48

two quarters or around this enemy is

33:51

going to see. Now, our pathing isn't

33:53

going to be perfect. It's just going to

33:54

move towards the player. There's more

33:57

advanced pathing materials you can do to

33:59

have them further away from walls and

34:01

those kind of things, but this should

34:02

work for now. Let's go and save that.

34:05

Now, let's run our scene.

34:09

Oh. Oh, that's silly. Let's stop that

34:12

for now. My spelling has destroyed me

34:16

again.

34:17

Let's check. Let's change our visible

34:21

spellch checking is better. Spelled it

34:24

right in the comment but not where it

34:25

actually matters. So actually here I'm

34:28

going to hold control F. I'm going to

34:30

search for visible.

34:33

I'll also search for visibil how I

34:35

spelled it last time. It's not visible.

34:38

It's visible. Perfect. All right. Let's

34:41

exit that. Let's go back to the Make

34:44

sure that's saved. back to our world

34:46

scene once again. Let's give this a try.

34:50

It's always something. All right, we are

34:52

in our room here. Me go and turn off my

34:56

mouse pointer.

34:58

That's distracting.

35:00

There we go. Now we are in here. Let's

35:04

go into our door.

35:07

Let's make our way to our tape.

35:12

See if our enemy starts chasing us. Oh,

35:15

I can hear it.

35:17

Oh. Oh. Oh. Oh.

35:21

That's pretty spooky.

35:26

Oh jeez.

35:28

Ah.

35:30

And it got me. Now we reset.

35:34

Look at that.

35:37

Now I like how it goes through the walls

35:38

like that. That makes it super

35:40

unpredictable. Obviously, we are

35:42

probably going to be

35:44

really hard to get away from this thing.

35:47

So, this is where the polish would come

35:49

in where you'd edit out the enemies and

35:53

then

35:54

make it so it's more survivable. Maybe a

35:57

way to get away from the enemy. The goal

36:01

right now is obviously to go pick up the

36:03

tape, but I keep getting caught. But

36:06

there you go.

36:09

In five videos, we went from empty void

36:11

to kind of terrifying. That was a scary

36:14

enemy in the end there. Atmospheric

36:17

horror game. Now, we covered FPS

36:19

movement, modular level design,

36:22

post-processing, shaders, raycast

36:24

interactions, and AI pathfinding. Now,

36:28

this project is finished. It's not

36:31

perfect. The monster is a pill. The maze

36:33

is simple, but you made it, and that's

36:36

what really matters. Now, this is where

36:38

you go off and make larger levels,

36:41

scarier enemies, mid or better AI,

36:45

and an inventory system to make picking

36:47

up the tapes matter. Now, if you found

36:49

this helpful at all or fun, leave a

36:52

comment on what your GDO game dev goals

36:54

are. Please like, subscribe, and hit

36:56

that notification bell. It really helps

36:58

out the channel. And thank you to all

36:59

our current and past Patreon and coffee

37:01

members. Your generous support keeps the

37:04

channel moving. Now, if you want early

37:06

access to tutorials, source code, or

37:08

suggesting future tutorials, please

37:10

consider becoming a member yourself. The

37:12

links are in the description. I'm

37:14

Spaghetti Syntax, and remember, always

37:17

stay curious, and I'll see you at the

37:20

next checkpoint.

Interactive Summary

This video, the finale of a GDAU horror game tutorial series, demonstrates how to transform a walking simulator into a survival horror by implementing a Nextbot-style AI enemy. The process involves setting up a navigation mesh for AI pathfinding, creating the enemy character with a mesh and collision shape, and scripting its behavior to chase the player, perform a "glitching" teleportation effect with synchronized static audio, and trigger a jump scare or game over mechanic. The video concludes with a live demonstration of the enemy in action and a recap of the series' covered features, encouraging further development and polish.

Suggested questions

8 ready-made prompts