ngui Panel多层次事件响应异常

2015年01月25日 14:14 0 点赞 0 评论 更新于 2025-11-21 15:26

在使用 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 多层次事件响应异常。

作者信息

feifeila

feifeila

共发布了 3994 篇文章