Collision Shape Still Can Check Even When Disabled, This Is Weird

I’m getting an issue with my enemies still checking others even if it’s disabled, the get_overlapping_areas() function in my Move() function still can get disabled enemies. When I kill an enemy, it’ll set the collisionShape to disable and also the process mode and I set it back to enable when needed, please help, is this an Engine bug?

This is my Enemy.gd

func Move(delta):
	if(Global.world.localPlayer != null):
		if(currentHealth > 0):	
			#Push other enenmies without using RigidBody, the get_overlapping_areas is getting disabled Collision, don't know why
			for i in get_overlapping_areas():
				if i.collision_layer == 2:
					if speed == i.speed and global_position.y > i.global_position.y:
						var direc = global_position - i.global_position
						global_position += direc.normalized() * delta * speed
						break
						
			direction = Global.world.localPlayer.global_position - global_position
			if (direction.length() > attackRange):
				global_position += direction.normalized() * delta * speed
			if(direction.length() > attackRange and aniTree["parameters/conditions/run"] == false):
				aniTree["parameters/conditions/die"] = false
				aniTree["parameters/conditions/run"] = true
				aniTree["parameters/conditions/attack"] = false
			elif(direction.length() <= attackRange and aniTree["parameters/conditions/attack"] == false):
				aniTree["parameters/conditions/die"] = false
				aniTree["parameters/conditions/run"] = false
				aniTree["parameters/conditions/attack"] = true 			
			if(direction.normalized().x > 0 and $Sprite2D.flip_h != false):
				$Sprite2D.flip_h = false
			elif(direction.normalized().x < 0 and $Sprite2D.flip_h != true):
				$Sprite2D.flip_h = true	
func DamageObject(damage, knockbackStrength : float):
	currentHealth -= damage
	
	if currentHealth > 0:
		if knockbackStrength > 0:	
			knockback(knockbackStrength)
		$Sprite2D.material.set_shader_parameter("hit_opacity", 100.0)
		timer.start()	

	elif(currentHealth <= 0 and aniTree["parameters/conditions/die"] == false):
		$Sprite2D.material.set_shader_parameter("canFlash", false)
		var tween : Tween = get_tree().create_tween()
		direction = Global.world.localPlayer.global_position.direction_to(self.global_position)
		tween.parallel().tween_property(self, "global_position", global_position + (direction * 50), 0.4)
		tween.parallel().tween_property($Sprite2D, "modulate", Color.TRANSPARENT, 0.4)
		Global.world.consumablePool.CreateConsumable(global_position, 1)
		tween.tween_callback(DisableObject)
func DisableObject():
	Global.world.enemySpawner.enemyOnMap -= 1
	if Global.world.monstersKilled.has(GlobalEnums.EnemyName.keys()[enemyName]):
		Global.world.monstersKilled[GlobalEnums.EnemyName.keys()[enemyName]] +=  1
	else:
		Global.world.monstersKilled[GlobalEnums.EnemyName.keys()[enemyName]] = 1

	$CollisionShape2D.call_deferred("set_disabled", true)
	process_mode = Node.PROCESS_MODE_DISABLED
	visible = false

This is how i spawn my enemies:

func CreateEnemy(type : GlobalEnums.EnemyName, initPosition : Vector2):
	#Get disabled enemy
	var ref : Enemy = poolList[GlobalEnums.EnemyName.keys()[type]].GetDisabledPoolingObject()
	ref.process_mode = Node.PROCESS_MODE_INHERIT
	ref.visible = true
	ref.currentHealth = ref.maxHealth + monstersHealthIncreased
	ref.global_position = initPosition
	ref.ResetState()

	enemyOnMap += 1

Is this occurring in the 1-2 frames after disabling it? If so, it may be a combination of using set_deferred() to disable the collision shape (which is correct as you’ll get an error if you try to set it immediately) and Area2Ds being late to update.

I run into that circumstance frequently, and this inherent lag can be a problem. So I usually have my own “enabled” variable on the Area2D that I manually set and check it as well whenever there’s a collision, since it will update immediately.

If your Area2D’s are never getting disabled, however, there’s probably something else going on.

1 Like

the enemy’s get_overlapping_areas keeps getting the disabled enemies, so it won’t move to but keep trying to push each others

Can you verify that the Area2D.disable_mode is set to DISABLE_MODE_REMOVE? Otherwise, it will still be processed while the node is disabled. It’s set by default, but makes the most sense. (link)

Another thing to check is that you’re getting the expected behavior from the for i in get_overlapping_areas(): loop in Move(). From the docs: “For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved.”

So multiple collisions may be detected across multiple frames, and I’m wondering if the tween for the death is getting created multiple times. It doesn’t look like that would be preventing the DisableObject() callback, but I dunno. That’s another reason you might want a separate ‘dead’ flag beyond the node being disabled: you could prevent doing things like creating duplicate tweens. You could also ignore collisions with already dead enemies if you check the ‘dead’ flag in the overlapping area.

If you’re desperate, you can also update the location once the enemy is disabled to put it outside of game bounds until you re-use the node. But that might be hiding an issue that could bite you later.

Hope that helps… I’m still trying to learn this monster :grimacing:

1 Like

Thanks for the help!, i’ll try to check if it’s disabled in the move function.