ngui Panel多层次事件响应异常
在使用 NGUI 的 Panel 时,当两个 Panel 重叠,点击前面的面板时,后面面板的按钮可能会被响应。这是因为 NGUI 将 UI 控件视为 3D 世界中的物体来创建碰撞体,通过 UICamera 响应射线碰撞事件。然而,由于 Panel 没有碰撞体,射线会直接穿过,从而碰撞到后面自带 Box Collider 的 Button 上,导致事件响应异常。
本人刚学习 NGUI 时发现了这个问题,不确定 NGUI 是否已经提供了解决方法,希望了解的大神能帮忙指点。这里先分享一个临时解决方法。
1. 在 NGUITools 中添加方法
重新计算碰撞体边界
// add for reCalculate collider bounds reference AddWidgetCollider
static public void RecalculateColliderBounds(GameObject go)
{
if (go != null)
{
BoxCollider box = go.GetComponent<Collider>() as BoxCollider;
if (box == null)
return;
int depth = NGUITools.CalculateNextDepth(go);
Bounds b = NGUIMath.CalculateRelativeWidgetBounds(go.transform);
box.isTrigger = true;
box.center = b.center + Vector3.back * (depth * 0.25f);
box.size = new Vector3(b.size.x, b.size.y, 0f);
}
}
此方法主要用于对添加了 Box Collider 的 Panel,重新计算其下子控件所组成的一个外围区域。
从控件移除碰撞体
// remove collider from widget
static public void RemoveColliderFromWidget(GameObject go)
{
if (go != null)
{
BoxCollider box = go.GetComponent<Collider>() as BoxCollider;
if (box == null)
return;
if (Application.isPlaying)
GameObject.Destroy(box);
else
GameObject.DestroyImmediate(box);
}
}
该方法为编辑器提供了一个手动设置 Panel 是否具有碰撞体的功能。
2. 在 UIPanel 中添加代码
添加是否为碰撞体 Panel 的选项
// whether this panel is collider panel
public bool isColliderPanel = false;
public bool IsColliderPanel
{
get { return isColliderPanel; }
set
{
this.isColliderPanel = value;
if (this.isColliderPanel)
{
NGUITools.AddWidgetCollider(this.gameObject);
}
else
{
NGUITools.RemoveColliderFromWidget(this.gameObject);
}
}
}
添加这个选项后,可以方便地设置 Panel 是否为带碰撞功能的 Panel。
更新碰撞体外围区域
在 void LateUpdate () 函数的最后添加 NGUITools.RecalculateColliderBounds(this.gameObject);,以便随时更新碰撞体的外围方块区域。
3. 在 UIPanelInspector 中添加编辑器选项
在 OnInspectorGUI () 函数的最后添加以下代码:
GUILayout.BeginHorizontal();
bool isColliderPanel = EditorGUILayout.Toggle("Is Collider", panel.IsColliderPanel, GUILayout.Width(100f));
GUILayout.Label("whether the panel need collider");
GUILayout.EndHorizontal();
if (panel.IsColliderPanel != isColliderPanel)
{
panel.IsColliderPanel = isColliderPanel;
EditorUtility.SetDirty(panel);
}
通过以上操作,就可以随时指定当前 Panel 是否带有碰撞体。效果如下图: NGUI - 解决 Panel 多层次事件响应异常。