I think yield(get_tree().create_timer(gun.fire_rate), "timeout") is causing your issues. When you yield() you actually drop out of the function and step back into the function when the signal is emitted. It can be finicky depending on how you use it. In this case _input() may be firing in such a way where it doesn’t line up with the timer created in your yield() statement
I think your gun object should have a Timer as a child node that keeps track of whether it can shoot or not.
gun_script.gd
onready var shot_timer = $Timer
func _ready() -> void:
shot_timer.one_shot = true
shot_timer.process_mode = TIMER_PROCESS_IDLE
shot_timer.wait_time = 1.0 # whatever you want it to be
...
func can_shoot() -> bool:
return shot_timer.is_stopped()
func shoot() -> void:
# you can check if can_shoot(): here or do it in a function that calls this
shot_timer.start()
... # the rest of the logic here
Thank you for the answer! I created a timer node in the gun scene and accessed its state in the player script. I compared the result with how it was previously and it definitely seems to be better, but the delay is still present.
I wrote another comment where I explain what I found upon further testing.
I was thinking about removing the input check like
var can_shoot:bool = false
func _input(event: InputEvent) -> void:
can_shoot = false
```
if event.is_action_pressed("left_click"):
can_shoot = true
shoot(current_gun)
```
func shoot(gun: Object) -> void:
#shoot bullets and play sound effect
next_shot(gun)
func next_shot(gun: Object) -> void:
yield(get_tree().create_timer(gun.fire_rate), "timeout")
gun.can_shoot = true
if gun.is_automatic and can_shoot:
shoot(gun)
Thank you for the answer! I’ve tried the code above and also printing the FPS to the console. It seems that some of the inconsistencies are caused by lag spikes, but replacing the input check did not fix the problem, unfortunately.
I might have an idea of what is causing the main issue, I wrote another comment where try to I explain it.
Thank you everyone for the answers. I did a lot of further testing and I might have figured out the reason behind the issue, but I might be completely wrong. I made a timer node to time the delay between each shot. Even when the shots are very out of sync, the console prints exactly or something very close to the correct value. This leads me to believe that the main problem I have is not with the timing of the shots, but with the sound.
In this (short) example the values printed in the console show no irregularities at all, but the sound is clearly off: https://youtu.be/RjVTpj84fLc)
The code that handles the sound effect is very simple and nothing I do with it seems to affect the outcome:
var player = AudioStreamPlayer.new()
player.stream = load(path)
self.add_child(player)
player.play()
This might be unrelated, but this is the only idea I have at the moment.
Why do you create a Streamplayer for each shot and load the stream. Maybe this causes the delay.
Why not create a streamplayer once (maybe for each barrel) then call play(0.0) whenever you shot.