I'm trying to learn how async programming works in Unity, using the UniTask library.
Let's say we have this code:
private async UniTask LoadGameAsync()
{
//this should be the right way to await the scene loading
await LoadSceneAsync("Level_01");
Debug.Log("Level 01 finished loading.");
//does this work?
//I'm uncertain if this is correct because I await a non async method. But then again it returns a task ... No compiler error.
await LoadScene("Level_02");
Debug.Log("Level 02 finished loading.");
//why all this?
//because I want to load multiple scenes simultaneously and only when all are finished loading, hide a loading screen.
//Does this work the way I intend to or are there pitfalls to avoid? If so, what's the correct way of implementing something like this?
UniTask level03Task = LoadScene("Level_03");
UniTask level03UITask = LoadScene("Level_03_UI");
await UniTask.WhenAll(level03Task, level03UITask);
Debug.Log("Level 03 and its UI finished loading, hide loading screen now.");
}
private async UniTask LoadSceneAsync(string sceneName)
{
await SceneManager.LoadSceneAsync(sceneName).ToUniTask();
}
private UniTask LoadScene(string sceneName)
{
return SceneManager.LoadSceneAsync(sceneName).ToUniTask();
}
The comments in the code basically summarize my question. Is it possible to return a UniTask from a method and then await it? It somehow feels wrong because the method is basically the same as the async one but ... not async.
If this doesn't work as intended, what would be the correct way to implement what I imagine?
Note that UniTask in comparison to Task is a struct, not a class. Not sure if this makes a difference when creating the tasks for later use.
Thank you!
I'm uncertain if this is correct because I await a non async method. But then again it returns a task ... No compiler error.
You await no methods, but awaitable objects. So far you await no a method, but the object it returns. It could be Task
, UniTask
, or any other objects, that are compatible with await
keyword.
Under the hood async/await
is reconstructed to a state machine with no async/await
keywords, but only with calling methods of awaitable objects with some auxiliary objects for its creation or something. You can try to check it, and other syntax sugar in the SharpLab.
//why all this? //because I want to load multiple scenes simultaneously and only when all are finished loading, hide a loading screen. //Does this work the way I intend to or are there pitfalls to avoid? If so, what's the correct way of implementing something like this? UniTask level03Task = LoadScene("Level_03"); UniTask level03UITask = LoadScene("Level_03_UI"); await UniTask.WhenAll(level03Task, level03UITask); Debug.Log("Level 03 and its UI finished loading, hide loading screen now.");
Lets deal with this.
UniTask level03Task = LoadScene("Level_03");
UniTask level03UITask = LoadScene("Level_03_UI");
These two lines will be executed immediately. They start scenes loading process and creates a handles(UniTask
s), that can be used to work with this process.
await UniTask.WhenAll(level03Task, level03UITask);
This line uses two tasks to make the third one, that will be a handle for their both completion. And after this task is created, it is instantly await
ed. So the execution of the method will continue only after the awaited task is completed. And it will be completed after two scene loading tasks are completed.
So far, if you want, to display any loading UI, you have to show it before this line and hide after this line.
Note that UniTask in comparison to Task is a struct, not a class. Not sure if this makes a difference when creating the tasks for later use.
In general, UniTask
s and Task
s have much much deeper differences besides struct
and class
types. In most cases, you won't notice any differences between them, while you are working with Unity API. Maybe the thing, I can mention, is that UniTask
s, by default, are executed inside the Unity main loop, while Task
are executed, by default, in the separate thread, that could lead to problems with accessing some Unity API.