tutorial done
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Inverted stencil mask (see materialForRendering). For raycasts, assign
|
||||
/// <see cref="raycastPassThroughRects"/> to rects that match each visual "hole"
|
||||
/// — clicks there won’t hit this graphic and pass to UI behind.
|
||||
///
|
||||
/// Parent <see cref="Mask"/> also implements <see cref="ICanvasRaycastFilter"/> and only
|
||||
/// allows points inside its RectTransform. A fullscreen child under a small mask would
|
||||
/// otherwise fail the raycast outside that rect (dimmed area lets clicks through) while
|
||||
/// still blocking inside the mask bounds. We skip only Mask/RectMask2D in the raycast
|
||||
/// walk (<see cref="Graphic.Raycast(UnityEngine.Vector2,UnityEngine.Camera,bool)"/> with
|
||||
/// ignoreMasks) so hit testing matches the fullscreen Image; rendering still uses stencil
|
||||
/// because <see cref="MaskableGraphic.maskable"/> stays true.
|
||||
/// </summary>
|
||||
public class CutoutMaskUI : Image
|
||||
{
|
||||
[Tooltip("Rects matching cutout/hole areas. Clicks inside are not consumed by this Image. Leave empty to use the parent Mask’s RectTransform.")]
|
||||
[SerializeField] RectTransform[] raycastPassThroughRects;
|
||||
|
||||
[Tooltip("The Image on the same object as Mask is usually the cutout shape and still receives raycasts. When this is on, that graphic’s Raycast Target is turned off while this component is enabled so the hole reaches UI behind the overlay.")]
|
||||
[SerializeField] bool disableRaycastOnParentMaskGraphic = true;
|
||||
|
||||
Mask cachedParentMask;
|
||||
Graphic cachedMaskGraphic;
|
||||
bool storedMaskGraphicRaycast;
|
||||
bool storedMaskGraphicRaycastValid;
|
||||
|
||||
public override bool Raycast(Vector2 sp, Camera eventCamera)
|
||||
{
|
||||
return Raycast(sp, eventCamera, ignoreMasks: true);
|
||||
}
|
||||
|
||||
public override Material materialForRendering{
|
||||
get{
|
||||
Material material = new Material(base.materialForRendering);
|
||||
material.SetInt("_StencilComp", (int)CompareFunction.NotEqual);
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
if (!disableRaycastOnParentMaskGraphic)
|
||||
return;
|
||||
|
||||
cachedParentMask = GetComponentInParent<Mask>();
|
||||
if (cachedParentMask == null)
|
||||
return;
|
||||
|
||||
cachedMaskGraphic = cachedParentMask.graphic;
|
||||
if (cachedMaskGraphic == null || cachedMaskGraphic == this)
|
||||
return;
|
||||
|
||||
storedMaskGraphicRaycastValid = true;
|
||||
storedMaskGraphicRaycast = cachedMaskGraphic.raycastTarget;
|
||||
cachedMaskGraphic.raycastTarget = false;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
if (storedMaskGraphicRaycastValid && cachedMaskGraphic != null)
|
||||
{
|
||||
cachedMaskGraphic.raycastTarget = storedMaskGraphicRaycast;
|
||||
storedMaskGraphicRaycastValid = false;
|
||||
}
|
||||
|
||||
cachedMaskGraphic = null;
|
||||
cachedParentMask = null;
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
|
||||
{
|
||||
if (IsInsidePassThroughHole(screenPoint, eventCamera))
|
||||
return false;
|
||||
|
||||
return base.IsRaycastLocationValid(screenPoint, eventCamera);
|
||||
}
|
||||
|
||||
bool IsInsidePassThroughHole(Vector2 screenPoint, Camera eventCamera)
|
||||
{
|
||||
if (raycastPassThroughRects != null)
|
||||
{
|
||||
for (int i = 0; i < raycastPassThroughRects.Length; i++)
|
||||
{
|
||||
RectTransform rect = raycastPassThroughRects[i];
|
||||
if (rect != null && RectTransformUtility.RectangleContainsScreenPoint(rect, screenPoint, eventCamera))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Mask mask = cachedParentMask != null ? cachedParentMask : GetComponentInParent<Mask>();
|
||||
if (mask != null && mask.rectTransform != null &&
|
||||
RectTransformUtility.RectangleContainsScreenPoint(mask.rectTransform, screenPoint, eventCamera))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 721d1e0343adc3c42b4508f55c455957
|
||||
Reference in New Issue
Block a user