HomeVideos

Godot 4.5 Beginner Tutorial: Auto-Aim Turrets & Nearest Enemy Logic (Part 3)

Now Playing

Godot 4.5 Beginner Tutorial: Auto-Aim Turrets & Nearest Enemy Logic (Part 3)

Transcript

566 segments

0:01

Now we have a horde of monsters chasing

0:03

us and our only defense well is running

0:05

away. It's time to fight back. Today we

0:08

build the auto aiming system.

0:10

Welcome back. In the last video we

0:12

created the horde. Today we create the

0:15

cure. We are going to build a weapon

0:16

that scans the environment. Does some

0:18

quick math to find the closest threat.

0:20

It automatically takes the shot.

0:24

First we need something to shoot. So,

0:26

we're going to use an area 2D because we

0:28

don't need it to bounce off the walls.

0:29

We just need to detect when it touches

0:31

the enemy. So, back in our game here,

0:33

what we're going to do is new scene

0:35

scene. New scene.

0:38

Go back to our 2D so we see what we're

0:40

looking at. And we need an other node.

0:42

We're going to use the area 2D

0:45

there. And rename this to projectile.

0:50

There we go. And right click there, add

0:53

a child node, sprite 2D.

0:56

Now, for this one, I just use a texture.

0:59

So, I click on the texture node here.

1:00

I'm just going to use a gradient texture

1:02

2D and just make a little ball here. And

1:04

how we do that, we can click in this

1:06

texture node here. And then in the fill

1:09

here, the fill section, linear, we want

1:13

radial. Perfect. Or make it a little

1:16

smaller here. We'll do

1:19

uh we'll do 8 by 8. Perfect. Then what

1:23

we're going to do here is the from

1:26

section the X 0.5,

1:29

the Y 0.5,

1:32

and the two 0.5.

1:35

There we go. And then in our gradient

1:38

section here, we want to click

1:40

interpolation,

1:42

then mode. Instead of linear, we want

1:45

constant.

1:47

There we go. Now, we have this little

1:49

pixel kind of ball thing here, but it's

1:52

not transparent on the edges. So, how do

1:54

we do that? Well, we're going to click

1:55

in this little bar here, and then click

1:58

in this little square here. We're going

2:00

to make this white to start.

2:04

So, if you want to add some color tint

2:06

to it later, it's easier. So, now that's

2:08

white. And click out of there. And then

2:10

to make the edges transparent, click on

2:13

this last bar on the right. And then in

2:16

this square here, change the alpha all

2:19

the way down to zero. Perfect. Now click

2:21

out of that. Now we have this little

2:23

circle pixel circle. And that'll do for

2:27

now. We also need something to tell it

2:31

collision. As this node configuration

2:33

says, it needs a collision shape. So

2:35

right click, add collision shape 2D.

2:40

Double click there. Add that. We're just

2:42

going to use in the shape another

2:45

circle. We zoom in here. Zoom in here.

2:50

We just want our collision shape to

2:51

match

2:53

the pixel. Maybe make it a little wider.

2:56

Perfect. Now, in our projectile section

2:59

here, click on the root node. We want to

3:02

go into our collision. Now, we don't

3:04

want to collide with our player. We

3:06

uncheck that. We also want to uncheck

3:09

the mask. We don't want to detect

3:11

collisions with our player. We only want

3:13

to check the mask or collisions on the

3:16

enemy. Now, you don't need it be on a

3:18

layer specifically. We're just going to

3:20

check the mask if it collides with the

3:22

player. And then it will do whatever it

3:24

needs to do. So then we need to attach a

3:27

script to say what we want to do when it

3:29

collides. With the projectile selected,

3:32

add script. want to add not just in the

3:35

root node, our root path, but I go into

3:38

our scripts folder. Open. And now it's

3:41

in our scripts folder. Create.

3:44

Now I'll make this bigger. Get rid of

3:47

this output. Click in there. And we get

3:49

rid of this boilerplate code for now. We

3:51

do not need that.

3:53

All right. First thing we need, we need

3:55

to see how fast it's going to go. So

3:56

we'll make a variable. Speed is going to

3:59

be uh 600.

4:01

And then we need where we want the

4:04

projectile to go. So we need a direction

4:06

and we're going to set it to default to

4:08

vector to do right.

4:11

And then we'll change that depending on

4:13

where it needs to be going. And next we

4:16

want to have a variable see how far it

4:19

went so we can keep track of where our

4:21

bullet is. So once again if it's it's

4:24

gone too far range range traveled just

4:27

like our enemy we want to get rid of it.

4:28

We don't want them flying around

4:30

forever. We'll set this to zero. Then we

4:34

do need a function, the physics process

4:36

function, the delta and float.

4:40

And then we want to enter down into the

4:42

function. The first thing we want to do

4:44

is move in the set direction that we

4:47

find. And how that well, we'll store the

4:49

movement in a variable. And then we'll

4:52

use the direction that we set up top and

4:54

multiply that by the speed.

4:57

And for this one, because we're not

4:58

using the move and slide, we do need to

5:00

use our delta because this will be

5:02

frame. We want to make this frame

5:03

independent because we don't want to

5:06

have a higher graphics card means your

5:07

bullet will just fly a million miles an

5:10

hour. So, we're going to limit it to how

5:12

we want how fast we want it to go, which

5:15

is a 600. And multiplying by delta will

5:17

do that for us. Those familiar with the

5:19

Unity engine, it's timed delta time,

5:21

those kind of things. Same thing. And

5:24

after that, well, we have the movement.

5:25

Now we just need to move the position of

5:29

the whatever this is attached to. And

5:31

we're going to plus equals that to the

5:33

movement.

5:35

Great. Now we got our projectile moving.

5:37

Now we just need to see if we need to

5:39

delete it or not. If it's gone too far.

5:41

So the range check if it delete. Delete

5:44

if it goes too far. There we go.

5:48

Perfect. Now we do that. We just take

5:50

our range traveled we set up there. And

5:52

then we're gonna add the length of the

5:55

traveled projectile.

5:58

All right? So the length, so how far

6:01

projectile has gone. Then we're going to

6:03

check if that range has traveled a

6:05

certain distance.

6:07

So greater than say a,000 pixels. Well,

6:10

we're going to get rid of it. There we

6:12

go. And not redraw. Not redraw. Free.

6:15

There we go. Want to delete. Not come

6:18

into existence again. All right. Now

6:20

that we've deleted that, we need to

6:23

actually

6:25

save and we need to save it in the

6:28

scenes folder. Oh, this is saving the

6:31

scene. That's fine, too. We'll save the

6:33

scene. Perfect. Players projectile

6:36

script is saved. Let's minimize this

6:38

real quick. Now, we need to go into the

6:41

projectile

6:42

root node and then in the by the node by

6:45

the inspector, we click the node here.

6:48

Oh, if it does this, we can click away

6:50

and click back on. There we go. Now,

6:52

what we need is the body entered. So, we

6:55

need to connect this to our projectile

6:58

script. And this will tell us when

7:00

something has entered the body of the

7:02

projectile. So, we can double click

7:03

that. Make sure it's on the projectile

7:05

script and connect. Then, I'll maximize

7:08

this script again.

7:11

Then, now we have the on body entered.

7:13

Now, what do we want to have happen when

7:16

something enters the body of the

7:17

projectile? Well, since we only I

7:22

minimize that again. Go into the

7:24

inspector. Since we only put the mask

7:27

two,

7:28

anything that this detects is going to

7:32

be only an enemy. Now, if you had a

7:34

player on here as well, you would have

7:36

to differentiate between, well, is this

7:39

a player or is this an enemy that this

7:41

projectile has collided with? But since

7:44

we only set two of the enemy,

7:47

we know this projectile has hit an enemy

7:49

if this gets triggered at all. That

7:52

makes coding a little simpler here. So,

7:54

I'll maximize this again.

7:57

So, okay, delete this

8:00

boiler plate here. So, I'll make a note

8:02

of that. So we only mask layer 2 enemies

8:07

or enemy.

8:09

So the body that is being passed in here

8:14

must be an enemy. So now we know. So all

8:18

we have to do is check

8:22

if body

8:25

has method. Now we're going to write

8:27

this method in a second. So it doesn't

8:29

exist yet, but it will. We're going to

8:32

put a method called take damage on our

8:35

enemy.

8:37

So there we go. So if this body has the

8:39

method take damage, so we want the enemy

8:41

to take damage. For some reason, we can

8:43

make an invincible enemy and we can not

8:46

have it have that. Well, then our

8:48

projectiles won't hurt it. We want to

8:50

call body.

8:52

Damage only if it has this function.

8:56

Now, this doesn't know if it does or

8:58

not. So this if is statement is going to

9:01

save us from throwing an error if it

9:03

doesn't have the take damage function.

9:06

So else

9:08

after it's take it's checked that we

9:11

just want to delete it for now. Q3.

9:17

So instead of letting him live forever

9:19

or projectile not do anything. Well,

9:20

we're just going to delete him anyway

9:22

for now until we want to get more

9:25

complicated with this. So let's make a

9:28

note of that. So we'll add

9:31

this method

9:33

to enemies

9:36

to enemies

9:38

spell here in video five. Okay, the next

9:41

one for now let's just

9:45

delete them so we can do other things.

9:48

Perfect. After we delete the enemy,

9:51

after we hit it with a projectile, we'll

9:53

deal with health and all that in a

9:54

little bit. We're just going to delete

9:56

the bullet. Q

9:59

three.

10:02

Don't be so hard to spell. There we go.

10:04

So, what does this do? This just

10:05

destroys the bullet. So, the bullet gets

10:08

destroyed if it hits something or gets

10:11

uh this projectile.

10:13

Destroys the projectile. So, the

10:16

projectile gets destroyed if it hits an

10:17

enemy and the enemy gets destroyed if it

10:20

gets hit by a projectile. Um, just in

10:23

this logic, this is expandable. So, it's

10:25

nice to have in case you want something

10:27

else to happen when the bullet hits

10:28

them. And when we get a take damage and

10:30

a health bar for the enemy, they won't

10:32

die in the first hit. And since we know

10:34

body is an enemy, we don't have to check

10:36

if it is or not. Great. Now, save that.

10:39

S or file save scene save.

10:44

And now, let's equip the player. We need

10:46

a scanner to tell us who's nearby. We're

10:49

going to use an area 2D again, but not

10:51

for physics, just for detection. I go

10:54

back into our player scene here. I'm

10:56

going minimize this. Go to my 2D. Now

11:00

I'm going to

11:02

make those smaller. And in my root node

11:04

of my player, I'm going to add a child

11:07

node 2D.

11:09

I'm going to rename this to holster.

11:13

I'm going to add a timer to my holster

11:17

here. And then I'm going to set the wait

11:19

time on this timer in the inspector to

11:22

0.3.

11:24

So that'll fire pretty fast right now.

11:26

So we'll check auto start to on,

11:30

but we also need to have an area 2D

11:33

selected. Select our holster, right

11:35

click, add child node, area 2D.

11:39

We want to rename this to the

11:41

rangefinder.

11:44

And to the rangefinder, we want to add a

11:46

child node, collision

11:49

shape 2D.

11:51

And this collision shape, we're going to

11:53

make it a circle shape 2D in the

11:56

inspector. And we're going to make it

11:59

really big. So I found 320 for the

12:03

radius. And you see this 320 highlights

12:07

all up and down entirely of our screen.

12:10

I don't want it shooting outside of our

12:12

viewport here. So I want to be able to

12:14

shoot the enemy if I can see them. And

12:17

then this safe spot here in the corners

12:19

for the enemies. So, we won't shoot them

12:21

in the corners. We're only going to

12:22

shoot them when they enter our collision

12:23

shape 2D. Now, for our collision in our

12:27

rangefinder here,

12:30

rangefinder selected. Go into collision.

12:33

Now, we don't want to worry about the

12:35

player. We don't want to be on a layer

12:37

there. We only want to find the enemies.

12:40

So, once again, deselect the mask for

12:42

the player and just select the mask for

12:45

the enemy. We only want to detect the

12:48

bad guys.

12:50

I reached a checkpoint. It's the nearest

12:52

neighbor problem. Now, the rangefinder

12:55

can give us a list of every enemy inside

12:57

the circle using get overlapping bodies.

13:00

But the list that it give us is

13:02

unsorted. It might give us an enemy 500

13:05

pixels away, ignoring the one right at

13:08

our ankles. So, we need to write an

13:10

algorithm to sort them out. So, we're

13:12

going to loop through the list, measure

13:14

the distance to each one, and then save

13:17

the winner.

13:18

So, let's script the holster. Now, we're

13:20

going to connect the timer to fire, but

13:22

only if we find a target. So, to the

13:25

holster here, we're going to add a

13:27

script

13:29

not in our scenes folder. Go to our

13:31

path. Go up to our root. Go into our

13:34

scripts. Holster.gd is fine. Open.

13:37

Create.

13:39

And let's get rid of this boilerplate

13:41

code for now. Now, first things first,

13:43

we want to take our timer. Click there.

13:47

And we want to go into our node section

13:49

right by the inspector and connect this

13:52

timeout function to the holster, not the

13:56

player. So scroll down to the holster.

14:00

We want to connect this timer to its

14:02

holster. So now that we have that,

14:04

connect. That should pop up in your

14:06

holster script that we just wrote. Now

14:08

let's get a couple variables here up

14:10

top. The first export one. Export var.

14:14

We need the scene of the projectile we

14:16

want to launch from the holster. So the

14:18

scene and it's going to be a packed

14:21

scene. I'll go ahead and make this

14:23

bigger. There we go. And then an on

14:26

ready. On ready will fire when the node

14:30

is ready. Is going to be the

14:32

rangefinder.

14:34

Okay. And that's going to equal to our

14:37

money symbol rangefinder. Once again, it

14:40

should pop up. If it doesn't, perhaps

14:43

you changed your node name to something

14:46

else or you didn't rename it at all. So

14:49

in our minimize this. So in our holster

14:52

section, we change this area 2D to a

14:55

rangefinder and that is what we're using

14:57

in this already. We'll make that bigger.

15:00

Now that we have those, we need to go

15:03

into our timer timeout function

15:06

and make that work. So the first thing

15:08

we want to do is we're going to get all

15:11

the enemies in range. So we have that in

15:14

a big list. So var enemies in range

15:19

in range. That's going to be the

15:21

rangefinder. So we have that. We do that

15:24

one we called get overlapping bodies.

15:27

That's what we want. And then after we

15:30

have all the bodies in range. Well,

15:33

first we need to check if there are any

15:34

enemies. If there are no enemies, we're

15:36

going to stop. Stop here. How do we do

15:39

that? Well, if the enem is in range is

15:44

uh size is zero. Well, return stop.

15:51

Don't need to go any further. But if

15:53

there are enemies in range, well, we

15:55

need to find the closest one.

15:58

So, first we're going to set our target.

16:00

We're going to keep it null

16:03

right there. So if there isn't a target

16:06

enemy from the last time this ran after

16:08

the timer timed out before, we want to

16:10

reset that to null. We want a new enemy.

16:13

So we also want to get the shortest

16:15

distance.

16:16

So we make a new variable shortest

16:19

distance

16:20

equals

16:22

NF.

16:24

Now what is this? Well, that's infinite.

16:26

So first we're going to start with

16:28

infinite distance and then we're going

16:31

to narrow it down from there. infinite

16:34

distance. Perfect.

16:37

And then we're going to loop through our

16:39

enemies to find out which one's closest

16:42

to us. So for the enemy with enemies in

16:45

range, well, we need to measure the

16:48

distance from the holster. Measure

16:51

distance from holster to enemy.

16:56

So after we do that by well we store the

16:58

distance in the variable and then we

17:00

want to get the global position.

17:03

Then once again we use the distance to

17:06

just like we did with the enemies

17:09

but we want to check the distance to not

17:10

the player but the enemy enemy

17:14

global

17:16

position.

17:18

There we go. There's that.

17:22

Then we have that we're going to check

17:26

the distance now that we have the

17:28

distance is less than the shortest

17:31

distance.

17:34

So it's all the distances save the

17:36

shortest distance from our infinite and

17:41

as it loops through it'll grab that

17:42

shortest one and once it has it well the

17:45

shortest distance becomes the distance

17:49

or the distance becomes the shortest

17:50

distance. Sorry, I had that backwards.

17:52

And then our target enemy

17:55

becomes this enemy we got the distance

17:58

to here, the target enemy is now that

18:01

enemy.

18:03

There we go. And last but not least,

18:06

well, after we have the closest enemy,

18:10

well, we need to fire. Fire at the enemy

18:14

or the winner. Yeah, fire at the winner

18:16

to the shortest distance. Perfect. So,

18:18

if the target enemy that we set in the

18:22

loop. Well, we're going to shoot target

18:25

enemy.

18:27

Great. And notice we don't have a shoot

18:29

yet. Well, we're going to do that. Now,

18:32

we found the target. Now, we need to

18:34

create the projectile. Remember, we must

18:37

not add the projectile as a child of the

18:39

holster or it's going to move when we

18:41

move. It needs to live in the world.

18:44

Much like we did with the enemy with our

18:46

mob spawner, we use the get tree to

18:48

spawn it on the root node of the current

18:50

scene. We do much the same here. So in

18:54

our holster script here, we're going to

18:56

do create the new function called shoot.

18:58

Enter down a couple times and then

19:01

function funk shoot. And what are we

19:04

going to shoot? Well, we're going to

19:05

shoot the target that gets passed in.

19:08

The first thing we need to do is create

19:09

the projectile. So, new projectile

19:13

is going to equal the projectile

19:16

scene that we have up top. And we're

19:19

going to instantiate it.

19:22

And now that we have that, well, we need

19:24

to set the starting position

19:28

to the holsters

19:30

position. Perfect. So, we're going to

19:33

make a the new projectile.

19:36

New projectile. There we go. is going to

19:39

be the global position

19:44

of the holster which is the global

19:46

position which just accesses what this

19:48

script is attached to. So then we need

19:51

to calculate

19:53

the direction to the target to target.

19:58

Perfect. Then the var direction

20:03

2 target our new variable. Well, that's

20:07

going to equal to the global position

20:10

dot direction two. Again, really handy

20:14

function there. Well, we need a

20:16

direction to what? We need a direction

20:17

to the target.

20:20

Global position. Ah, I don't spell

20:24

right. Global position.

20:27

There we go.

20:29

Now that we have that, we have the

20:31

direction to the target. Well, what we

20:34

need to do, we need to change the

20:37

projectiles direction. New projectile.

20:42

We need to set the direction

20:44

to the direction that we just got. So,

20:48

direction to target. All right. Now, we

20:50

have all the calculations done. Well, we

20:52

need to look at it. So, say you had an

20:55

arrow or something like that. instead of

20:56

a ball, we want to rotate the projectile

21:00

to actually face the target it's going

21:02

to attack. So what we do is rotate

21:06

projectile visually

21:08

to face target. And we do that just by

21:12

saying the new projectile

21:14

look at

21:16

to look at the what we want to look at

21:18

the target. Global position.

21:23

Global position.

21:26

Perfect.

21:28

And last but not least, well, we need to

21:30

add it to the main world, not the

21:33

holster. So, how do we do that? Well, we

21:36

get the tree of the scene. So, get tree

21:39

of the current scene we're in. So, it'll

21:41

get the root node. We want to add the

21:43

root node. We want to add the child to

21:46

the root node. So, we want to add the

21:48

child. The child we want to add is the

21:51

new projectile.

21:54

Perfect. Now, after all that, Crl Save

21:58

all of that. I'm going to make that

22:01

smaller. Now, in our holster here, back

22:04

in our inspector here, we need to do is

22:07

set the projectile we want to fire. So,

22:09

this projectile scene is going to be our

22:12

projectile scene. Click and drag that

22:15

and drop it in there. Now, it knows

22:17

which projectile to use.

22:19

So, after all that's set up, we're going

22:22

to go back to our we're going to save

22:24

that. Go back to our main game here. And

22:27

then we're going to run the current

22:28

scene and give this a test. So, running

22:31

the current scene, we're going to run

22:32

around. Soon as the enemies start

22:33

popping up, there we go. See our bullets

22:36

start firing. They fly off. They're

22:38

going to delete themselves. Let's make

22:40

sure they do. If we go into our remote

22:42

section here, go to our main game, we

22:45

can see our

22:47

projectiles,

22:49

our enemies as well. Here and our Let's

22:53

open up our game here. There we go. We

22:57

also see our projectiles. So, if we run

22:59

around and then our projectiles start

23:01

missing, well, they don't keep stacking

23:03

up and the enemies don't keep stacking

23:06

up as well. This will keep all the stuff

23:09

optimized. because you don't want too

23:10

much of this stuff on the screen. Even

23:12

with 2D, it will bog down anyone's

23:15

system eventually.

23:18

And there you have it, an automated

23:19

turret system. We scan the area, loop

23:22

through the array to find the closest

23:23

threat, and instantiate a projectile.

23:26

But right now, killing enemies gives us

23:29

nothing. So, in the next video, we're

23:30

going to add the dopamine. will

23:32

implement the XP system, enemies

23:34

dropping gems, a smooth XP bar, and the

23:38

level up screen. Now, if you found this

23:41

helpful at all or fun, leave a comment

23:43

what your GDO game dev goals are. I love

23:45

seeing your stuff. Now, please like,

23:47

subscribe, and hit that notification

23:49

bell. It really helps out the channel.

23:50

And thank you to all our current and

23:52

past Patreon and coffee members. Your

23:54

generous support keeps the channel

23:56

moving. Now, if you want early access to

23:58

tutorials, source code, or suggesting

24:00

future tutorials, please consider

24:02

becoming a member yourself. The links

24:04

are in the description. I'm Spaghetti

24:06

Syntax, and remember, finished not

24:08

perfect, fail fast, fail often, always

24:11

stay curious, and I'll see you at the

24:13

next checkpoint.

Interactive Summary

This video explains how to create an auto-aiming weapon system in a 2D game. It covers the creation of a projectile, its movement, and collision detection. It also details setting up a rangefinder for the player to detect enemies and a timer to trigger shooting. The script for the player's 'holster' finds the closest enemy using `get_overlapping_bodies` and then instantiates and directs a projectile towards it. The video concludes with a demonstration of the auto-aiming system in action and previews the next video's focus on adding an XP and reward system.

Suggested questions

6 ready-made prompts