Why is only the first enemy able to take damage from a bullet?

Godot Version

4.4

Question

In my main scene, I had several instances of the same raider scene. But only the first one that I place detects collisions from my bullet scene.

The main scene breakdown:
Enemes (Node)
|-- Raider
|-- Raider2
|-- Raider3

Raider2 and Raider3 do not detect collisions from the bullet. But the first takes damage and emits the die signal correctly.
raider.gd:

extends CharacterBody2D

signal died

@export var max_health: int = 100

var current_health: int 

func _ready() -> void:
	current_health = max_health
	
	died.connect(_on_raider_died)

func take_damage(amount: int):
	current_health -= amount 
	if current_health <= 0:
		died.emit()

func _on_raider_died():
	queue_free()

Bullet.gd

extends Area2D

signal hit_something

const SPEED: int = 10000

var damage: int 

func _physics_process(delta: float) -> void:
	position += transform.x * SPEED * delta


func _on_expiration_timeout() -> void:
	queue_free()


func _on_body_entered(body: Node2D) -> void:
	print("Bullet entered body.")
	if body.has_method("take_damage"): 
		body.take_damage(damage)
	queue_free()

Make sure that the collision masks are correctly set up for all of your enemies first, that’s often the issue!

That was what I thought as well, but Layer and Mask on the bullet, and all raiders are set to 1for all of them

Because you’re destroying the bullet as soon as it hits something.

I don’t think that is the issue. The first enemy instantiated takes damage from each bullet I fire that interacts with its collision shape, but the other enemies (the same raider scene duplicated) will not.

I don’t want the bullets to travel through one enemy to next, but queue free after they hit an enmy.

That was unclear to me.

What’s your scene tree look like?

To me it looks like the problem is how you use signals.
If you connect them in _ready and something is there to connect to, it will work. But if you spawn in later it could be that whatever gets spawned in later does not connect. Try to double check with a print statement if the signals connect properly. Check error messages as well as sometimes they pop up when something is unable to connect.

I would skip the use of signals within the raider scene tbh. It seems convoluted. You have it send a signal to itself when it dies. You could just call the function after the health check.

Do you use the hit_something signal?

Do you get any prints that the bullet entered the body?

Does the bullets have any damage? It looks like you’re just using an empty variable for damage.

@baba is right about the signal being convoluted. I’m not convinced it’s the problem, but I recommend these changes to your code to simplify it.

extends CharacterBody2D

@export var max_health: int = 100		

var current_health: int = max_health:
	set(value):
		current_health = value
		if current_health <= 0:
			_on_raider_died()


func take_damage(amount: int):
	current_health -= amount 


func _on_raider_died():
	queue_free()

If another object is connecting to the signal you can add it back in:

extends CharacterBody2D

signal died

@export var max_health: int = 100		

var current_health: int = max_health:
	set(value):
		current_health = value
		if current_health <= 0:
			_on_raider_died()


func take_damage(amount: int):
	current_health -= amount 


func _on_raider_died():
	queue_free()
	died.emit() #This can come after queue_free() because queue_free doesn't happen until the end of the frame

The bullet damage is set in the gun scene, where it is instantiated, 35 damage.

In my main scene I instantiated three raiders, no changes to the scene there. The first raider will take damage correctly, bullets can interact/print interactions. But the other enemies do not, and that is why I am so confused. It works ‘perfectly’, but only on the first enemy I create.

I do appreciate the point you made about using signals in the raider scene, that does over complicate things.

Are you sure you have not made any local changes to the first instance that then did not apply to the duplicates?
Just to try I would create a group “enemy” and add the player scene to it. Then make the bullet check if whatever it hits is inside that group.
if body.is_in_group(“enemy”):
body.take_damage()

What exactly happens, when you shoot a raider, that doesn’t take damage? Does the bullet go through or get destroyed? If you set a breakpoint in take_damage function, does it get triggered? What is the value of max_health for each of the raiders and what is the value of current_health before and after a bullet hit?

The bullet just passes through and does not interact with the body.

The only group right now is enemies and they are added to it in their _ready() functions

In the main scene I just clicked on the child Raider scene and then Ctrl + D to duplicate it. It wasn’t done in the script or spawned as part of the level.

I think the issue is duplication. Try to drag the scene from your filesystem onto the scene 3 times instead of duplicating one.

Then there must be something wrong with the Raider scene, and the code is irrelevant to the problem. If you run the game and look at the scene tree in the editor, you can see all of the current nodes in the remote tab. Do all of the raiders have CollisionShape2D nodes and do they have Shape2D resources assigned to them?

Honestly, this sounds like after you duplicated it you then adjusted the collision layers/masks on the first one and that’s why the other two aren’t colliding. Do all three have the exact same settings for physics collision layers and masks?

If no suggestions work, I’d recommend deleting all three raiders and making new ones the way @tibaverus suggested. I suspect either all of them will now get hit and none of them will, and you’ll remove the problem of them acting differently.

I just realized that one potential cause is the bullet movement. If it moves really fast, it can sometimes skip over targets. Games typically handle collisions with small fast moving projectiles with ray casting, so if the bullet does a ray cast from old position to the new one, it won’t skip over it.

At the speed you have, that’s certainly a possibility. TBH at that speed you don’t really even need a model. Just do the Raycast3D and decide who hits.

I think it was the speed. I took it down to 500 to test and it worked. It works at 1000 and 2000. It stops working somewhere between 2000-3000. I do want to have bullets to travel at a ‘realistic speed’, so I’ll have to implement a Raycast2d when I do.

Thank you all for the effort to help me!

Well I believe that speed is 1 meter/per second in 3D (I could be wrong), which makes 10,000 about 23k mph. Guns shoot around 2,000 feet per second, so 500-700 is pretty close to the correct “real world” speed.