using UnityEngine; using Unity.Cinemachine; using UnityEngine.UI; public class CameraInfoUI : MonoBehaviour { [Header("UI References")] [SerializeField] private GameObject uiPanel; [SerializeField] private Text cameraNameText; [SerializeField] private Text fovValueText; [SerializeField] private Text fovSpeedText; [SerializeField] private Text velocityText; [SerializeField] private Text dofValueText; [SerializeField] private Text dofSpeedText; [SerializeField] private Text dofVelocityText; [SerializeField] private GameObject flashPanel; [Header("UI Settings")] [SerializeField] private float updateInterval = 0.1f; // UI 업데이트 간격 [SerializeField] private float flashDuration = 0.2f; private CameraManager cameraManager; private CameraControlSystem cameraControlSystem; private float lastUpdateTime; private bool isUIVisible = true; private Coroutine flashCoroutine; private void Awake() { CreateUI(); } private void Start() { cameraManager = FindObjectOfType(); cameraControlSystem = FindObjectOfType(); if (cameraManager != null) { cameraManager.OnCameraChanged += OnCameraChanged; } } private void OnDestroy() { if (cameraManager != null) { cameraManager.OnCameraChanged -= OnCameraChanged; } } private void Update() { if (isUIVisible && Time.time - lastUpdateTime > updateInterval) { UpdateUI(); lastUpdateTime = Time.time; } } private void CreateUI() { // 캔버스 생성 GameObject canvasGO = new GameObject("CameraInfoCanvas"); Canvas canvas = canvasGO.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = 1000; // 최상위 렌더링 CanvasScaler scaler = canvasGO.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920, 1080); canvasGO.AddComponent(); // UI 패널 생성 (우측 상단) uiPanel = new GameObject("CameraInfoPanel"); uiPanel.transform.SetParent(canvasGO.transform, false); Image panelImage = uiPanel.AddComponent(); panelImage.color = new Color(0, 0, 0, 0.7f); // 반투명 검은색 RectTransform panelRect = uiPanel.GetComponent(); panelRect.anchorMin = new Vector2(1, 1); panelRect.anchorMax = new Vector2(1, 1); panelRect.pivot = new Vector2(1, 1); panelRect.anchoredPosition = new Vector2(-20, -20); panelRect.sizeDelta = new Vector2(350, 200); // 텍스트들 생성 CreateInfoText("Camera Name: ", out cameraNameText, 0); CreateInfoText("FOV: ", out fovValueText, 1); CreateInfoText("FOV Force: ", out fovSpeedText, 2); CreateInfoText("FOV Velocity: ", out velocityText, 3); CreateInfoText("DOF Distance: ", out dofValueText, 4); CreateInfoText("DOF Force: ", out dofSpeedText, 5); CreateInfoText("DOF Velocity: ", out dofVelocityText, 6); // 플래시 패널 생성 flashPanel = new GameObject("FlashPanel"); flashPanel.transform.SetParent(canvasGO.transform, false); Image flashImage = flashPanel.AddComponent(); flashImage.color = new Color(1, 1, 1, 0); // 투명한 흰색 RectTransform flashRect = flashPanel.GetComponent(); flashRect.anchorMin = Vector2.zero; flashRect.anchorMax = Vector2.one; flashRect.sizeDelta = Vector2.zero; flashRect.anchoredPosition = Vector2.zero; flashPanel.SetActive(false); } private void CreateInfoText(string label, out Text textComponent, int index) { GameObject textGO = new GameObject($"InfoText_{index}"); textGO.transform.SetParent(uiPanel.transform, false); textComponent = textGO.AddComponent(); textComponent.text = label + "Loading..."; textComponent.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); textComponent.fontSize = 14; textComponent.color = Color.white; RectTransform textRect = textGO.GetComponent(); textRect.anchorMin = new Vector2(0, 1); textRect.anchorMax = new Vector2(1, 1); textRect.pivot = new Vector2(0, 1); textRect.anchoredPosition = new Vector2(10, -10 - (index * 25)); textRect.sizeDelta = new Vector2(-20, 20); } private void UpdateUI() { if (cameraManager?.CurrentPreset?.virtualCamera != null) { var currentCamera = cameraManager.CurrentPreset.virtualCamera; cameraNameText.text = $"Camera: {currentCamera.name}"; fovValueText.text = $"FOV: {currentCamera.Lens.FieldOfView:F1}°"; } else { cameraNameText.text = "Camera: None"; fovValueText.text = "FOV: --°"; } if (cameraControlSystem != null) { fovSpeedText.text = $"FOV Force: {cameraControlSystem.GetCurrentForce():F0} ({cameraControlSystem.GetCurrentForceIndex() + 1}/3)"; velocityText.text = $"FOV Velocity: {cameraControlSystem.GetCurrentVelocity():F1}"; dofValueText.text = $"DOF Distance: {cameraControlSystem.GetCurrentDOF():F1}"; dofSpeedText.text = $"DOF Force: {cameraControlSystem.GetCurrentDofForce():F1} ({cameraControlSystem.GetCurrentDofForceIndex() + 1}/3)"; dofVelocityText.text = $"DOF Velocity: {cameraControlSystem.GetCurrentDofVelocity():F2}"; } else { fovSpeedText.text = "FOV Force: --"; velocityText.text = "FOV Velocity: --"; dofValueText.text = "DOF Distance: --"; dofSpeedText.text = "DOF Force: --"; dofVelocityText.text = "DOF Velocity: --"; } } private void OnCameraChanged(CameraManager.CameraPreset oldPreset, CameraManager.CameraPreset newPreset) { UpdateUI(); } public void ToggleUI() { isUIVisible = !isUIVisible; uiPanel.SetActive(isUIVisible); Debug.Log($"[CameraInfoUI] UI {(isUIVisible ? "표시" : "숨김")}"); } public void TriggerScreenshotFlash() { if (flashCoroutine != null) { StopCoroutine(flashCoroutine); } flashCoroutine = StartCoroutine(FlashEffect()); } private System.Collections.IEnumerator FlashEffect() { flashPanel.SetActive(true); Image flashImage = flashPanel.GetComponent(); // 페이드 인 float elapsed = 0f; float fadeTime = flashDuration * 0.3f; while (elapsed < fadeTime) { elapsed += Time.deltaTime; float alpha = Mathf.Lerp(0f, 0.8f, elapsed / fadeTime); flashImage.color = new Color(1, 1, 1, alpha); yield return null; } // 페이드 아웃 elapsed = 0f; float fadeOutTime = flashDuration * 0.7f; while (elapsed < fadeOutTime) { elapsed += Time.deltaTime; float alpha = Mathf.Lerp(0.8f, 0f, elapsed / fadeOutTime); flashImage.color = new Color(1, 1, 1, alpha); yield return null; } flashImage.color = new Color(1, 1, 1, 0); flashPanel.SetActive(false); flashCoroutine = null; } public bool IsUIVisible => isUIVisible; }