1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
using UnityEngine;
using UnityEngine.UI;
 
/// <summary>
/// 特效穿透阻挡器
/// 将此脚本挂在特效游戏对象上,可以防止特效穿透UI界面
/// </summary>
public class EffectPenetrationBlocker : MonoBehaviour
{
    [Tooltip("是否在UI层级下自动调整排序顺序")]
    public bool autoAdjustSorting = true;
    
    [Tooltip("特效渲染器,如果为空则自动获取")]
    public Renderer[] effectRenderers;
    
    [Tooltip("特效粒子系统,如果为空则自动获取")]
    public ParticleSystem[] particleSystems;
    
    [Tooltip("自定义排序顺序,仅在不自动调整时有效")]
    public int customSortingOrder = 0;
    
    [Tooltip("自定义排序层,为空则使用默认UI层")]
    public string customSortingLayer = "UI";
    
    [Tooltip("特效所属的Canvas,如果为空则查找父级Canvas")]
    public Canvas parentCanvas;
    
    [Tooltip("特效在Canvas中的排序偏移量")]
    public int _sortingOrderOffset = 0;
    
    public int canvasSortingOrder = 0;
    
    private void Awake()
    {
        // 如果没有指定渲染器,则自动获取
        if (effectRenderers == null || effectRenderers.Length == 0)
        {
            effectRenderers = GetComponentsInChildren<Renderer>(true);
        }
        
        // 如果没有指定粒子系统,则自动获取
        if (particleSystems == null || particleSystems.Length == 0)
        {
            particleSystems = GetComponentsInChildren<ParticleSystem>(true);
        }
        
        // 查找父级Canvas
        if (parentCanvas == null)
        {
            parentCanvas = GetComponentInParent<Canvas>();
        }
        
        if (autoAdjustSorting)
        {
            UpdateSortingOrder();
        }
        else
        {
            // 使用自定义排序
            ApplySortingSettings(customSortingOrder, customSortingLayer);
        }
    }
    
    private void OnEnable()
    {
        if (autoAdjustSorting)
        {
            UpdateSortingOrder();
        }
    }
    
    /// <summary>
    /// 更新排序顺序,确保特效显示在当前UI界面上方
    /// </summary>
    public void UpdateSortingOrder()
    {
        if (!autoAdjustSorting) return;
        
        // 获取父级Canvas的排序顺序
        if (parentCanvas != null)
        {
            canvasSortingOrder = parentCanvas.sortingOrder;
        }
        else
        {
            // 如果没有找到父级Canvas,则使用默认值
            canvasSortingOrder = 0;
        }
        
        // 将特效的排序顺序设置为Canvas排序顺序加上偏移量
        ApplySortingSettings(canvasSortingOrder + _sortingOrderOffset, customSortingLayer);
    }
    
    /// <summary>
    /// 应用排序设置到所有渲染器和粒子系统
    /// </summary>
    private void ApplySortingSettings(int sortingOrder, string sortingLayer)
    {
        // const int overlayRQ = 4000;
 
        // 应用到渲染器
        foreach (Renderer renderer in effectRenderers)
        {
            if (renderer != null)
            {
                renderer.sortingOrder = sortingOrder;
                // renderer.material.renderQueue = overlayRQ;
                if (!string.IsNullOrEmpty(sortingLayer))
                {
                    renderer.sortingLayerName = sortingLayer;
                }
            }
        }
        
        // 应用到粒子系统
        foreach (ParticleSystem ps in particleSystems)
        {
            if (ps != null)
            {
                ParticleSystemRenderer psRenderer = ps.GetComponent<ParticleSystemRenderer>();
                if (psRenderer != null)
                {
                    psRenderer.sortingOrder = sortingOrder;
                    // psRenderer.material.renderQueue = overlayRQ;
                    if (!string.IsNullOrEmpty(sortingLayer))
                    {
                        psRenderer.sortingLayerName = sortingLayer;
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// 手动设置排序顺序
    /// </summary>
    public void SetSortingOrder(int sortingOrder, string sortingLayer = null)
    {
        customSortingOrder = sortingOrder;
        if (!string.IsNullOrEmpty(sortingLayer))
        {
            customSortingLayer = sortingLayer;
        }
        
        autoAdjustSorting = false;
        ApplySortingSettings(customSortingOrder, customSortingLayer);
    }
    
    /// <summary>
    /// 设置父级Canvas
    /// </summary>
    public void SetParentCanvas(Canvas canvas)
    {
        parentCanvas = canvas;
        if (autoAdjustSorting)
        {
            UpdateSortingOrder();
        }
    }
 
#if UNITY_EDITOR
    [ContextMenu("Apply")]
    public void Apply()
    {
        UpdateSortingOrder();
    }
#endif
}