My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Not per se. There is nothing in particular wrong with Task.Delay
in games, nor too many instances of it.
However, what you are doing after Task.Delay
can be a problem. If you execute await Task.Delay(span);
, the code that comes after might run in a different thread, and thus it could cause a race condition. This is because of await
, not because of Task.Delay
.
For example, if after await Task.Delay(span);
you will be adding a Node
to the scene tree (e.g. a bullet), that will interfere with any other thread using the scene tree. And Godot will be using the scene tree every frame. A quick look at Thread-safe APIs will tell you that the scene tree is not thread-safe. By the way, the same happen with virtually any widget API out there.
The solution is use call_deferred
(CallDeferred
in C#) to interact with the scene tree. And, yes, that could offset the moment it happens to the next frame.
I'll give you a non threading alternative to do that.
There are method get_ticks_msec
and get_ticks_usec
(GetTicksMsec
and GetTicksUsec
in C#) on the Time
class (previously OS
class), that give you monotone time which you can use for time comparison.
So, if you make a queue with the times it should shoot (computed by taking the current time plus whatever interval you need). Then in your process or physics process callback, you can check the queue. Dequeue all the times that are overdue, and create those bullets.
If you don't want to solve this with Godot APIs, then start a Stopwatch
at the start of the game, and use its elapsed time.
But perhaps that is not the mechanic you want anyway. If you want a good old cool-down, you can start the Stopwatch
when you need the cool-down, and then compare the elapsed time with the cool-down duration you want to know if it is over.