using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections.Generic;
using UnityEngine.EventSystems;
///
/// 用于在Ui中切割Renderer的组件,类似RectMask2d;
/// 暂时未处理Mask嵌套的情况
///
[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
public class UICameraMask : UIBehaviour, IClipper
{
private RectTransform rectTransform;
private bool m_ShouldRecalculateClipRects;
private List maskableList;
private Vector4 clipArea;
protected override void Awake()
{
base.Awake();
rectTransform = (RectTransform)transform;
maskableList = new List();
}
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));
}
}