先修复一下,错误的场景 删除不必要的钓场资产 修复into场景 update:更新meta文件,修复报错 update:修复资源 修复第一章节建造 修复建造第三章 update:删除多余内容 update:更新README.md update:还原图标 update:更新README update:更新配置
261 lines
7.9 KiB
C#
261 lines
7.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Coffee.UISoftMaskInternal;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.UI;
|
|
|
|
namespace Coffee.UISoftMask
|
|
{
|
|
public interface IMaskingShapeContainerOwner
|
|
{
|
|
void Register(MaskingShapeContainer container);
|
|
}
|
|
|
|
[ExecuteAlways]
|
|
[DisallowMultipleComponent]
|
|
[AddComponentMenu("")]
|
|
[Icon("Packages/com.coffee.softmask-for-ugui/Icons/SoftMaskIcon.png")]
|
|
public class MaskingShapeContainer : MonoBehaviour, ICanvasRaycastFilter, IMaterialModifier
|
|
{
|
|
[SerializeField]
|
|
private List<MaskingShape> m_MaskingShapes = new List<MaskingShape>();
|
|
|
|
private Action _checkTransformChanged;
|
|
|
|
private bool _dirty;
|
|
private Mask _mask;
|
|
private bool _needTerminal;
|
|
private TerminalMaskingShape _terminal;
|
|
|
|
private void OnEnable()
|
|
{
|
|
UIExtraCallbacks.onBeforeCanvasRebuild +=
|
|
_checkTransformChanged ?? (_checkTransformChanged = CheckTransformChanged);
|
|
hideFlags = UISoftMaskProjectSettings.hideFlagsForTemp;
|
|
SetContainerDirty();
|
|
|
|
if (_mask is IMaskingShapeContainerOwner owner)
|
|
{
|
|
owner.Register(this);
|
|
}
|
|
|
|
_dirty = true;
|
|
m_MaskingShapes.RemoveAll(x => !x);
|
|
m_MaskingShapes.Sort();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
UIExtraCallbacks.onBeforeCanvasRebuild -=
|
|
_checkTransformChanged ?? (_checkTransformChanged = CheckTransformChanged);
|
|
_dirty = false;
|
|
_needTerminal = false;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
_mask = null;
|
|
_terminal = null;
|
|
m_MaskingShapes.Clear();
|
|
_checkTransformChanged = null;
|
|
}
|
|
|
|
bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
|
|
{
|
|
const string key = nameof(ICanvasRaycastFilter.IsRaycastLocationValid);
|
|
if (FrameCache.TryGet(this, key, out bool valid))
|
|
{
|
|
return valid;
|
|
}
|
|
|
|
// If the mask is owner of the container, skip the raycast.
|
|
if (!_mask || !_mask.MaskEnabled() || _mask is IMaskingShapeContainerOwner)
|
|
{
|
|
FrameCache.Set(this, key, true);
|
|
return true;
|
|
}
|
|
|
|
valid = IsInside(sp, eventCamera, true);
|
|
|
|
FrameCache.Set(this, key, valid);
|
|
return valid;
|
|
}
|
|
|
|
Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial)
|
|
{
|
|
// If the terminal exists, remove pop instruction (the operation to revert the stencil).
|
|
if (isActiveAndEnabled && _mask && _mask.MaskEnabled() && _needTerminal)
|
|
{
|
|
_mask.graphic.canvasRenderer.hasPopInstruction = false;
|
|
_mask.graphic.canvasRenderer.popMaterialCount = 0;
|
|
}
|
|
|
|
return baseMaterial;
|
|
}
|
|
|
|
public bool IsInside(Vector2 sp, Camera eventCamera, bool defaultValid = false, float threshold = 0.01f)
|
|
{
|
|
if (FrameCache.TryGet(this, nameof(IsInside), defaultValid ? 0 : 1, out bool valid))
|
|
{
|
|
return valid;
|
|
}
|
|
|
|
Profiler.BeginSample("(SM4UI)[MaskingShapeContainer] IsInside");
|
|
valid = defaultValid;
|
|
for (var i = 0; i < m_MaskingShapes.Count; i++)
|
|
{
|
|
var maskingShape = m_MaskingShapes[i];
|
|
if (!maskingShape || !maskingShape.IsInside(sp, eventCamera, threshold)) continue;
|
|
switch (maskingShape.actualRaycastMethod)
|
|
{
|
|
case MaskingShape.RaycastMethod.Additive:
|
|
valid = true;
|
|
break;
|
|
case MaskingShape.RaycastMethod.Subtract:
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FrameCache.Set(this, nameof(IsInside), defaultValid ? 0 : 1, valid);
|
|
Profiler.EndSample();
|
|
|
|
return valid;
|
|
}
|
|
|
|
public void SetContainerDirty()
|
|
{
|
|
Logging.LogIf(!_dirty, this, $"! SetContainerDirty {GetInstanceID()}");
|
|
|
|
if (!_mask)
|
|
{
|
|
TryGetComponent(out _mask);
|
|
}
|
|
|
|
_dirty = true;
|
|
}
|
|
|
|
private void CheckTransformChanged()
|
|
{
|
|
if (!_mask) return;
|
|
|
|
var softMask = _mask as SoftMask;
|
|
_needTerminal = false;
|
|
for (var i = 0; i < m_MaskingShapes.Count; i++)
|
|
{
|
|
var shape = m_MaskingShapes[i];
|
|
if (!shape || !shape.graphic || !shape.graphic.IsInScreen()) continue;
|
|
|
|
if (shape.hasTransformChanged)
|
|
{
|
|
_dirty = true;
|
|
}
|
|
|
|
if (shape.maskingMethod == MaskingShape.MaskingMethod.Additive)
|
|
{
|
|
_needTerminal = true;
|
|
}
|
|
}
|
|
|
|
if (_dirty && _mask && _mask.MaskEnabled())
|
|
{
|
|
if (softMask)
|
|
{
|
|
softMask.SetSoftMaskDirty();
|
|
}
|
|
else
|
|
{
|
|
_mask.graphic.SetMaterialDirty();
|
|
}
|
|
}
|
|
|
|
_dirty = false;
|
|
|
|
if (!_mask.MaskEnabled()
|
|
|| (softMask && softMask.SoftMaskingEnabled() && !UISoftMaskProjectSettings.useStencilOutsideScreen))
|
|
{
|
|
_needTerminal = false;
|
|
}
|
|
|
|
if (_needTerminal && !_terminal)
|
|
{
|
|
_terminal = FindTerminal();
|
|
}
|
|
|
|
if (_terminal)
|
|
{
|
|
_terminal.enabled = _needTerminal;
|
|
_terminal.transform.SetAsLastSibling();
|
|
}
|
|
}
|
|
|
|
public bool IsInScreen()
|
|
{
|
|
for (var i = 0; i < m_MaskingShapes.Count; i++)
|
|
{
|
|
var shape = m_MaskingShapes[i];
|
|
if (shape && shape.graphic && shape.graphic.IsInScreen())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void DrawSoftMaskBuffer(CommandBuffer cb, int softMaskDepth)
|
|
{
|
|
for (var i = m_MaskingShapes.Count - 1; i >= 0; i--)
|
|
{
|
|
var shape = m_MaskingShapes[i];
|
|
if (!shape) m_MaskingShapes.RemoveAtFast(i);
|
|
}
|
|
|
|
m_MaskingShapes.Sort();
|
|
|
|
for (var i = 0; i < m_MaskingShapes.Count; i++)
|
|
{
|
|
m_MaskingShapes[i].DrawSoftMaskBuffer(cb, softMaskDepth);
|
|
}
|
|
}
|
|
|
|
public void Register(MaskingShape shape)
|
|
{
|
|
if (!shape || m_MaskingShapes.Contains(shape)) return;
|
|
|
|
m_MaskingShapes.Add(shape);
|
|
_dirty = true;
|
|
Logging.Log(this, $"Register #{m_MaskingShapes.Count}: {shape} {shape.GetInstanceID()}");
|
|
}
|
|
|
|
public void Unregister(MaskingShape shape)
|
|
{
|
|
if (!m_MaskingShapes.Contains(shape)) return;
|
|
|
|
m_MaskingShapes.Remove(shape);
|
|
_dirty = true;
|
|
Logging.Log(this, $"Unregister #{m_MaskingShapes.Count}: {shape} {shape.GetInstanceID()}");
|
|
}
|
|
|
|
private TerminalMaskingShape FindTerminal()
|
|
{
|
|
var count = transform.childCount;
|
|
for (var i = 0; i < count; i++)
|
|
{
|
|
if (transform.GetChild(i).TryGetComponent<TerminalMaskingShape>(out var terminal))
|
|
{
|
|
return terminal;
|
|
}
|
|
}
|
|
|
|
var go = new GameObject("[generated] TerminalMaskingShape");
|
|
go.transform.SetParent(transform, false);
|
|
go.hideFlags = UISoftMaskProjectSettings.hideFlagsForTemp;
|
|
|
|
return go.AddComponent<TerminalMaskingShape>();
|
|
}
|
|
}
|
|
}
|