+1 vote

Hi,
I made a script where the enemy has a field of vision and if it sees the player, it will follow and rotate towards him.

But the enemy object just stops midway and only moves again when the player moves.
I also noticed that this happens when the enemy object moves in a straight line towards the player.

I checked every if statement and the other variables, but I just can not figure it out.

This is the code I wrote (It is in the enemy object):

    extends KinematicBody2D

var speed = 50
var FOV = 45
var detection_radius = 400
var velocity = Vector2()

func _physics_process(delta):
    var facing = Vector2(1,0).rotated(rotation).normalized()
    var player = get_parent().get_node("Player")
    var distance_to_player = player.global_position - global_position
    if distance_to_player.length() <= detection_radius:
        if rad2deg(acos(distance_to_player.normalized().dot(facing))) < FOV:
                var direction = (player.global_position - global_position).normalized()
                velocity = direction * speed
                move_and_slide(velocity)
                velocity = move_and_slide(velocity)
                look_at(player.global_position)
asked May 27 in Engine by DeadLy38 (18 points)
edited May 27 by DeadLy38

1 Answer

+1 vote
Best answer

This might be a Godot-Bug... (EDIT: Probably more a problem with floating-point-precision-stuff. normalize can't provide infinite-precise vectors.)

distance_to_player.normalized().dot(facing)

gives values > 1. (Something like 1.0000001)
acos does really NOT like values > 1

Try this:

extends KinematicBody2D

export (float, 1.0, 100.0, 1.0) var speed : float = 50.0
export (float, 0.0, 360.0, 1.0) var FOV : float = 45.0
export (float, 0.0, 1000.0, 5.0) var detection_radius : float = 400.0

var velocity : Vector2 = Vector2.ZERO

onready var player : KinematicBody2D = $"../Player"

func _ready() -> void:
    FOV = acos(deg2rad(FOV))

func _physics_process(delta : float) -> void:
    var facing : Vector2 = Vector2.RIGHT.rotated(rotation).normalized()
    var distance_to_player : Vector2 = player.global_position - global_position
    var direction : Vector2 = distance_to_player.normalized()

    if distance_to_player.length() <= detection_radius:
        if direction.normalized().dot(facing) > FOV:
                velocity = direction * speed
                velocity = move_and_slide(velocity)
                look_at(player.global_position)

i optimized a little bit. Please ask, if something is unclear!

EDIT2:
You can debug suchs problems easily, if you just print out some variables while running your game.

answered May 27 by whiteshampoo (976 points)
selected May 27 by DeadLy38

Thank you very much for your answer. I will try it out.

I did print the variables and if statements while debugging, but the problem was that there was nothing out of the ordinary visible. Though I did notice that once the dot product reached 0 the enemy just stopped.

Thanks again for your answer, I will come back once I tried it out.

EDIT:
It works now! Thank you very much, I had been struggling with this problem for over a day now!

Just one more question, in your example code you used something called void (like: "func physicsprocess(delta : float) -> void:") what does this do exactly?

That says the editor, that delta is a float, and the function/method will return nothing (void)

See Static-Typing in the docs.

Use this whenever possible. This can prevent some nasty bugs and helps the editor to help you with autocomplete-suggestions.

Hi,

Just wanted to say thank you for your help.
I understand much more about GDscript because of your help :D.

Have a nice day!

Always with pleasure :D

(more very handy stuff)

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.