Quick answer: Set global_position after add_child(), so the node knows its parent's transform. Add projectiles to the level, not to the moving shooter, or they move with it. If every instance is offset by the same amount, the root of the instanced scene (or its child sprite) is not at (0, 0) in its own scene.
You instance a scene, set a position and add it, and it turns up at (0, 0), a few hundred pixels away, or glued to the player. The cause is nearly always the order of operations or the choice of parent.
Cause 1: global_position set before add_child
Before a node is in the tree it has no parent transform, so setting global_position effectively sets the local position. Once added under a parent that is itself offset, the node ends up shifted by the parent's transform.
var bullet := BulletScene.instantiate()
get_tree().current_scene.add_child(bullet) # add first
bullet.global_position = $Muzzle.global_position
bullet.global_rotation = $Muzzle.global_rotation
Setting the local position before adding is fine when you know the parent's transform is identity; global values belong after add_child().
Cause 2: the wrong parent
Adding a bullet as a child of the gun or player makes it inherit every move and turn the player makes afterwards. Add it to the level (or a dedicated Projectiles node) instead. If it must be a child for organisational reasons, enable Top Level on it so it ignores the parent's transform.
Cause 3: the scene root is offset in its own scene
Open the instanced scene. If the root node is not at (0, 0), or the visible Sprite2D or CollisionShape2D child is offset from the root, every instance carries that offset. Keep the root at the origin and position children around it, with the origin where you want the spawn point to be (for example at a character's feet).
Cause 4: local vs global confusion
position is relative to the parent; global_position is relative to the world. $Muzzle.position is the muzzle's offset inside the gun, not its location in the level. Use $Muzzle.global_position when spawning.
Cause 5: the spawn point moves before the frame ends
Reading a position during _ready() of a node whose parent has not been positioned yet, or in the same frame a parent is repositioned, can return stale values. Spawn from _physics_process() or after positioning is finished, or use call_deferred().
Cause 6: Control nodes inside containers
A Control instanced into a Container is positioned by the container, so any position you set is overwritten. Set size flags or use a plain Control parent if you need manual placement.
3D
The same rules apply with global_transform and global_position on Node3D: add first, then set global transform, and make sure the scene's root is at the origin.