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()
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.
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?
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.
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.
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.