Home > Back-end >  How to use async-await in Unity3d?
How to use async-await in Unity3d?

Time:01-17

I want to use Async-await tasks in my Unity3d game for IO, Network and other operations. I know I can use IEnumerators and Coroutines, but those have a very limited functionality and fails to work while working with Web Service APIs using TcpClient, HttpClient and other async tasks in C#.

I cannot work with UI Components while in async Task. Suppose I get a string from a Web API, I cannot set Text field's text from async async task. How can it be done.

CodePudding user response:

There are many solutions to this problem.

Two very similar implementations are UnityMainThreadDispatcher and Microsoft's own UnityDispatcher

They implement running IEnumerators and Actions to be on the main thread respectively. Both rely on a MonoBehaviour pseudo singleton. This answer goes into a some more detail and shows an alternative implementation.

CodePudding user response:

Downvoters, I can only accept my answer after 2 days.

Searched all over the internet, but didn't find a proper way to achieve async-await in Unity. Some say to use external plugin, some say not possible. No proper answer. Hence, here is the proper way of doing it.

Like most application frameworks, Unity game runs on main UI thread. Hence changing UI elements from an async task doesn't work as we need to call Unity's API only from a Main thread like calling from Methods and IEnumerators. Methods and IEnumerators run on main UI thread.

Also Unity doesn't provide a method to call Main thread like .Net does in Xamarin.Forms (Device.BeginInvokeOnMainThread).

For that we need to use MVVM architecture. MVVM stands for Model-View-ViewModel. We don't need to import anything, just change the way our project works.

By default, Unity uses singleton approach and doesn't provide any application building framework. Hence MVVM would be better for making versatile games. Using MVVM, we can standardize our code by splitting UI Management, our Application's logic and Data, by splitting Models, Views and logic. MVVM is widely used in cross platform application development.

In MVVM we bind controls (UI Components) to the properties in ViewModel, and we only change properties in ViewModel. Then ViewModel notifies these property changes to the View and thus those changes are reflected in UI components in our scene.

Create a ViewModel Class

public class MainSceneViewModel : INotifyPropertyChanged
{
    public string Title { get { return title; } set { title = value; OnPropertyChanged(nameof(Title)); } }
    string title;

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

In your Scene Script (Attach to a Gameobject in Unity Inspector).

public class MainSceneScript : MonoBehaviour
{
    public Text SceneTitle; // Assign Text Component in Unity Inspector

    MainSceneViewModel mainSceneViewModel = new MainSceneViewModel();

    void Start()
    {
        mainSceneViewModel.PropertyChanged  = ViewModelPropertyChanged;
        DelayedTitleChange();
    }

    async void DelayedTitleChange()
    {
        await Task.Delay(2000);
        mainSceneViewModel.Title = "This is the Main Scene";
    }

    // Will be called whenever a property of `MainSceneViewModel` is updated.
    void ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(MainSceneViewModel.Title))
        {
            SceneTitle.text = mainSceneViewModel.Title;
        }
    }

    // Clean up
    void Dispose()
    {
        mainSceneViewModel.PropertyChanged -= ViewModelPropertyChanged;
    }
}

We can also use Model and notify property changed of that model.

  • Related