You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity拍立得相机功能BUG:所有拍立得均显示最新拍摄照片

问题分析与解决方案

问题根源

  1. 共享纹理资源:复用全局的screenCapture Texture2D,每次拍照都会覆盖该纹理内容,导致所有生成的拍立得指向同一份纹理数据,自然显示最新照片。
  2. 全局UI引用:ShowPhoto方法直接使用脚本内的全局photoDisplayArea和photoFrame,未关联当前捡起的拍立得的专属照片数据。
  3. 拍立得无独立数据存储:每个生成的拍立得没有专属组件存储对应照片Sprite,完全依赖PhotoCapture的全局变量。

解决方案

1. 创建拍立得专属组件

给每个拍立得预制体添加独立脚本,让它自行管理照片数据:

using UnityEngine;
using UnityEngine.UI;

public class PolaroidItem : MonoBehaviour
{
    // 拍立得预制体上的照片显示组件(地面缩略图用)
    [SerializeField] private Image polaroidImage;
    // 当前拍立得的专属照片Sprite
    private Sprite _ownPhoto;

    // 设置当前拍立得的照片
    public void SetPhoto(Sprite photo)
    {
        _ownPhoto = photo;
        if (polaroidImage != null)
        {
            polaroidImage.sprite = photo;
        }
    }

    // 获取当前拍立得的照片
    public Sprite GetPhoto()
    {
        return _ownPhoto;
    }
}

2. 修改PhotoCapture脚本

调整拍照、生成拍立得、查看照片的逻辑,确保每个拍立得拥有独立照片资源:

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class PhotoCapture : MonoBehaviour
{
    [Header("Photo Taker")]
    [SerializeField] public Image photoDisplayArea;
    [SerializeField] public GameObject photoFrame;

    [Header("Flash Effect")]    
    [SerializeField] private GameObject cameraFlash;
    [SerializeField] private float flashTime;

    public static bool viewingPhoto = false;

    [Header("GUI")]
    [SerializeField] private GameObject GUI;

    [Header("Polaroid GameObject")]
    [SerializeField] private GameObject itemPolaroid;

    [Header("Controls")]
    [SerializeField] private KeyCode closePicture = KeyCode.Mouse1;

    private RaycastHit hitObject;
    private bool itemObject = false;

    void Start()
    {
        // 移除全局screenCapture初始化,改为每次拍照创建新实例
    }

    void Update()
    {
        if(Input.GetKeyDown(PlayerActions.useCameraButton) && ItemCamera.canUseCamera && !viewingPhoto)
        {
            StartCoroutine(CapturePhoto());
        }

        itemObject = Physics.Raycast(transform.position, transform.forward, out hitObject, 6f);
        if(!viewingPhoto && Input.GetKeyDown(PlayerActions.actionButton) && itemObject && hitObject.collider.gameObject.CompareTag("Polaroid"))
        {
            ShowPhoto();
        }

        if(viewingPhoto && Input.GetKeyDown(closePicture))
        {
            RemovePhoto();
        }
    }

    private IEnumerator CameraFlashEffect()
    {
        cameraFlash.SetActive(true);
        yield return new WaitForSeconds(flashTime);
        cameraFlash.SetActive(false);
    }

    private IEnumerator CapturePhoto()
    {
        GUI.SetActive(false);
        yield return new WaitForEndOfFrame();

        // 每次拍照创建新的Texture2D,避免覆盖旧照片
        Texture2D captureTexture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
        Rect captureRegion = new Rect(0, 0, Screen.width, Screen.height);
        captureTexture.ReadPixels(captureRegion, 0, 0, false);
        captureTexture.Apply();

        Sprite photoSprite = Sprite.Create(captureTexture, new Rect(0, 0, captureTexture.width, captureTexture.height), new Vector2(0.5f, 0.5f), 100f);
        // 更新相机预览UI
        photoDisplayArea.sprite = photoSprite;

        StartCoroutine(CameraFlashEffect());
        GUI.SetActive(true);
        // 将生成的照片传给新拍立得
        SpawnItemPolaroid(photoSprite);
    }

    public void ShowPhoto()
    {
        viewingPhoto = true;
        GUI.SetActive(false);
        photoFrame.SetActive(true);

        // 获取当前捡起的拍立得的专属组件,加载它的照片
        PolaroidItem targetPolaroid = hitObject.collider.GetComponent<PolaroidItem>();
        if(targetPolaroid != null)
        {
            photoDisplayArea.sprite = targetPolaroid.GetPhoto();
        }
    }

    private void RemovePhoto()
    {
        viewingPhoto = false;
        photoFrame.SetActive(false);
        GUI.SetActive(true);
    }

    private void SpawnItemPolaroid(Sprite photoSprite)
    {
        Vector3 spawnPos = new Vector3(
            Random.Range(FirstPersonController.characterController.transform.position.x - 0.5f, FirstPersonController.characterController.transform.position.x + 0.5f),
            Random.Range(FirstPersonController.characterController.transform.position.y + 0.5f, FirstPersonController.characterController.transform.position.y + 1.5f),
            Random.Range(FirstPersonController.characterController.transform.position.z - 0.5f, FirstPersonController.characterController.transform.position.z + 0.5f)
        );

        GameObject newPolaroid = Instantiate(itemPolaroid, spawnPos, Quaternion.identity);
        // 给新拍立得设置专属照片
        PolaroidItem polaroidItem = newPolaroid.GetComponent<PolaroidItem>();
        if(polaroidItem != null)
        {
            polaroidItem.SetPhoto(photoSprite);
        }
    }
}

3. 预制体设置

  • 打开itemPolaroid预制体,添加PolaroidItem脚本。
  • 如果预制体上有用于显示照片的Image组件(比如地面上的拍立得缩略图),将其拖到PolaroidItem的polaroidImage字段中。
  • 确保预制体的Tag设置为Polaroid。

内容的提问来源于stack exchange,提问作者Keno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 12:12:04