在制作游戏时,想在玩家保存游戏进度时,记录当前的游戏界面,这就需要用到截屏保存图片的功能


在截屏的时候,同时隐藏UI

方法一:临时禁用Canvas(最简单)

using UnityEngine;

public class ScreenshotWithoutUI : MonoBehaviour
{
    public Canvas[] canvasesToHide; // 需要隐藏的Canvas
    public KeyCode captureKey = KeyCode.Print;
    public string savePath = "Screenshots/";
    public string fileNamePrefix = "Screenshot_";

    void Update()
    {
        if (Input.GetKeyDown(captureKey))
        {
            StartCoroutine(CaptureAndSave());
        }
    }

    private IEnumerator CaptureAndSave()
    {
        // 隐藏所有Canvas
        foreach (var canvas in canvasesToHide)
        {
            canvas.enabled = false;
        }

        var folder = Application.persistentDataPath + "/" + savePath;
        // 创建保存目录(如果不存在)
        System.IO.Directory.CreateDirectory(folder);

        // 生成带时间戳的文件名
        var timestamp = System.DateTime.Now.ToString("yyyyMMdd_HHmmss");
        var filePath = $"{folder}{fileNamePrefix}{timestamp}.png";

        // 等待一帧确保UI已隐藏
        yield return null;

        // 截屏并保存
        ScreenCapture.CaptureScreenshot(filePath);

        // 恢复显示Canvas
        yield return new WaitForEndOfFrame();
        foreach (var canvas in canvasesToHide)
        {
            canvas.enabled = true;
        }

        Debug.Log($"截屏已保存至: {filePath}");
    }
}

方法二:使用RenderTexture(高性能)

这种方法通过相机单独渲染游戏内容,不包含UI层。

using UnityEngine;

public class RenderTextureScreenshot : MonoBehaviour
{
    public Camera mainCamera; // 主相机
    public Canvas uiCanvas;   // UI Canvas
    public KeyCode captureKey = KeyCode.Space;
    public string savePath = "Screenshots/";

    private RenderTexture renderTexture;

    void Start()
    {
        // 创建与屏幕尺寸匹配的RenderTexture
        renderTexture = new RenderTexture(Screen.width, Screen.height, 24);
        mainCamera.targetTexture = renderTexture;
    }

    void Update()
    {
        if (Input.GetKeyDown(captureKey))
        {
            CaptureScreenshot();
        }
    }

    void CaptureScreenshot()
    {
        // 临时禁用UI相机
        uiCanvas.worldCamera.enabled = false;

        // 渲染场景到RenderTexture
        mainCamera.Render();

        // 读取RenderTexture内容
        Texture2D screenShot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
        RenderTexture.active = renderTexture;
        screenShot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
        screenShot.Apply();

        // 恢复UI相机
        uiCanvas.worldCamera.enabled = true;

        // 保存图片
        byte[] bytes = screenShot.EncodeToPNG();
        System.IO.File.WriteAllBytes(savePath + "screenshot.png", bytes);

        // 清理资源
        Destroy(screenShot);
    }
}

方法三:分层渲染(推荐方案)

通过设置相机的Culling Mask,让主相机只渲染游戏内容,UI相机单独渲染UI。

步骤:

  1. 创建图层

    • 创建一个新图层(如"UI"),将所有UI元素移到该图层。
  2. 配置相机

    • 主相机:取消勾选"UI"图层。
    • UI相机:只勾选"UI"图层,并设置为"Screen Space - Camera"模式。
  3. 截图代码

using UnityEngine;

public class LayeredScreenshot : MonoBehaviour
{
    public Camera uiCamera; // UI相机
    public KeyCode captureKey = KeyCode.Space;

    void Update()
    {
        if (Input.GetKeyDown(captureKey))
        {
            StartCoroutine(Capture());
        }
    }

    System.Collections.IEnumerator Capture()
    {
        // 禁用UI相机
        uiCamera.enabled = false;

        // 等待一帧确保UI已隐藏
        yield return null;

        // 截屏
        ScreenCapture.CaptureScreenshot("screenshot.png");

        // 恢复UI相机
        yield return new WaitForEndOfFrame();
        uiCamera.enabled = true;
    }
}

使用建议

  • 性能对比:方法二(RenderTexture)和方法三(分层渲染)对性能影响较小,适合频繁截图的场景。
  • UI恢复:确保在截图完成后恢复UI显示,避免用户体验中断。
  • 动态UI:如果UI是动态生成的,建议通过代码动态获取所有Canvas组件。

扩展功能

1. 只隐藏部分UI

// 隐藏特定UI元素而非整个Canvas
public GameObject[] uiElementsToHide;

foreach (var element in uiElementsToHide)
{
    element.SetActive(false);
}

2. 截图时显示临时提示

public GameObject captureHint;

// 截图前显示提示
captureHint.SetActive(true);

// 截图后隐藏提示
captureHint.SetActive(false);