一、先看下效果
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; } } } }