0

I keep seeing people posting loading scenes where the progress bar works. I've got an animated character while the scene loads, and it all just freezes. Like people have said it's not perfectly async. The debug goes from 0 to 0.9 and you can see the delay in the timestamp. So, I thought maybe if I animated using code rather than the animator and ran that code on a new thread it might keep animating but alas that didn't work. unity gave an error saying I couldn't use threading that way I think it has something to do with accessing the image sprite. This is the error

UnityException: get_rect can only be called from the main thread. Constructors and field initializers will be executed from the loading thread when loading a scene. Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

EDIT Question: Is there any way of updating a sprite in another thread or is the other thread only good for calculations and cant update the scene at all. (only time I've used multithreading was to calculate pathfinding but it sent the calculated path back to the main thread to be executed)

private void Start()
    {
        animating = true;
        backGroundThread = new Thread(AnimateIt);
        backGroundThread.Start();
        StartCoroutine(LoadScene());     
    }

    private void OnDestroy()
    {
        animating = false;
    }
IEnumerator LoadScene()
    {
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(gotoScene.ToString(), LoadSceneMode.Single);
        asyncLoad.allowSceneActivation = false;
        while (!asyncLoad.isDone)
        {
            Debug.Log(asyncLoad.progress);
            if (asyncLoad.progress >= 0.9f)
            {                
                yield return new WaitForSeconds(0.5f);                
                asyncLoad.allowSceneActivation = true;
            }
            yield return null;
        }
        yield return null;
        Debug.Log("Out Of Loops");
        Destroy(gameObject);
    }
public void AnimateIt()
    {
        int currentFrame = 0;
        while (animating)
        {
            int frame = (int)(currentFrame % frameList.Count);
            frameSprite.sprite = frameList[frame];
            currentFrame++;
            Thread.Sleep((int)((frameRate / 60)*1000));
        }
    }

EDIT------ The original is super simple. Its just a load and the animation is just done on an animator. You can see in the video that the animation on the animator freezes. You can see that the while loop doesnt seem to loop properly. It goes from 0 - 0.9 after 7 seconds without doing any sort of loop to show the progress

Here are the video and the code Youtube video

public void SetUp(LOCATIONS _gotoScene)
{
    gotoScene = _gotoScene;
    DontDestroyOnLoad(gameObject);
}
void FadeOnfinished()
    {
        StartCoroutine(LoadScene());
    }
    IEnumerator LoadScene()
    {
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(gotoScene.ToString(), LoadSceneMode.Single);
        asyncLoad.allowSceneActivation = false;
        Debug.Log("Going to Load");
        while (!asyncLoad.isDone)
        {
            Debug.Log("Loading: "+ asyncLoad.progress * 100 + "%");
            if (asyncLoad.progress >= 0.9f)
            {
                yield return new WaitForSeconds(0.5f); 
                asyncLoad.allowSceneActivation = true;  
            }
            yield return null;
        }
        yield return null;
        Debug.Log("Loaded");
        animator.SetTrigger("Off");
    }
11
  • 3
    As the error says, calls like that can only be made from the main thread. There isn't a way around that. Commented Jul 8 at 15:09
  • 2
    EDIT Question: Is there any way of updating a sprite in another thread or is the other thread only good for calculations and cant update the scene at all most of Unity API in particular anything accessing or setting things in the native c++ Engine (basically anything that affects the scene directly) can only be done on the main thread. There are certain exceptions like the Mesh API, Compute Shaders, and certain Image/Texture API .. but unless there is a specific explicit async support from Unity most of the time the answer is no, it needs to be the main thread Commented Jul 8 at 16:04
  • 1
    @MikETheElf I don't know all the details and decision making .. but maintaining the underlying c++ engine in sync with the c# API must be a pain in the ass already .. in addition to that rendering isn't that straight forward either and you have to also ensure that the CPU is in sync with the GPU .. there is probably many factors why Unity started the way it is .. I too hope that at some point they properly support .NET and full async coding but for now it is what it is Commented Jul 8 at 16:29
  • 3
    @MikeTheElf I think it would be better if you showed us your actual original approach that wasn't behaving as expected .. currently you basically tried to workaround it using a thread which doesn't work that way ... (see XY Problem) Commented Jul 10 at 7:15
  • 2
    So your code (the bottom one) looks basically fine to me. Have in mind that the async loading only means that assets etc are loaded asynchronously but when it comes to actually instantiate all the objects into the scene and run all their respective Awake and Start methods also initialize all the physics and colliders etc .. this all happens in the main thread .. you should profile where the freeze comes from and once you figured out what actually causes the freeze you could workaround it (e.g. enable objects one by one in a Coroutine or similar while staying on the loading screen) Commented Jul 22 at 7:23

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.