来源:https://github.com/asyncrun/GuideMask
using UnityEngine;
using UnityEngine.UI;
/*
引导遮罩
-- 打开后只有指定地方可以点击,且指定地方完全透明
targetArea:
指定区域
offset:
偏差值
*/
[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(CanvasRenderer))]
public class GuideMask : MaskableGraphic, ICanvasRaycastFilter
{
public RectTransform targetArea;
public Vector2 offset = Vector2.zero;
/// <summary>
/// 是否屏蔽某个位置的射线事件
/// false -- 代表不屏蔽
/// true -- 代表屏蔽
/// </summary>
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
return !RectTransformUtility.RectangleContainsScreenPoint(targetArea, sp, eventCamera);
}
protected override void OnPopulateMesh(VertexHelper vh)
{
if (targetArea != null)
{
vh.Clear();
var maskRect = rectTransform.rect;
var targetRect = GetRect(targetArea);
targetRect.x -= offset.x;
targetRect.y -= offset.y;
targetRect.width += offset.x * 2;
targetRect.height += offset.y * 2;
Rect rect1 = new Rect(maskRect.x, maskRect.y, targetRect.x - maskRect.x, maskRect.height);
Rect rect2 = new Rect(targetRect.x + targetRect.width, maskRect.y, maskRect.width - (targetRect.x - maskRect.x) - targetRect.width, maskRect.height);
Rect rect3 = new Rect(targetRect.x, maskRect.y, targetRect.width, targetRect.y - maskRect.y);
Rect rect4 = new Rect(targetRect.x, targetRect.y + targetRect.height, targetRect.width, maskRect.height - (targetRect.y - maskRect.y) - targetRect.height);
AddMask(vh, rect1);
AddMask(vh, rect2);
AddMask(vh, rect3);
AddMask(vh, rect4);
}
else
{
base.OnPopulateMesh(vh);
}
}
// 左下 左上 右上 右下
// 0 1 2 3
// 构成一个矩形(0 1 2)(2 3 0)
private void AddMask(VertexHelper vh, Rect rect)
{
var currentVertCount = vh.currentVertCount;
var leftBottom = new Vector2(rect.x, rect.y);
var leftTop = new Vector2(rect.x, rect.y + rect.height);
var rightTop = new Vector2(rect.x + rect.width, rect.y + rect.height);
var rightBottom = new Vector2(rect.x + rect.width, rect.y);
vh.AddVert(leftBottom, color, Vector2.zero);
vh.AddVert(leftTop, color, Vector2.zero);
vh.AddVert(rightTop, color, Vector2.zero);
vh.AddVert(rightBottom, color, Vector2.zero);
vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2);
vh.AddTriangle(currentVertCount + 2, currentVertCount + 3, currentVertCount);
}
/// <summary>
/// 获取一个RectTransform相对于中心点的Rect
/// </summary>
private Rect GetRect(RectTransform rectTransform)
{
Rect rect = rectTransform.rect;
rect.x = rect.x + rectTransform.position.x - Screen.width / 2;
rect.y = rect.y + rectTransform.position.y - Screen.height / 2;
return rect;
}
private void LateUpdate()
{
SetAllDirty();
}
}