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));
|
|||
|
}
|
|||
|
}
|