好多新内容

This commit is contained in:
FloatGaming
2026-07-22 05:35:53 +08:00
parent b5d1cdcbc5
commit 15649d02f8
128 changed files with 5956 additions and 673 deletions
+100
View File
@@ -0,0 +1,100 @@
using UnityEngine;
/// <summary>
/// 全屏背景/遮罩自适应(Cover):保持原始宽高比,等比放大到覆盖整个根 Canvas,超出部分裁切。
/// 过覆盖 => 任意宽高比都无缝铺满、且 sizeDelta 永不为 0;对纯色遮罩与艺术背景都正确、不失真。
/// 仅调整 sizeDelta(表现层),不改锚点/位置/pivot,不影响居中布局与位移动画。
/// 16:9 屏下结果等于设计尺寸,与原始逐像素一致。由 UIResolutionAutoFitter 自动附加。
/// </summary>
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class UIBackgroundCover : MonoBehaviour
{
public float sourceAspect = 16f / 9f;
private RectTransform rt;
private RectTransform coverTarget;
private float lastW = -1f, lastH = -1f;
private bool aspectResolved;
// 重入锁:设置 sizeDelta 会同步触发 OnRectTransformDimensionsChange
// 若不拦截会无限递归导致 StackOverflow 崩溃。
private bool _isFitting;
private void OnEnable()
{
rt = GetComponent<RectTransform>();
ResolveAspectFromInitialSize();
ResolveTarget();
Fit(true);
}
private void LateUpdate()
{
// 每帧检测 coverTarget 实际尺寸变化(而非只看 Screen):Unity 布局延迟更新,
// Screen 变化后 CanvasScaler 可能过几帧才把新尺寸写入 rootCanvas.rect。
// Fit(false) 内部按 lastW/lastH 判重,尺寸未变时零开销,无需额外节流。
if (coverTarget == null) ResolveTarget();
if (coverTarget != null)
{
float pw = coverTarget.rect.width;
float ph = coverTarget.rect.height;
if (!Mathf.Approximately(pw, lastW) || !Mathf.Approximately(ph, lastH))
{
Fit(false);
}
}
}
/// <summary>用元素初始 sizeDelta 推断原始宽高比,避免写死。</summary>
private void ResolveAspectFromInitialSize()
{
if (aspectResolved) return;
if (rt == null) rt = GetComponent<RectTransform>();
Vector2 s = rt.sizeDelta;
if (s.x > 1f && s.y > 1f) sourceAspect = s.x / s.y;
aspectResolved = true;
}
private void OnRectTransformDimensionsChange()
{
if (_isFitting) return; // 拦截自身写入触发的递归回调
Fit(false);
}
private void ResolveTarget()
{
Canvas canvas = GetComponentInParent<Canvas>();
if (canvas != null)
{
Canvas root = canvas.rootCanvas != null ? canvas.rootCanvas : canvas;
coverTarget = root.GetComponent<RectTransform>();
}
}
private void Fit(bool force)
{
if (_isFitting) return;
if (rt == null) rt = GetComponent<RectTransform>();
if (coverTarget == null) ResolveTarget();
if (coverTarget == null || sourceAspect <= 0f) return;
float pw = coverTarget.rect.width;
float ph = coverTarget.rect.height;
if (pw <= 0f || ph <= 0f) return;
if (!force && Mathf.Approximately(pw, lastW) && Mathf.Approximately(ph, lastH)) return;
lastW = pw; lastH = ph;
float targetAspect = pw / ph;
float w, h;
if (targetAspect > sourceAspect) { w = pw; h = pw / sourceAspect; }
else { h = ph; w = ph * sourceAspect; }
Vector2 newSize = new Vector2(w, h);
if (rt.sizeDelta != newSize)
{
_isFitting = true;
rt.sizeDelta = newSize;
_isFitting = false;
}
}
}