Welcome to the forums @Arakiti!
I would recommend using an Area2D around the enemies and players to detect bullets. While there is a slight performance cost for this (two collision checks instead of just one), unless you have many, many players and enemies all at once, it probably won't affect performance too badly that it would be noticeable. I've done this several times for both 2D and 3D and it has worked well. The Area2D node isn't nearly as performance heavy as the KinematicBody2D node, in my experience.
The benefit of doing it this way as well is that the bullet can just be a bullet, it doesn't need any extra collision or even need to know anything about what it collided with at all, making the code easier. You can optionally call functions on the object(s) that enter the area (check for functions using has_method
, for example) if you need the bullet or other damaging object to have a reference to the player or thing it hit.
All in all, I would highly suggest using an Area2D. It is simpler to program, gives a lot of flexibility in what you can do with it, and it keeps the objects pretty separate from each other if you want. It doesn't work for every project, and as you mentioned it has a performance cost, but it is the solution I would try initially.
That said, there are some ways around it that might work. The first I can think of is to have your bullets use RigidBody2D nodes instead of KinematicBody2D nodes, as I believe KinematicBody2D node to RigidBody2D collision is a bit more stable because it's done by the physics engine. The minor problem here is that you may still miss collisions if the player/enemy KinematicBody2D body is moving towards a bullet that is moving towards them, as then the physics engine has to resolve who "collided" with whom in that case since they are both moving towards each other.
I do not remember if I've tried this though, so I'm not 100% sure if it will work nor if you'd encounter issues with it or not.
Another, potentially lightweight solution would be to have the bullet's use a raycast instead of a KinematicBody2D. This would be a little more performant and would solve the issue of collisions being missed. What you'd want to do though is have the bullet send a function if it hits a damageable object, and then move in the direction of the raycast if it doesn't hit anything. The code for the bullet could look something like this:
extends Node2D
# I'll assume the velocity is set by whatever is firing the bullet
var velocity = Vector2.ZERO
# the amount of damage a bullet would do
var bullet_damage = 10
func _physics_process(delta):
var space_state = get_world_2d().direct_space_state
# raycast to where the bullet will be moving towards
var raycast_result = space_state.intersect_ray(global_position, global_position + (velocity * delta))
# if something was hit
if raycast_result:
if raycast_result.collider.has_method("damage"):
raycast_result.collider.damage(bullet_damage)
# free/destroy the bullet
queue_free()