Hello, i made some particles but they don't appear when the gun shoots

Godot Version

4.4

Question

i made some particles one for when the gun shoots and one for where it shoot, the second one is not appearing in game
u know what im making wrong?

@export var fire_rate := 14.0
@export var recoil := 0.05
@export var weapon_mesh: Node3D
@export var Weapon_damage := 15
@export var rays: GPUParticles3D 
@export var sparks: PackedScene


@onready var cooldown: Timer = $cooldown
@onready var weapon_position: Vector3 = weapon_mesh.position
@onready var ray_cast_3d: RayCast3D = $RayCast3D

# Called when the node enters the scene tree for the first time.

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if Input.is_action_pressed("fire"):
		if cooldown.is_stopped():
			shoot()
	
	weapon_mesh.position = weapon_mesh.position.lerp(weapon_position, delta * 10)
	
	
func shoot() -> void:
	rays.restart()
	cooldown.start(1.0 / fire_rate)
	var collider = ray_cast_3d.get_collider()
	print("fires",collider)
	weapon_mesh.position.z =+ recoil
	if collider is Enemy:
		collider.Hp -= Weapon_damage
	var spark = sparks.instantiate()
	add_child(spark)
	spark.global_position = ray_cast_3d.get_collision_point()

You’re setting spark.global_position; I’m not sure what happens when you do that.

In theory, usually global_position comes from the engine walking the tree and accumulating transforms, so (say) your gun script there is a grandchild of the scene, it’s global_position will be its own position added to its parent’s position (ignoring rotation for the moment).

What I’m not sure about is what happens if you set global_position directly. Does it look at the parent and do the math to set position correctly so global_position will still be right on subsequent updates? Or does it just set the value and then get stomped during the next update?

Edit: add_child(spark) here is also (assuming your script above is the weapon script) adding spark as the child of the weapon, which means it will move relative to the weapon.

like i have the particle (spark) as its own scene and yes this is the gun that becomes a child scene of the player and then that becomes a child scene of the test map,

but now that i think of it i think there is another problem that causes this becuse when i put to print something on get_collision it dosent print it but when i shoot the test enemy it does interact and kill it (without the particles showing tho)

Maybe try making a shots node off the root of the main scene, and add_child() your shots to that; if the shots node’s position is zero, position and global_position for each shot should be identical.

Having the shots parented to the weapon is liable to cause you grief in other ways as well; if you switch weapons, for example, what happens to shots/sparks that are in flight?

global_position is the global_position of a node, relative to 0 0 0. setting global_position places the node relative to the world.

rays.restart()
this removes all spawned particles.

I would not do that.
either set emitting = true, or spawn a particle scene for each shot and have it delete itself after a timer finishes.


var spark = sparks.instantiate()
add_child(spark)
spark.global_position = ray_cast_3d.get_collision_point()

this code is perfect. but… you are adding spark as child of current node, which might be the gun.
get a reference to player and add_sibling or get a reference to the world and add_child


@onready var player : Node3D = $..#if player is parent

add_sibling(spark)

im confused as to how should i write that

sorry, my bad.

@onready var player : Node3D = $".."

but just grab your player or root of player scene and drag it while holding the Ctrl key into the script

i added the player scene onto the gun script but no changes