我目前正在嘗試使用 Godot C# 制作一個基本的射擊游戲,而對于槍的射速,我一直在嘗試不同的延遲系統。盡管我試圖使腳本通用,但節點計時器仍然有效,并且計時器呼叫似乎只呼叫父腳本中的函式。
我現在正在查看 C# 的 Task.Delay 方法,它似乎也有效,因為它是一個異步操作,它看起來不受幀速率的影響或減慢游戲速度。
我的問題是,在游戲應用程式中使用 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;
}
uj5u.com熱心網友回復:
我對戈多沒有任何經驗......但我的想法是......
您可以將上次拍攝時間存盤在變數/欄位中,而不是使用計時器。如果您嘗試在 內射擊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;
}
由于 Theodor 的有效評論,關于更改系統時間會導致容易出錯的游戲玩法。
我寫了第二個版本。
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();
}
我認為這將是一個更好的解決方案。
uj5u.com熱心網友回復:
我不是 Godot 的專家,但我可以說這Task.Delay()被認為比替代方案更好Thread.Sleep(),例如因為異步我將執行緒釋放到執行緒池,當時間過去后它繼續執行,與阻塞執行緒的后一個選項形成對比反而。
我可以看到的問題是每個 Web 服務器都可以接受并發請求的最大限制,通過Task.Delay()在您的代碼中使用,您可以開始累積由于延遲而“等待”的請求。因此,如果您的應用程式開始接收大量請求,并且延遲時間很長,這可能是請求排隊(延遲)甚至被拒絕的問題。
如果延遲是幾秒(重要的時間),那么我可能會考慮將用戶存盤在快取中(您也可以存盤在一個字典中Dictionary<string, bool>,其中字串是 userId,但此解決方案不會向外擴展,這就是為什么我建議使用分布式快取),并檢查 ( TryGetValue()) 您的快取是否允許用戶拍攝。如果延遲是幾微秒(負擔得起的時間)仍然不是理想的解決方案,但它可能會成為一個問題。
uj5u.com熱心網友回復:
我的問題是,在游戲應用程式中使用 Task.Delay 是否存在任何已知問題:比如它是否不可靠,或者如果呼叫了太多的方法實體,它會崩潰嗎?
本身不是。Task.Delay游戲中沒有什么特別的錯誤,也沒有太多的例子。
但是,您之后所做的事情Task.Delay可能是個問題。如果您執行await Task.Delay(span);,后面的代碼可能會在不同的執行緒中運行,因此可能會導致競爭條件。這是因為await,不是因為Task.Delay。
例如,如果在await Task.Delay(span);您將添加Node到場景樹(例如子彈)之后,這將干擾使用場景樹的任何其他執行緒。Godot 將在每一幀中使用場景樹。快速查看執行緒安全 API會告訴您場景樹不是執行緒安全的。順便說一句,幾乎所有的小部件 API 都會發生同樣的情況。
解決方案是使用call_deferred(CallDeferred在 C# 中)與場景樹進行互動。而且,是的,這可以抵消它發生在下一幀的那一刻。
我會給你一個非執行緒的替代方案來做到這一點。
類上有方法get_ticks_msec和get_ticks_usec(GetTicksMsec和GetTicksUsec在 C# 中)OS,可以為您提供單調時間,您可以將其用于時間比較。
所以,如果你把它應該拍攝的時間排成一個佇列(通過獲取當前時間加上你需要的任何間隔來計算)。然后在您的流程或物理流程回呼中,您可以檢查佇列。出列所有過期的時間,并創建這些專案符號。
如果您不想使用 Godot API 解決此問題Stopwatch,請在游戲開始時啟動 a ,并使用其經過的時間。
但也許這不是你想要的機制。如果你想要一個好的舊冷卻,你可以Stopwatch在需要冷卻的時候開始,然后將經過的時間與你想知道是否結束的冷卻持續時間進行比較。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/360544.html
下一篇:將字典值分組到C#中的物件中
