Yes I was looking at that before but looked much closer and did a bunch of experimenting. Turns out Area nodes ARE physics objects after all (I thought they were regular nodes). I also figured out I don't need to use apply_impulse() or anything, just set some things at the start then let it do it's own thing:
bullet = Bullet.instance()
add_child(bullet)
bullet.transform = $Spawn.global_transform
bullet.velocity = -bullet.transform.basis.z * bullet.muzzle_velocity
It flies off and I apply gravity inside the bullet itself with
velocity += g * delta
look_at(transform.origin + velocity.normalized(), Vector3.UP)
transform.origin += velocity * delta
Then I hooked body_shape_entered() to its own script and did
func _on_Bullet_body_shape_entered(_body_rid, body, body_shape_index, local_shape_index):
var armor = body.shape_owner_get_owner(body_shape_index)
if body.name != "Ground":
body.TakeHit(player, armor, Damage)
queue_free()
Inside the body it hit I do this
func TakeHit(_from, _to, _damage):
print(_from.name + " " + _to.name + " " + str(_damage))
So it's perfect. I set the player ID on the bullet then when it hits a collider "body" gives me the base node" and body_shape_index tells me which collider was hit. I'm really liking this now