Quick answer: Godot 4 RigidBody3D losing applied force after set_position called the same frame? Position set is a teleport that resets integrator state - apply force on next frame via call_deferred.
Cannonball: position to muzzle, then apply_impulse. Ball drops straight down; impulse silently discarded.
Defer the impulse
set_position(muzzle)
call_deferred("apply_central_impulse", force)Position this frame; impulse next. Physics integrates cleanly.
Or use linear_velocity directly
Set linear_velocity = velocity after position. Skips the impulse path entirely.
Wrap in helper
Spawn-with-velocity helper hides the order. Callers don't deal with the teleport dance.
“Teleports reset physics state. The reset is correct; surprising.”
For spawned projectiles, the spawn-with-velocity pattern is the standard. Encode it once; reuse everywhere.