在 Godot 中使用 C# 异步延迟

meg*_*old 5 c# async-await godot

我目前正在尝试用 Godot C# 制作一个基本的射手,对于枪的射速,我一直在尝试不同的延迟系统。尽管我试图使脚本通用,但节点计时器仍然有效,并且计时器调用似乎只调用父脚本中的函数。

\n

我现在正在研究 C# 的 Task.Delay 方法,它似乎也可以工作,因为它是一个异步操作,它看起来不会受到帧速率的影响或减慢游戏速度。

\n

我的问题是,在游戏应用程序中使用 Task.Delay 是否存在任何已知问题:比如它是否不可靠,或者如果调用该方法的实例过多,它会崩溃吗?

\n

这是下面的代码,尽管我认为它\xe2\x80\x99s 并不重要:

\n
 private void shoot() {\n  //if "canShoot" spawn bullet\n  ShootCooledDown();\n}\n\nprivate async void ShootCooledDown() {\n  TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));\n  canShoot = false;\n  await Task.Delay(span);\n  canShoot = true;\n}  \n
Run Code Online (Sandbox Code Playgroud)\n

The*_*aot 3

我的问题是,在游戏应用程序中使用 Task.Delay 是否存在任何已知问题:比如它是否不可靠,或者如果调用该方法的实例过多,它会崩溃吗?

本身不是。游戏中并没有什么特别的问题Task.Delay,也没有太多的例子。

但是,您之后所做的事情Task.Delay可能会出现问题。如果执行await Task.Delay(span);,后面的代码可能会在不同的线程中运行,因此可能会导致竞争条件。这是因为await,不是因为Task.Delay

例如,如果await Task.Delay(span);您将添加一个Node到场景树(例如子弹),这将干扰使用场景树的任何其他线程。Godot 每一帧都会使用场景树。快速浏览一下线程安全 API,您会发现场景树不是线程安全的。顺便说一句,几乎任何小部件 API 都会发生同样的情况。

解决方案是使用call_deferredCallDeferred在 C# 中)与场景树进行交互。是的,这可能会抵消下一帧发生的那一刻。


我会给你一个非线程替代方案来做到这一点。

有方法get_ticks_msecget_ticks_usecGetTicksMsec类(以前的GetTicksUsec C# 中的and ) ,它们为您提供单调时间,您可以使用它来进行时间比较。TimeOS

因此,如果您按照应该拍摄的时间排列一个队列(通过当前时间加上您需要的任何间隔来计算)。然后在您的进程或物理进程回调中,您可以检查队列。将所有逾期的时间出队,并创建这些项目符号。

如果你不想用 Godot API 来解决这个问题,那么启动一个Stopwatch在游戏开始时启动 a ,并使用其经过的时间。


但也许这并不是您想要的机制。如果您想要良好的旧冷却时间,您可以Stopwatch在需要冷却时间时开始,然后将经过的时间与您想知道是否结束的冷却持续时间进行比较。