121 lines
3.5 KiB
C#
121 lines
3.5 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.Events;
|
||
using System.Collections.Generic;
|
||
using UnityEngine.EventSystems;
|
||
/// <summary>
|
||
/// 用于在Ui中切割Renderer的组件,类似RectMask2d;
|
||
/// 暂时未处理Mask嵌套的情况
|
||
/// </summary>
|
||
[DisallowMultipleComponent]
|
||
[RequireComponent(typeof(RectTransform))]
|
||
public class UICameraMask : UIBehaviour, IClipper
|
||
{
|
||
private RectTransform rectTransform;
|
||
private bool m_ShouldRecalculateClipRects;
|
||
private List<UICameraMaskable> maskableList;
|
||
private Vector4 clipArea;
|
||
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
rectTransform = (RectTransform)transform;
|
||
maskableList = new List<UICameraMaskable>();
|
||
}
|
||
protected override void OnEnable()
|
||
{
|
||
base.OnEnable();
|
||
m_ShouldRecalculateClipRects = true;
|
||
ClipperRegistry.Register(this);
|
||
}
|
||
protected override void OnDisable()
|
||
{
|
||
base.OnDisable();
|
||
maskableList.Clear();
|
||
ClipperRegistry.Unregister(this);
|
||
}
|
||
// 暂时使用低端的transform.hasChanged Api来追踪Transform状态变化。
|
||
// 用ClipperRegistry获得Clipping流程时间点。
|
||
public virtual void PerformClipping()
|
||
{
|
||
if (IsTransformDirty(rectTransform))
|
||
m_ShouldRecalculateClipRects = true;
|
||
if (m_ShouldRecalculateClipRects)
|
||
{
|
||
m_ShouldRecalculateClipRects = false;
|
||
ResetClipArea();
|
||
}
|
||
}
|
||
|
||
public void AddClippable(UICameraMaskable clippable)
|
||
{
|
||
if (clippable == null)
|
||
return;
|
||
if (!maskableList.Contains(clippable))
|
||
maskableList.Add(clippable);
|
||
SetClipForOne(clippable);
|
||
}
|
||
|
||
public void RemoveClippable(UICameraMaskable clippable)
|
||
{
|
||
if (clippable == null)
|
||
return;
|
||
var index = maskableList.IndexOf(clippable);
|
||
if (index >= 0)
|
||
{
|
||
maskableList.RemoveAt(index);
|
||
RemoveClipForOne(clippable);
|
||
}
|
||
}
|
||
|
||
private void ResetClipArea()
|
||
{
|
||
var corners = new Vector3[4];
|
||
rectTransform.GetWorldCorners(corners);
|
||
for (int i = 0; i < corners.Length; i++)
|
||
{
|
||
corners[i] = RectTransformUtility.WorldToScreenPoint(GetWorldCamera(), corners[i]);
|
||
corners[i].x = corners[i].x / Screen.width * 2f - 1f;
|
||
corners[i].y = corners[i].y / Screen.height * 2f - 1f;
|
||
}
|
||
clipArea = new Vector4(corners[0].x, corners[0].y, corners[2].x, corners[2].y);
|
||
for (int i = 0; i < maskableList.Count; i++)
|
||
SetClipForOne(maskableList[i]);
|
||
}
|
||
|
||
private void SetClipForOne(UICameraMaskable clippable)
|
||
{
|
||
clippable.SetClipRect(clipArea);
|
||
}
|
||
|
||
private Camera GetWorldCamera()
|
||
{
|
||
var uiManager = UIManager.Instance();
|
||
if (uiManager)
|
||
return uiManager.UICamera;
|
||
else
|
||
return Camera.main;
|
||
}
|
||
|
||
// 暂时使用transform.hasChanged api来检测Mask是否有变化
|
||
Rect lastRect;
|
||
private bool IsTransformDirty(RectTransform rectTransform)
|
||
{
|
||
bool result = false;
|
||
if (rectTransform.hasChanged)
|
||
{
|
||
rectTransform.hasChanged = false;
|
||
result = true;
|
||
}
|
||
else if (rectTransform.rect != lastRect)
|
||
result = true;
|
||
if (result)
|
||
lastRect = rectTransform.rect;
|
||
return result;
|
||
}
|
||
|
||
public static void RemoveClipForOne(UICameraMaskable clippable)
|
||
{
|
||
clippable.SetClipRect(new Vector4(-1f, -1f, 1f, 1f));
|
||
}
|
||
} |