Enemy AI gives unexpected result

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By mateushmm14
:warning: Old Version Published before Godot 3 was released.

Well, this AI is supposed to follow the player if it is on a “reachable area”, which is determined by a “Area2D” node. Else, if there’s nothing to chase, the enemy should “wander” from point A to Point B. Everything works fine, except for the weird “wander” transition from point A to point B that, instead of smoothly translate between those points, it simply jumps to them. So, what I did wrong?

That’s it, let me know if something is not clear and thanks for your attention.

extends KinematicBody2D

var target
var speed = 2
var timer
var canWander
var d = dir.RIGHT

enum dir{RIGHT, LEFT}
func _ready():
	set_fixed_process(true)
	target = get_parent().get_node("Player")
	timer = get_node("Timer")
	timer.connect("timeout", self, "_on_timeout")
	pass

func _fixed_process(delta):
	var body = get_node("Body").get_overlapping_bodies()
	var direction = (target.get_global_pos() - self.get_global_pos()).normalized()
	
	if body.size() != 0:
		for i in body:
			if(i.is_in_group("player")):
				canWander = false
				move(direction*speed)
	elif body.size() == 0:
		if canWander == true:
			canWander = false
			timer.set_wait_time(2)
			if d == dir.RIGHT:
				move(Vector2(-16,0) * speed)
				d = dir.LEFT
			elif d == dir.LEFT:
				move(Vector2(16,0) * speed)
				d = dir.RIGHT
func _on_timeout():
	canWander = true

Your move funtion seems to be used in a wrong way.
The distance your AI moves should be calculated by the formula:
distance = velocity * time (for zero acceleration).

The velocity can be calculated as direction * speed. So in Godot you should change your:

move(Vector2(-16,0) * speed)

into something like

var direction = Vector2(-1,0)
var speed = 16
var velocity = direction * speed

move(velocity * delta)

While delta is your delta-time between two frames (given by the _fixed_process).

rolfpancake | 2017-12-11 17:47

I tried this, but it didn’t work.

	extends KinematicBody2D

var target
var timer
var canWander
var d = dir.RIGHT

var speed = 0
var velocity
var direction = Vector2()

enum dir{RIGHT, LEFT}
func _ready():
	set_process(true)
	target = get_parent().get_node("Player")
	timer = get_node("Timer")
	timer.connect("timeout", self, "_on_timeout")
	pass

func _process(delta):
	var body = get_node("Body").get_overlapping_bodies()
	velocity = direction * speed
	print (velocity)
	if body.size() != 0:
		direction = (target.get_global_pos() - self.get_global_pos()).normalized()
		speed = 2
		for i in body:
			if(i.is_in_group("player")):
				canWander = false
				move(direction*speed)
	elif body.size() == 0:
		speed = 5000
		if canWander == true:
			canWander = false
			timer.set_wait_time(2)
			if d == dir.RIGHT:
				direction = Vector2(-1,0)
				move(velocity * delta)
				d = dir.LEFT
			elif d == dir.LEFT:
				direction = Vector2(1,0)
				move(velocity * delta)
				d = dir.RIGHT
func _on_timeout():
	canWander = true

mateushmm14 | 2017-12-11 21:21

I tried your code and your problem is the immediate change of the direction:

if d == dir.RIGHT:
  direction = Vector2(-1,0)
  move(velocity * delta)
  d = dir.LEFT

In this case the AI can only move 1 frame in the given direction with the given speed. Then it turns into the other direction. Remove the line d = dir.LEFT and d = dir.RIGHT and place it into a new control sequence where you specify on what terms the AI should turn in the other direction (like a specified traveled distance).

rolfpancake | 2017-12-11 21:35

:bust_in_silhouette: Reply From: rolfpancake

Regarding the comments you could try this:

var distance
...
    speed = 100            
    ...
        if d == dir.RIGHT:
            direction = Vector2(-1,0)
            velocity = direction * speed
            distance = velocity * delta
            move(distance)
            wandered_distance += distance.length()
        elif d == dir.LEFT:
            direction = Vector2(1,0)
            velocity = direction * speed
            distance = velocity * delta
            move(distance)
            wandered_distance += distance.length()

    if wandered_distance > 100:
        if d == dir.RIGHT:
            d = dir.LEFT
        else:
            d = dir.RIGHT
        wandered_distance = 0

(This could be refactored into a more compact code structure but this was not in the scope of this question.)

Thank you, It works! Every time I try to code from scratch, I end up with a buged code like this, due my low programming knowledge. I’m pretty sure that it will help someone else, thanks again!

mateushmm14 | 2017-12-12 12:58