Files
bansonic_beta_main/Assets/scripts/gTransBlack.cs
T
2026-07-22 05:35:53 +08:00

274 lines
6.8 KiB
C#

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<Canvas>(true);
}
if (b_CG == null)
{
b_CG = GetComponent<CanvasGroup>();
if (b_CG == null)
{
b_CG = GetComponentInChildren<CanvasGroup>(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<CanvasScaler>();
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<Camera>(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;
}
}