提交小游戏项目
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// 计算 Sprite 的非透明可见区域(基于 sprite.rect),
|
||||
/// 将其中心与 Image 矩形中心对齐,并把偏移应用到「父物体」的 anchoredPosition.y。
|
||||
/// 同时缓存上下左右边界,避免重复扫描,并提供 UI 尺寸下的边界/宽度。
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class ImageAlphaBounds : MonoBehaviour
|
||||
{
|
||||
[Range(0f, 1f)]
|
||||
public float alphaThreshold = 0.1f;
|
||||
|
||||
private Sprite cachedSprite;
|
||||
private int cachedTop;
|
||||
private int cachedBottom;
|
||||
private int cachedLeft;
|
||||
private int cachedRight;
|
||||
private bool cachedValid;
|
||||
|
||||
private void EnsureBounds(Image img)
|
||||
{
|
||||
Sprite sp = img.sprite;
|
||||
if (cachedValid && cachedSprite == sp) return;
|
||||
|
||||
cachedSprite = sp;
|
||||
cachedValid = false;
|
||||
|
||||
if (sp == null) return;
|
||||
|
||||
Texture2D tex = sp.texture;
|
||||
if (tex == null || !tex.isReadable)
|
||||
{
|
||||
Debug.LogWarning($"{name}: Texture not readable. Enable Read/Write in import settings.");
|
||||
return;
|
||||
}
|
||||
|
||||
Rect r = sp.rect;
|
||||
int sx = Mathf.RoundToInt(r.x);
|
||||
int sy = Mathf.RoundToInt(r.y);
|
||||
int sw = Mathf.RoundToInt(r.width);
|
||||
int sh = Mathf.RoundToInt(r.height);
|
||||
|
||||
Color[] pixels = tex.GetPixels(sx, sy, sw, sh);
|
||||
|
||||
int top = -1, bottom = -1, left = -1, right = -1;
|
||||
|
||||
for (int y = 0; y < sh; y++)
|
||||
{
|
||||
int rowStart = y * sw;
|
||||
for (int x = 0; x < sw; x++)
|
||||
{
|
||||
if (pixels[rowStart + x].a > alphaThreshold)
|
||||
{
|
||||
if (top == -1) top = y;
|
||||
bottom = y;
|
||||
|
||||
if (left == -1 || x < left) left = x;
|
||||
if (right == -1 || x > right) right = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (top == -1 || bottom == -1)
|
||||
{
|
||||
cachedTop = cachedBottom = cachedLeft = cachedRight = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedTop = top;
|
||||
cachedBottom = bottom;
|
||||
cachedLeft = left;
|
||||
cachedRight = right;
|
||||
}
|
||||
|
||||
cachedValid = true;
|
||||
}
|
||||
|
||||
public void AdjustY()
|
||||
{
|
||||
Image img = GetComponent<Image>();
|
||||
if (img == null || img.sprite == null) return;
|
||||
|
||||
EnsureBounds(img);
|
||||
|
||||
if (!cachedValid || cachedBottom < cachedTop) return;
|
||||
|
||||
RectTransform imgRT = img.rectTransform;
|
||||
float fullHeightUI = imgRT.sizeDelta.y;
|
||||
float spriteHeightPx = img.sprite.rect.height;
|
||||
float scaleY = fullHeightUI / spriteHeightPx;
|
||||
|
||||
float centerVisibleFromTopPx = (cachedTop + cachedBottom + 1) * 0.5f;
|
||||
float centerVisibleFromTopUI = centerVisibleFromTopPx * scaleY;
|
||||
float imageCenterFromTopUI = fullHeightUI * 0.5f;
|
||||
|
||||
float deltaY = centerVisibleFromTopUI - imageCenterFromTopUI;
|
||||
|
||||
RectTransform parentRT = img.transform.parent as RectTransform;
|
||||
if (parentRT != null)
|
||||
{
|
||||
Vector2 p = parentRT.anchoredPosition;
|
||||
float parentScaleY = parentRT.localScale.y;
|
||||
parentRT.anchoredPosition = new Vector2(p.x, -deltaY * parentScaleY);
|
||||
}
|
||||
}
|
||||
|
||||
public float GetOpaqueHeight()
|
||||
{
|
||||
if (!cachedValid || cachedBottom < cachedTop) return 0f;
|
||||
return cachedBottom - cachedTop + 1;
|
||||
}
|
||||
|
||||
public float GetOpaqueWidth()
|
||||
{
|
||||
if (!cachedValid || cachedRight < cachedLeft) return 0f;
|
||||
return cachedRight - cachedLeft + 1;
|
||||
}
|
||||
|
||||
public float GetOpaqueLeftUI()
|
||||
{
|
||||
Image img = GetComponent<Image>();
|
||||
if (img == null || !cachedValid || cachedRight < cachedLeft) return 0f;
|
||||
|
||||
RectTransform rt = img.rectTransform;
|
||||
float spriteWidthPx = img.sprite.rect.width;
|
||||
float scaleX = rt.sizeDelta.x / spriteWidthPx;
|
||||
return cachedLeft * scaleX;
|
||||
}
|
||||
|
||||
public float GetOpaqueRightUI()
|
||||
{
|
||||
Image img = GetComponent<Image>();
|
||||
if (img == null || !cachedValid || cachedRight < cachedLeft) return 0f;
|
||||
|
||||
RectTransform rt = img.rectTransform;
|
||||
float spriteWidthPx = img.sprite.rect.width;
|
||||
float scaleX = rt.sizeDelta.x / spriteWidthPx;
|
||||
return cachedRight * scaleX;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回不透明宽度的 UI 尺寸(换算自 sprite.rect 像素宽度)
|
||||
/// </summary>
|
||||
public float GetOpaqueWidthUI()
|
||||
{
|
||||
Image img = GetComponent<Image>();
|
||||
if (img == null || !cachedValid || cachedRight < cachedLeft) return 0f;
|
||||
|
||||
RectTransform rt = img.rectTransform;
|
||||
float spriteWidthPx = img.sprite.rect.width;
|
||||
float scaleX = rt.sizeDelta.x / spriteWidthPx;
|
||||
return (cachedRight - cachedLeft + 1) * scaleX;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user