using System.Collections; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; public class gTransBlack : MonoBehaviour { [SerializeField] private Canvas b_Canvas; [SerializeField] private CanvasGroup b_CG; [SerializeField] private Text nowLoadingText; [SerializeField] private int postSceneLoadCameraRefreshFrames = 12; public Canvas Canvas => b_Canvas; public CanvasGroup CanvasGroup => b_CG; private Camera boundCamera; private Coroutine cameraRefreshRoutine; private int lastScreenWidth; private int lastScreenHeight; private void Awake() { EnsureReferences(); ConfigureCanvasForLetterbox(); ApplySceneCamera(true); } private void OnEnable() { SceneManager.sceneLoaded -= HandleSceneLoaded; SceneManager.sceneLoaded += HandleSceneLoaded; SceneManager.activeSceneChanged -= HandleActiveSceneChanged; SceneManager.activeSceneChanged += HandleActiveSceneChanged; ConfigureCanvasForLetterbox(); StartCameraRefreshRoutine(); } private void OnDisable() { SceneManager.sceneLoaded -= HandleSceneLoaded; SceneManager.activeSceneChanged -= HandleActiveSceneChanged; if (cameraRefreshRoutine != null) { StopCoroutine(cameraRefreshRoutine); cameraRefreshRoutine = null; } } private void Update() { if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight || NeedsCameraRefresh()) { ConfigureCanvasForLetterbox(); ApplySceneCamera(false); } } private void HandleSceneLoaded(Scene scene, LoadSceneMode mode) { StartCameraRefreshRoutine(); } private void HandleActiveSceneChanged(Scene oldScene, Scene newScene) { StartCameraRefreshRoutine(); } public void RefreshCanvasCamera() { ConfigureCanvasForLetterbox(); ApplySceneCamera(true); StartCameraRefreshRoutine(); } public void SetNowLoadingText(string text) { if (nowLoadingText != null) { nowLoadingText.text = text; } } private void EnsureReferences() { if (b_Canvas == null) { b_Canvas = GetComponentInChildren(true); } if (b_CG == null) { b_CG = GetComponent(); if (b_CG == null) { b_CG = GetComponentInChildren(true); } } } private void ConfigureCanvasForLetterbox() { EnsureReferences(); if (b_Canvas == null) { return; } if (b_Canvas.renderMode != RenderMode.ScreenSpaceCamera) { b_Canvas.renderMode = RenderMode.ScreenSpaceCamera; } if (b_Canvas.transform.localScale == Vector3.zero) { b_Canvas.transform.localScale = Vector3.one; } if (b_Canvas.planeDistance <= 0f) { b_Canvas.planeDistance = 100f; } b_Canvas.sortingOrder = short.MaxValue; CanvasScaler scaler = b_Canvas.GetComponent(); if (scaler != null) { scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920f, 1080f); scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; // 锁高度缩放:分辨率跟随屏幕后,非 16:9 屏也能保证各 UI 层一致缩放、不错位。 scaler.matchWidthOrHeight = 1f; } } private bool ApplySceneCamera(bool force) { EnsureReferences(); if (b_Canvas == null) { return false; } ConfigureCanvasForLetterbox(); Camera targetCamera = ResolveFirstSceneCamera(); if (targetCamera == null) { return false; } if (force || b_Canvas.worldCamera != targetCamera || boundCamera != targetCamera) { b_Canvas.worldCamera = targetCamera; boundCamera = targetCamera; } lastScreenWidth = Screen.width; lastScreenHeight = Screen.height; Canvas.ForceUpdateCanvases(); return true; } private bool NeedsCameraRefresh() { if (b_Canvas == null) { return true; } if (boundCamera == null || !boundCamera.isActiveAndEnabled) { return true; } if (b_Canvas.renderMode != RenderMode.ScreenSpaceCamera) { return true; } return b_Canvas.worldCamera != boundCamera; } private void StartCameraRefreshRoutine() { if (!isActiveAndEnabled) { return; } if (cameraRefreshRoutine != null) { StopCoroutine(cameraRefreshRoutine); } cameraRefreshRoutine = StartCoroutine(RefreshCameraForSeveralFrames()); } private IEnumerator RefreshCameraForSeveralFrames() { int frames = Mathf.Max(1, postSceneLoadCameraRefreshFrames); for (int i = 0; i < frames; i++) { ApplySceneCamera(true); yield return null; } yield return new WaitForEndOfFrame(); ApplySceneCamera(true); cameraRefreshRoutine = null; } private static Camera ResolveFirstSceneCamera() { Scene activeScene = SceneManager.GetActiveScene(); Camera mainCam = Camera.main; if (IsUsableSceneCamera(mainCam, activeScene, true)) { return mainCam; } Camera[] cameras = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); for (int i = 0; i < cameras.Length; i++) { Camera camera = cameras[i]; if (IsUsableSceneCamera(camera, activeScene, true)) { return camera; } } if (IsUsableSceneCamera(mainCam, activeScene, false)) { return mainCam; } for (int i = 0; i < cameras.Length; i++) { Camera camera = cameras[i]; if (IsUsableSceneCamera(camera, activeScene, false)) { return camera; } } return null; } private static bool IsUsableSceneCamera(Camera camera, Scene preferredScene, bool requirePreferredScene) { if (camera == null || !camera.isActiveAndEnabled) { return false; } Scene cameraScene = camera.gameObject.scene; if (!cameraScene.IsValid() || !cameraScene.isLoaded) { return false; } if (requirePreferredScene && cameraScene != preferredScene) { return false; } return true; } }