我正在開發一個在 Unity 中保存游戲狀態的系統。當前的結構如下所示:
public void SaveGame() {
StopAllCoroutines();
if (source != null)
{
source.Cancel();
}
StartCoroutine(DoSave());
}
protected IEnumerator DoSave(){
/// Code that prepares a bunch of stuff necessary to save the game goes here
foreach (item in itemsToSave)
{
// Code that adds 'item' to a data structure in memory that is accessible by later functions goes here //
yield return new WaitForSeconds(0.05f);
}
source = new CancellationTokenSource();
WriteFiles(source.Token);
}
private async Task WriteFiles(CancellationToken token)
{
Task task = Task.Run(() => GenerateSaveFiles(), token);
// (A canceled task will raise an exception when awaited).
await task;
}
private void GenerateSaveFiles()
{
/// Functions that actually write to disk go here
/// E.g. File.WriteAllText();
/// This function has access to the place in memory where 'items' were being added to in the DoSave() foreach loop, so it just dumps that memory storage to disk
}
我以這種方式設定它,以便我可以在單獨的執行緒中異步保存并跟蹤它的狀態(例如,它是否失敗,以及錯誤訊息)。
SaveGame()
然后每當發生不同事件(如撿起物品、殺死敵人等)時,圍繞我的代碼庫呼叫以實時保存游戲。這主要適用于我 99% 的用例,但在某些情況下,我想呼叫SavGame()
并等待它完成,然后再做任何其他事情。例如,如果玩家死了,我想將狀態寫入磁盤而不給其他任何事情(例如在不同場景中重生玩家)發生的機會。
我已經研究了一些東西,比如回呼(例如https://codesaying.com/action-callback-in-unity/),但我不確定如何為我的大部分SaveGame()
任務運行的用例正確設定它async 但其他時候能夠等待它完成,或者至少讓呼叫的方法SaveGame()
知道它何時完成。
uj5u.com熱心網友回復:
只需做一個任何人都可以訪問的簡單布爾屬性:
public bool IsSavingGame {
get; private set;
}
// ...
private IEnumerator SaveGameCoroutine(){
IsSavingGame = true;
// Your save functionality.
IsSavingGame = false;
}
例如,如果您想在保存時拒絕加載任何場景,您可以撰寫以下腳本:
// or you can singleton it
[SerializeField]
private SaveManager yourSaveManger
public void LoadScene(){
StartCoroutine(LoadSceneCoroutine());
}
private IEnumerator LoadSceneCoroutine(){
while (yourSaveManger.IsSavingGame){
// Show a loading or saving screen or something
yield return null;
}
SceneManager.LoadScene("Your Scene Name");
}
uj5u.com熱心網友回復:
好的,經過大量的閱讀和努力,我能夠讓它作業。由于我使用協程的設定以及嵌套在其中的任務和其他協程,有很多事情會妨礙我。
我的解決方案有兩個
- 對于
DoSave()
協waitForSaveComplete
程DoSave()
(因此,從我的問題中的示例中,我將所有的 yield 陳述句都包裝成這樣:
if (!waitForSaveComplete)
{
yield return new WaitForSeconds(0.05f);
}
我也有一些同步的嵌套協程,我以同樣的方式包裝了它們的 yield 陳述句。
接下來,我將嵌套協程的呼叫從:
yield return StartCoroutine(MySynchronizedCoroutine());
到:
if(!waitForSaveComplete) {
yield return StartCoroutine(MySynchronizedCoroutine(waitForSavComplete));
} else
{
// IMPORTANT: Make sure MySynchronizedCoroutine also uses
// waitForSaveComplete to wrap its own yield statements
// or else this won't work!!!
StartCoroutine(MySynchronizedCoroutine(waitForSavComplete));
}
像這樣包裝 yield 陳述句是可行的,因為這是 Coroutine 暫停并放棄控制權的地方,直到滿足相應的Wait
條件。在那之前,它一直處于“阻塞”狀態,鑒于我不確定為什么我花了這么長時間才想到這一點。
- 對于我
WaitUntil
在異步案例中使用的任務,以確保它在協程本身發生任何其他事情之前完成。在這種waitForSaveComplete
情況下,我什至根本沒有啟動任務,而是GenerateSaveFiles()
像這樣直接運行
if (waitForSaveComplete)
{
GenerateSaveFiles();
} else
{
Task writeTask = WriteFiles(source.Token);
yield return new WaitUntil(() => writeTask.IsCompleted);
}
再次,另一個'duh'時刻,只是不喜歡..在不需要的情況下開始一項任務。
這似乎可行,但也有點復雜,因為嵌套協同程式的位似乎是可怕的、難以跟蹤的錯誤的沃土。唉,我的異步編程經驗非常有限,所以我沒有更好的設計或實作想法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/477592.html
上一篇:通過單擊銷毀物件
下一篇:使用新輸入系統處理不同的函式呼叫