我目前正在用Godot C#做一个基本的射手,为了提高枪的射速,我一直在用不同的延迟系统做实验。虽然我试图使脚本通用化,但是节点计时器仍然工作,计时器调用似乎只调用父脚本中的函数。
我现在正在看C#的任务。延迟方法似乎也有效,因为它是一个异步动作,看起来不会受到帧速率的影响,也不会降低游戏速度。
我的问题是,在游戏应用程序中使用 Task.Delay 是否存在任何已知问题:例如它是否不可靠,或者如果调用该方法的太多实例,它会崩溃吗?
这是下面的代码,尽管我认为这并不重要:
private void shoot() {
//if "canShoot" spawn bullet
ShootCooledDown();
}
private async void ShootCooledDown() {
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
canShoot = false;
await Task.Delay(span);
canShoot = true;
}
在Godot或任何其他游戏引擎中开发游戏时,不应使用基于计算机时钟的任何计时器,如秒表
或Task.delay
。相反,您必须使用前一帧的增量时间来管理自己所用的时间,该时间在_Process(float delta)
或_PhysicsProcess(float delta)
方法中接收。原因是:
这就是Godot为您提供Timer 组件的主要原因,您必须将其附加到当前场景才能使用它。如果你不想向场景添加任何东西,这是完全合理的,你必须获取增量,将经过的时间存储在一个变量中,并检查这个变量是否达到某个限制。
在我的游戏中,我在这个非常简单的类中使用我自己的计时器:
public class Timer {
public float Elapsed { get; private set; } = 0;
public bool Stopped { get; private set; } = true;
public float Alarm { get; private set; } = float.MaxValue;
public Timer Start() {
Stopped = false;
return this;
}
public Timer Stop() {
Stopped = true;
return this;
}
public Timer Reset() {
Elapsed = 0;
return this;
}
public Timer ClearAlarm() {
Alarm = float.MaxValue;
return this;
}
public Timer SetAlarm(float finish) {
Alarm = finish;
return this;
}
public bool IsAlarm() => Elapsed > Alarm;
public Timer Update(float delta) {
if (!Stopped) {
Elapsed += delta;
}
return this;
}
}
```
You have to Update the timer in every frame
我的问题是,在游戏应用程序中使用 Task.Delay 是否存在任何已知问题:例如它是否不可靠,或者如果调用该方法的太多实例,它会崩溃吗?
本质上不是。< code >任务没有什么特别的问题。延迟在游戏中,也没有太多的实例。
然而,在<代码>任务之后你在做什么。延迟可能是一个问题。如果执行< code>await任务。延迟(跨度);,后面的代码可能会在不同的线程中运行,因此可能会导致争用情况。这是因为< code>await,而不是因为< code>Task。延迟。
例如,如果在等待 Task.Delay(span)
之后,您将向场景树添加一个节点
(例如项目符号),这将干扰使用场景树的任何其他线程。戈多将在每一帧都使用场景树。快速浏览线程安全 API 会告诉您场景树不是线程安全的。顺便说一下,几乎任何小部件API都会发生同样的情况。
解决方案是使用 call_deferred
(C# 中的 CallDeferred
)与场景树进行交互。而且,是的,这可能会抵消下一帧发生的那一刻。
我会给你一个非线程的选择来做到这一点。
操作系统
类上有方法get_ticks_msec
和get_ticks_usec
(C#中的GetTicksMsec和GetTicksUsec
),它们为您提供了可用于时间比较的单调时间。
所以,如果你用它应该射击的时间来创建一个队列(通过获取当前时间加上你需要的任何间隔来计算)。然后在你的进程或物理进程回调中,你可以检查队列。退出所有逾期的时间,并创建这些项目符号。
如果您不想使用Godo API解决此问题,请在游戏开始时启动Stopwatch
,并使用其经过的时间。
但也许这不是你想要的机制。如果你想要一个好的旧冷却,你可以在需要冷却时启动Stopwatch
,然后将经过的时间与你想知道是否结束的冷却持续时间进行比较。
我对戈多没有任何经验..但是我的想法是....
您可以将上次拍摄时间存储在变量/字段中,而不是使用计时器。如果您尝试在 lastTimeShot coolDown
内拍摄,只需忽略拍摄命令即可。
例如:
private DateTime _lastShot = DateTime.MinValue;
private void shoot()
{
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
// if the time when the last shot has fire with the cooldown time
// is greater than the current time. You are still in the cooldown time.
if(_lastShot.Add(span) > DateTime.UtcNow)
return; // within cooldown, do nothing
//if "canShoot" spawn bullet
ShootCooledDown();
_lastShot = DateTime.UtcNow;
}
由于西奥多的一个有效评论,关于更改系统时间将导致容易出错的游戏。
我写了第二个版本。
private Stopwatch _shootingCooldownStopwatch = default;
private void shoot()
{
var shotDelayMs = shotDelay * 1000;
// if the _shootingCooldownStopwatch is ever started
// and the ElapsedMilliseconds are in the showDelay
// we're not allowed to fire again. So exit the method.
if (_shootingCooldownStopwatch?.ElapsedMilliseconds < shotDelayMs)
return;
_shootingCooldownStopwatch = Stopwatch.StartNew();
//if "canShoot" spawn bullet
ShootCooledDown();
}
我认为这将是一个更好的解决方案。
我有cxfweb服务,我使用异步方法调用。我使用回调方法(使用javax.xml.ws.asynchHandler-http://cxf.apache.org/docs/developing-a-consumer.html)以获得如下响应: 这个方法很好,我得到了正确的响应。 我的问题是性能。我测量了刚好在上面行所需的时间,我的应用程序显示大约2000ms的上线(我用jmeter做了测试)。我的应
我偶然发现了下面这段代码: 我理解
Godot是一个全新开发的游戏引擎,其功能集类似知名的跨平台游戏引擎Unity,可用于开发PC、主机、移动和Web游戏。开发者声称引 擎的2D和动画支持要强于Unity,表示在功能和特性上没有其它开源游戏引擎能相媲美。Godot引擎内置了类似Unity的编辑器,GUI工具 包,2D/3D物理支持,支持OpenGL ES 2.0 功能集的3D渲染器,易于学习的语言和API,支持用ASM.js或Goo
我有下面的科特林协程代码。< code>doWorkAsync是正常(非挂起)函数,它返回< code>Deferred 我不知道如何在< code>doWorkAsync函数中使用< code>delay。 我正在使用kotlin协程版本。
问题内容: 我有2个异步运行的函数。我想使用瀑布模型来编写它们。问题是,我不知道如何。 这是我的代码: 知道如何使用Waterfall编写它,以便我可以控制它吗?请给我写一些例子,因为我是node.js的新手 问题答案: 首先确定步骤并将其编写为异步函数(带有回调参数) 读取文件 } 处理文件(在示例中,我删除了大部分console.log) } 请注意,我在这里没有进行特定的错误处理,我将利用a
我想进行一个基于当前状态的API调用,但不能使setState函数作为异步函数工作。 给我错误: 类型为“”的参数(状态:只读)= 如果我在setState方法之外获取数据,它会起作用,但我害怕对过时的页码进行API调用: