How to: Enemy detecting player?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Napoleonite

Aside from ray-casting every frame from each enemy to each player, is there any other build-in way (or a better, more efficient method) to check if it can see a player?

Should I maybe make an Area2D (attached to each enemy) and use the OnBodyEntered/Exited signals and check for a player body and only if there is one inside, then ray cast each frame? This feels so meh… I’m hoping for some build-in method/node that I overlooked.

I just want an enemy to shoot at the player but only if it can see the player. If it matters, I’m using tilemaps in a 2D platformer.

:bust_in_silhouette: Reply From: SIsilicon

First you need to have a reference to the player. I’m sure you can figure that out.
Then you take your(enemy) position and subtract from player position.

var EnemyToPlayer = Player.translation - translation

This gives a vector pointing from enemy to player. Your first condition should be distance. If the player is too far. They pretty much can’t see them.

if EnemyToPlayer.length() < MaxDistance:
    #We move on to the next step.

If that works check if the player is inside the field of view of the enemy.
By the way we are doing nested if statements.

    if acos(EnemyToPlayer.normalized().dot(facing)) < FOV:
        #Next step awaits.

Where facing is the direction the enemy is looking, and FOV defines how much he can see. An FOV of 90° would mean the enemy can see everything in front of him, but not behind him.
Then there is the last step.

        $RayCast2D.cast_to = EnemyToPlayer
        if $RayCast2D.is_colliding():
            if $RayCast2D.get_collider() == Player:
                #Do what ever you do when a player is detected

That’s right. You’ll need a RayCast2D node. Make sure the node is at the center of the enemy. And that you add the enemy’s collision shape to its exception.

func _ready():
    $RayCast2D.add_collision_exception($CollisionShape)

I was hoping for something build-in from Godot itself. But your post is a really in-depth explanation and it doesn’t require an extra two Area2D’s on every enemy. Thanks a lot!

Napoleonite | 2018-05-05 16:21

Thank you too for that compliment :). It’s not everyday you get a compliment like that.

SIsilicon | 2018-05-06 22:47

but how to get Facing i am not able to get it

Vikrant | 2021-01-29 15:16