一、先看下效果
Prefab结构
二、实现思路:
1、prefab上的Panel层级设置成较高
2、背景由5个UISprite拼接起来的,4个(L,R,U,D)当作遮罩,1个镂空(Hollow)当作点击触发(全部都有BoxCollider,并且都生效,有人会问这不就把后面的按钮也给拦截住了,后面会说为什么要这样)
3、4个遮罩的大小由Holow大小决定
4、Hollow绑定一个点击事件ClickCenter (后面代码里有)
三、关键部分:
这里解释为什么上面要把Hollow也带上BoxCollider,目的是修正点击位置,只要是点Hollow上,就让NGUI只相应点击在Hollow中心点后面的第一个UIWidget,这样就可以避免因为点不准,拖拽的其他问题
如图,只要我点在篮筐里,就只响应红点下面的第一个控件
四、代码
其实就是NGUI的点击响应代码,位置传入的是Hollow的位置
using System; using UnityEngine; using System.Collections; using System.Collections.Generic; public class NewbieGuide : MonoBehaviour { public Transform Hollow; bool IsVisible(Vector3 worldPoint, GameObject go) { UIPanel panel = NGUITools.FindInParents<UIPanel>(go); while (panel != null) { if (!panel.IsVisible(worldPoint)) return false; panel = panel.parentPanel; } return true; } struct DepthEntry { public int depth; public RaycastHit hit; public Vector3 point; public GameObject go; } #if UNITY_FLASH static bool IsVisible (DepthEntry de) #else static bool IsVisible(ref DepthEntry de) #endif { UIPanel panel = NGUITools.FindInParents<UIPanel>(de.go); while (panel != null) { if (!panel.IsVisible(de.point)) return false; panel = panel.parentPanel; } return true; } void Notify(GameObject go, string funcName, object obj) { if (NGUITools.GetActive(go)) { go.SendMessage(funcName, obj, SendMessageOptions.DontRequireReceiver); } } public void ClickCenter() { DepthEntry mHit = new DepthEntry(); BetterList<DepthEntry> mHits = new BetterList<DepthEntry>(); UICamera cam = UICamera.current; UIEventTrigger.current = null; // Convert to view space var currentCamera = cam.cachedCamera; // Cast a ray into the screen var p = Hollow.transform.position; p.z = currentCamera.nearClipPlane; Ray ray = new Ray(p, Vector3.forward); // Raycast into the screen int mask = currentCamera.cullingMask & (int)cam.eventReceiverMask; float dist = (cam.rangeDistance > 0f) ? cam.rangeDistance : currentCamera.farClipPlane - currentCamera.nearClipPlane; RaycastHit[] hits = Physics.RaycastAll(ray, dist, mask); if (hits.Length > 1) { for (int b = 0; b < hits.Length; ++b) { GameObject go = hits[b].collider.gameObject; if (go == Hollow.gameObject) continue; UIWidget w = go.GetComponent<UIWidget>(); if (w != null) { if (!w.isVisible) continue; if (w.hitCheck != null && !w.hitCheck(hits[b].point)) continue; } else { UIRect rect = NGUITools.FindInParents<UIRect>(go); if (rect != null && rect.finalAlpha < 0.001f) continue; } mHit.depth = NGUITools.CalculateRaycastDepth(go); if (mHit.depth != int.MaxValue) { mHit.hit = hits[b]; mHit.point = hits[b].point; mHit.go = hits[b].collider.gameObject; mHits.Add(mHit); } } mHits.Sort(delegate(DepthEntry r1, DepthEntry r2) { return r2.depth.CompareTo(r1.depth); }); for (int b = 0; b < mHits.size; ++b) { #if UNITY_FLASH if (IsVisible(mHits.buffer[b])) #else if (IsVisible(ref mHits.buffer[b])) #endif { Notify(mHits.buffer[b].go, "OnClick", null); return; } } mHits.Clear(); } else if (hits.Length == 1) { GameObject go = hits[0].collider.gameObject; if (go == Hollow.gameObject) return; UIWidget w = go.GetComponent<UIWidget>(); if (w != null) { if (!w.isVisible) return; if (w.hitCheck != null && !w.hitCheck(hits[0].point)) return; } else { UIRect rect = NGUITools.FindInParents<UIRect>(go); if (rect != null && rect.finalAlpha < 0.001f) return; } if (IsVisible(hits[0].point, hits[0].collider.gameObject)) { Notify(hits[0].collider.gameObject, "OnClick", null); return; } } } }