Search code examples
c#androidunity-game-enginescreenshot

How to disable Gameobjects for Screenshot capturing in Unity on Android?


I have a simple goal for my Unity application running on Android: create a function, which disables my GUI, creates a screenshot, stores the image and enables the GUI again.

This is my current code:

The whole UI is stored in a GameObject which my handler class holds as property:

private bool makeScreenshotFlag;
public GameObject UserInterface;

makeScreenshotFlag above is used in the Update function:

// Update is called once per frame
void Update()
{
    if (makeScreenshotFlag)
    {
        // Working with this flag is necessary, 
        // since we need to wait for the next frame, 
        // where the gui is not visible;
        MakeScreenShot();
    }
}

If the corresponding button gets pressed I fire the following Method:

public void OnCreateScreenshotButtonPressed()
{
    UserInterface.SetActive(false);
    makeScreenshotFlag = true;
}

And at last the method for the screenshot itself:

private void MakeScreenShot()
{
    if (UserInterface.activeSelf) return; // wait for the next frame if the gui is still active

    try
    {
        string filename = "screenshot_" + DateTime.Now.ToString("HH-mm-ss--dd-MM-yyyy") + ".png";
        ScreenCapture.CaptureScreenshot(filename);
    }
    catch (Exception e)
    {
        DebugHelper.NewLog = "Error capturing screenshot: " + e.Message;
    }
    finally
    {
        makeScreenshotFlag = false;
        UserInterface.SetActive(true);
    }
}

In theory this should work, however the documentation for ScreenCapture.CaptureScreenshot() states the following:

The CaptureScreenshot returns immediately on Android. The screen capture continues in the background. The resulting screen shot is saved in the file system after a few seconds.

In practice this means, when my screenshot is made, the GUI is already enabled again. So far I couldn't find any event or similar to get notified as soon as the screenshot is made. The only thing I can think of is to store the screenshot filename and check if the file exists each frame after the screenshot is started.

Is there any other, more practical way?


Solution

  • Most probably, you are capturing the frame with UI itself. It's better to wait till the end of the frame using Coroutine.

    public IEnumerator MakeScreenShot()
    {
        // Wait till the last possible moment before screen rendering to hide the UI
        yield return null;
    
        // Disable UI       
        UserInterface.SetActive(false);
    
        // Wait for screen rendering to complete
        yield return new WaitForEndOfFrame();
    
        // Take screenshot
        Application.CaptureScreenshot("screenshot.png");
    
        // Show UI after we're done
        UserInterface.SetActive(true);
    }