player detection by enemy using 2d raycasts

Godot Version

4.3

Question

hi all,

this is my first project in Godot, so i am using it to learn.
I created an enemy with 2 raycasts2d Left and Right. and have the following code to detect the player, measure the distance between the enemy and player and set chasing = true to start chasing the player.

everything works fine except when the enemy is approaching the player from the left side (right raycast) the enemy stops moving and starts flipping directions in its place.

I have checked the following:

  1. player is on layer 4 and the raycasts layer masks are set to layer 4, disabled parent detection, enabled collision with bodies
  2. the scene is a characterbody2d->node2d->(raycaslt left, raycast right)
  3. both characterbody2d and node2d are at layer 3 and set to collide with layer 4 (player)
func detect_rays():
	if ray_left.is_colliding():
		if ray_left.get_collider().name == "player":
			if (enemy_pos.x - player.position.x) <= enemy_detect:
				chasing = true
	elif ray_right.is_colliding():
		if ray_right.get_collider().name == "player":
			if (player.position.x - enemy_pos.x) <= enemy_detect:
				chasing = true
	else:
		chasing = false

this is where i am setting the direction of the enemy where i have a variable flip_sprite for enemies with opposite sprite direction (some enemies have left facing images others have right facing images):
i am suspecting that there might be a problem here, but i have went code blind :slight_smile: and can’t see where the problem is:

	if !flip_sprite:
		if player.position.x >= self.position.x:
			direction = 1
			enemy_anim.flip_h = false
		else:
			direction = -1
			enemy_anim.flip_h = true
	else:
		if player.position.x >= self.position.x:
			direction = 1
			enemy_anim.flip_h = true
		else:
			direction = -1
			enemy_anim.flip_h = false

Does

else:
	if player.position.x >= self.position.x:
		direction = 1
		enemy_anim.flip_h = true
	else:
		direction = -1
		enemy_anim.flip_h = false

need to be

else:
	if player.position.x >= self.position.x:
		direction = -1
		enemy_anim.flip_h = true
	else:
		direction = 1
		enemy_anim.flip_h = false

thank you for the reply, if the player position is more than the enemy position on the x axis (enemy approaching from the left, ie right raycast2d) then direction needs to be positive 1 so that when velocity.x = direction * speed is called the enemy moves right towards the player. if it was -1 like below it will move in the opposite direction of the player.
i have the x axis is from 0 to 1152px

if player.position.x >= self.position.x:
direction = -1
enemy_anim.flip_h = true

the weird thing is that I have the code checked multiple times, collisions as well, layers, everything. its either a bug or i just need some rest that i can’t see the error.

I was hoping its a really easy fix that i am missing and another eye will help see it :slight_smile:
I saw a few codes using
move_towards
global_position
i guess i’ll have to read the documentation tomorrow and familiarize myself with those functions

Can you upload it anywhere or give me instructions for a minimal project to replicate? Re-reading it, could the ray casts be interfering? The order of the if statements suggest that maybe they could be it.

sure,
this is the latest edited physics function that deals with the enemy movement and the detect rays and attack rays. the detect_rays() and attack_rays() return boolean value attacking and chasing. i manually edited the reversed sprite images to get rid of flipping them separately.

func _physics_process(delta):
	if enemy_damage < max_enemy_damage:
		enemy_damage = enemy_damage * Game.mob_damage_factor * Game.player_level
	else:
		enemy_damage = max_enemy_damage
	
	if player.position.x >= self.position.x:
		direction = 1
		enemy_anim.flip_h = false
	else:
		direction = -1
		enemy_anim.flip_h = true

	velocity.y += gravity * delta

	detect_rays()
	attack_rays()
	
	if player_damaged:
		temp_player_health = Game.player_hp - enemy_damage
		Game.player_hp = temp_player_health
		player_anim.play("damaged")
	else:
		player_anim.play("run")
		
	if chasing and !enemy_dead:
		enemy_speed = enemy_run
	else:
		if !enemy_dead:
			enemy_speed = enemy_walk
		else:
			enemy_speed = 0

	if attacking:
		enemy_anim.play("attack")
	elif enemy_dead:
		enemy_anim.play("dead")
	else:
		enemy_anim.play("run")
	velocity.x = direction * enemy_speed
	move_and_slide()

func detect_rays():
	if ray_left.is_colliding():
		if ray_left.get_collider().name == "player":
			if (enemy_pos.x - player.position.x) <= enemy_detect:
				chasing = true
	elif ray_right.is_colliding():
		if ray_right.get_collider().name == "player":
			if (player.position.x - enemy_pos.x) <= enemy_detect:
				chasing = true
	else:
		chasing = false

func attack_rays():
	if attack_ray_left.is_colliding():
		if attack_ray_left.get_collider().name == "player":
			if (enemy_pos.x - player.position.x) <= attack_range:
				attacking = true 
				player_damaged = true
	elif attack_ray_right.is_colliding():
		if attack_ray_right.get_collider().name == "player":
			if (player.position.x - enemy_pos.x) <= attack_range:
				attacking = true 
				player_damaged = true
	else:
		attacking = false
		player_damaged = false

Screenshot from 2024-08-07 07-56-58

the detect_rays() and attack_rays() return boolean value

It looks like internally they are setting values, but they are void returning functions. Without the whole project, showing all the affected variables and how the scripts link, I don’t know how I can help. e.g is player_damaged a local or a global variable.

If you’re happy to share the whole thing I’ll gladly play with it to try to help. If not I don’t think I can help. perhaps someone more knowledgeable then me may know more.

thank you for your help. i changed the function entirely using vector2d variables and everything works now.

1 Like