My mobs are acting weird


when my mob gets hit by player detection collision with Y-sorting tiles they stop or pass through those tiles.

here is the mob code:

func _on_area_2d_body_entered(body):
	player=body
	player_chase = true


func _on_area_2d_body_exited(_body):
	player = null
	player_chase = false

Have you tried:

func _on_area_2d_body_exited(_body):
	player_chase = false
	player = null

If that doesn’t solve it, the problem is probably in your _process() or _physics_process() code for the enemy.

unfortunately it didn’t help (attached physics processes)

func _physics_process(_delta):
	
	deal_with_damage()
	
	
	if player_chase:
		position +=(player.position - position)/max_speed
		$AnimatedSprite2D.play("run")
		if (player.position.x - position.x) < 0:
			$AnimatedSprite2D.flip_h = true
		else:
			$AnimatedSprite2D.flip_h = false

	else:
		$AnimatedSprite2D.play("idle")

	

maybe there’s something wrong with them

Hi,

My guess would be that you have a keyframe for the position inside the idle animation.
In your video, we can see that the two mobs on the left are overlapping when in idle, which shows they’re not going through the tiles, their position is just reset by some code/animation.
image

Check your idle animation and make sure there’s no key for the position. If that’s not the problem, please share the full enemy code.

1 Like


it doesn’t have an animation player so i doubt it’s the animation keys

Here is its full code

extends CharacterBody2D
@onready var animated_srtite_2d = $AnimatedSprite2D
var max_speed = 70
var player_chase = false
var player = null
var health = 40
var player_inattack_zone = false
var can_take_damage = true



func _physics_process(_delta):
	
	deal_with_damage()
	
	
	if player_chase:
		position +=(player.position - position)/max_speed
		$AnimatedSprite2D.play("run")
		if (player.position.x - position.x) < 0:
			$AnimatedSprite2D.flip_h = true
		else:
			$AnimatedSprite2D.flip_h = false

	else:
		$AnimatedSprite2D.play("idle")

	



func _on_area_2d_body_entered(body):
	player=body
	player_chase = true


func _on_area_2d_body_exited(_body):
	player_chase = false
	player = null


func enemy():
	pass
func handle_hit():
	health = health - 10
	print(health)
	if health <=0:
		self.queue_free()

func _on_enemy_hitbox_body_entered(body):
	if body.has_method("player"):
		player_inattack_zone = true
	if body.has_method("arrow"):
		player_inattack_zone = true

func _on_enemy_hitbox_body_exited(body):
	if body.has_method("player"):
		player_inattack_zone = false
	if body.has_method("arrow"):
		player_inattack_zone = false
func deal_with_damage():
	if player_inattack_zone and global.player_current_attack == true:
		if can_take_damage == true:
			health = health - 20
			$take_damage_cooldown.start()
			can_take_damage = false
			print("enemy health =", health)
			if health <= 0:
				self.queue_free()


func _on_take_damage_cooldown_timeout():
	can_take_damage = true


func _on_area_2d_2_body_entered(body:Node2D) -> void:
	if body.has_method("player"):
		var knockback_direction = (body.global_position - global_position)
		body.apply_knockback(knockback_direction,10.0, 0.12)

TBH I don’t see the issue, but I do see a lot of issues in your code. It is way overcomplicated.

  1. You are identifying objects by creating dummy functions inside them to identify them. Clever, but a class_name will do the same thing.
  2. You also are creating an @onready variable and then never using it - when you should be using it.
  3. You don’t need a player_inattack_zone variable that should be handled by physics masks and layers.
  4. Neither do you need can_take_damage because you don’t need to deal with damage every frame - only when it happens. And if you want to limit how quickly an enemy can take damage, change the attack rate of the player. Because swinging and nothing happening makes gameplay suck.
  5. The style guide recommends putting two spaces between each function. It makes readability clearer.
  6. You have two functions for the enemy to take damage. I deleted handle_hit because it is never used.
class_name Enemy extends CharacterBody2D

var max_speed = 70
var player_chase = false
var player = null
var health = 40

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D


func _physics_process(_delta):
	if player_chase:
		position +=(player.position - position)/max_speed
		animated_sprite_2d.play("run")
	else:
		animated_sprite_2d.play("idle")
	#simplified this and moved it out of the chase functionality so that your monsters will turn to look at the player when they're not chasing as well (put it back if you don't want that functionality)
	animated_sprite_2d.flip_h = player.position.x - position.x < 0


func _on_area_2d_body_entered(body):
	player=body
	player_chase = true


func _on_area_2d_body_exited(_body):
	player_chase = false
	player = null


func _on_enemy_hitbox_body_entered(body):
	deal_with_damage()


func deal_with_damage():
	health = health - 20 #This 20 is a "magic number" and you should think about getting it from the player instead of hard-coding it here.
	take_damage_cooldown_timer.start()
	print("enemy health =", health)
	if health <= 0:
		self.queue_free()


func _on_area_2d_2_body_entered(body:Node2D) -> void:
	# you need to add class_name Player to your player script for this to work
	if body is Player:
		var knockback_direction = (body.global_position - global_position)
		body.apply_knockback(knockback_direction,10.0, 0.12)

You then need to make the arrow and the player weapon (sword or whatever) bodies and put them on a weapon layer. Then have the enemy_hitbox Area2D have a mask only for that weapon layer and be on no layers itself. (Though TBH I would move this code to the weapons and have them be Area2Ds and detect what layer the Enemy is on and deal damage appropriately.)

After reading and refactoring your code, I believe the problem isn’t with this code. It is with apply_knockback() which is in your Player class.

1 Like

I don’t know, maybe I misunderstood something, but now the enemy, when in contact with the player and the Y-sorting tiles, simply dies in milliseconds