//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- #define FUNCELL_MODIFIED using UnityEngine; using System.Collections.Generic; #if !UNITY_5_4 using UnityEngine.Profiling; #endif /// /// UI Panel is responsible for collecting, sorting and updating widgets in addition to generating widgets' geometry. /// [ExecuteInEditMode] [AddComponentMenu("NGUI/UI/NGUI Panel")] public class UIPanel : UIRect { /// /// List of active panels. /// static public List list = new List(); static private List idList = new List(); static private bool listNeedSort = false; public enum RenderQueue { Automatic, StartAt, Explicit, } public delegate void OnGeometryUpdated (); /// /// Notification triggered when the panel's geometry get rebuilt. It's mainly here for debugging purposes. /// public OnGeometryUpdated onGeometryUpdated; /// /// Whether this panel will show up in the panel tool (set this to 'false' for dynamically created temporary panels) /// public bool showInPanelTool = true; /// /// Whether normals and tangents will be generated for all meshes /// public bool generateNormals = false; /// /// Whether widgets drawn by this panel are static (won't move). This will improve performance. /// public bool widgetsAreStatic = false; /// /// Whether widgets will be culled while the panel is being dragged. /// Having this on improves performance, but turning it off will reduce garbage collection. /// public bool cullWhileDragging = true; /// /// Optimization flag. Makes the assumption that the panel's geometry /// will always be on screen and the bounds don't need to be re-calculated. /// public bool alwaysOnScreen = false; /// /// By default, non-clipped panels use the camera's bounds, and the panel's position has no effect. /// If you want the panel's position to actually be used with anchors, set this field to 'true'. /// public bool anchorOffset = false; /// /// Whether the soft border will be used as padding. /// public bool softBorderPadding = true; /// /// By default all panels manage render queues of their draw calls themselves by incrementing them /// so that the geometry is drawn in the proper order. You can alter this behaviour. /// public RenderQueue renderQueue = RenderQueue.Automatic; public static int lateUpdateRate = 0; /// /// Render queue used by the panel. The default value of '3000' is the equivalent of "Transparent". /// This property is only used if 'renderQueue' is set to something other than "Automatic". /// public int startingRenderQueue = 3100; /// /// List of widgets managed by this panel. Do not attempt to modify this list yourself. /// [System.NonSerialized] public List widgets = new List(); /// /// List of draw calls created by this panel. Do not attempt to modify this list yourself. /// [System.NonSerialized] public List drawCalls = new List(); /// /// Matrix that will transform the specified world coordinates to relative-to-panel coordinates. /// [System.NonSerialized] public Matrix4x4 worldToLocal = Matrix4x4.identity; /// /// Cached clip range passed to the draw call's shader. /// [System.NonSerialized] public Vector4 drawCallClipRange = new Vector4(0f, 0f, 1f, 1f); public delegate void OnClippingMoved (UIPanel panel); /// /// Event callback that's triggered when the panel's clip region gets moved. /// public OnClippingMoved onClipMove; #if FUNCELL_MODIFIED public delegate void OnParentChanged(UIPanel panel); public OnParentChanged onParentChanged; #endif // Clip texture feature contributed by the community: http://www.tasharen.com/forum/index.php?topic=9268.0 [HideInInspector][SerializeField] Texture2D mClipTexture = null; // Panel's alpha (affects the alpha of all widgets) [HideInInspector][SerializeField] float mAlpha = 1f; #if FUNCELL_MODIFIED private float _oldAlpha = -1; [System.NonSerialized] public float oldFinalAlpha = 1f; [System.NonSerialized] public bool updateDrawCall = false; #endif // Clipping rectangle [HideInInspector][SerializeField] UIDrawCall.Clipping mClipping = UIDrawCall.Clipping.None; [HideInInspector][SerializeField] Vector4 mClipRange = new Vector4(0f, 0f, 300f, 200f); [HideInInspector][SerializeField] Vector2 mClipSoftness = new Vector2(4f, 4f); [HideInInspector][SerializeField] int mDepth = 0; [HideInInspector][SerializeField] int mSortingOrder = 0; // Whether a full rebuild of geometry buffers is required bool mRebuild = false; bool mResized = false; [SerializeField] Vector2 mClipOffset = Vector2.zero; int mMatrixFrame = -1; int mAlphaFrameID = 0; int mLayer = -1; // Values used for visibility checks static float[] mTemp = new float[4]; Vector2 mMin = Vector2.zero; Vector2 mMax = Vector2.zero; bool mHalfPixelOffset = false; bool mSortWidgets = false; bool mUpdateScroll = false; #if FUNCELL_MODIFIED //设置渐变的隐藏边(left,right,top,bottom) [HideInInspector] [SerializeField] Vector4 mClipSoftnessHide = Vector4.one; /// /// 设置渐变的隐藏边(left,right,top,bottom) /// public Vector4 ClipSoftnessHide { get { return mClipSoftnessHide; } set { mClipSoftnessHide = value; if (mClipSoftnessHide.x > 0) mClipSoftnessHide.x = 1; if (mClipSoftnessHide.y > 0) mClipSoftnessHide.y = 1; if (mClipSoftnessHide.z > 0) mClipSoftnessHide.z = 1; if (mClipSoftnessHide.w > 0) mClipSoftnessHide.w = 1; } } //当前是否挂起 private bool _IsSuspend = false; private int _suspendFrameCount = -1; //当前是否挂起 public bool IsSuspend { get { return _IsSuspend && _suspendFrameCount < Time.frameCount; } set { if (_IsSuspend != value) { _suspendFrameCount = Time.frameCount + 1; _IsSuspend = value; } } } public delegate void OnRenderQueueChanged(int sq); //RenderQueue改变的回调操作 public OnRenderQueueChanged onRenderQueueChanged; #endif /// /// Helper property that returns the first unused depth value. /// static public int nextUnusedDepth { get { int highest = int.MinValue; for (int i = 0, imax = list.Count; i < imax; ++i) highest = Mathf.Max(highest, list[i].depth); return (highest == int.MinValue) ? 0 : highest + 1; } } /// /// Whether the rectangle can be anchored. /// public override bool canBeAnchored { get { return mClipping != UIDrawCall.Clipping.None; } } /// /// Panel's alpha affects everything drawn by the panel. /// public override float alpha { get { return mAlpha; } set { float val = Mathf.Clamp01(value); if (mAlpha != val) { mAlphaFrameID = -1; mResized = true; mAlpha = val; SetDirty(); } } } /// /// Panels can have their own depth value that will change the order with which everything they manage gets drawn. /// public int depth { get { return mDepth; } set { if (mDepth != value) { mDepth = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif //list.Sort(CompareFunc); listNeedSort = true; } } } /// /// Sorting order value for the panel's draw calls, to be used with Unity's 2D system. /// public int sortingOrder { get { return mSortingOrder; } set { if (mSortingOrder != value) { mSortingOrder = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif UpdateDrawCalls(); } } } /// /// Function that can be used to depth-sort panels. /// static public int CompareFunc (UIPanel a, UIPanel b) { if (a != b && a != null && b != null) { if (a.mDepth < b.mDepth) return -1; if (a.mDepth > b.mDepth) return 1; return (a.GetHashCode() < b.GetHashCode()) ? -1 : 1; } return 0; } /// /// Panel's width in pixels. /// public float width { get { return GetViewSize().x; } } /// /// Panel's height in pixels. /// public float height { get { return GetViewSize().y; } } /// /// Whether the panel's drawn geometry needs to be offset by a half-pixel. /// public bool halfPixelOffset { get { return mHalfPixelOffset; } } /// /// Whether the camera is used to draw UI geometry. /// #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 public bool usedForUI { get { return (anchorCamera != null && mCam.isOrthoGraphic); } } #else public bool usedForUI { get { return (anchorCamera != null && mCam.orthographic); } } #endif /// /// Directx9 pixel offset, used for drawing. /// public Vector3 drawCallOffset { get { #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (anchorCamera != null && mCam.isOrthoGraphic) #else if (anchorCamera != null && mCam.orthographic) #endif { Vector2 size = GetWindowSize(); float pixelSize = (root != null) ? root.pixelSizeAdjustment : 1f; float mod = (pixelSize / size.y) / mCam.orthographicSize; bool x = mHalfPixelOffset; bool y = mHalfPixelOffset; if ((Mathf.RoundToInt(size.x) & 1) == 1) x = !x; if ((Mathf.RoundToInt(size.y) & 1) == 1) y = !y; return new Vector3(x ? -mod : 0f, y ? mod : 0f); } return Vector3.zero; } } /// /// Clipping method used by all draw calls. /// public UIDrawCall.Clipping clipping { get { return mClipping; } set { if (mClipping != value) { mResized = true; mClipping = value; mMatrixFrame = -1; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif #if FUNCELL_MODIFIED if (onClipMove != null) onClipMove(this); #endif } } } UIPanel mParentPanel = null; /// /// Reference to the parent panel, if any. /// public UIPanel parentPanel { get { return mParentPanel; } } /// /// Number of times the panel's contents get clipped. /// public int clipCount { get { int count = 0; UIPanel p = this; while (p != null) { if (p.mClipping == UIDrawCall.Clipping.SoftClip || p.mClipping == UIDrawCall.Clipping.TextureMask) ++count; p = p.mParentPanel; } return count; } } /// /// Whether the panel will actually perform clipping of children. /// public bool hasClipping { get { return mClipping == UIDrawCall.Clipping.SoftClip || mClipping == UIDrawCall.Clipping.TextureMask; } } /// /// Whether the panel will actually perform clipping of children. /// public bool hasCumulativeClipping { get { return clipCount != 0; } } [System.Obsolete("Use 'hasClipping' or 'hasCumulativeClipping' instead")] public bool clipsChildren { get { return hasCumulativeClipping; } } /// /// Clipping area offset used to make it possible to move clipped panels (scroll views) efficiently. /// Scroll views move by adjusting the clip offset by one value, and the transform position by the inverse. /// This makes it possible to not have to rebuild the geometry, greatly improving performance. /// public Vector2 clipOffset { get { return mClipOffset; } set { if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f || Mathf.Abs(mClipOffset.y - value.y) > 0.001f) { mClipOffset = value; InvalidateClipping(); // Call the event delegate if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// /// Invalidate the panel's clipping, calling child panels in turn. /// void InvalidateClipping () { mResized = true; mMatrixFrame = -1; for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p != this && p.parentPanel == this) p.InvalidateClipping(); } } /// /// Texture used to clip the region. /// public Texture2D clipTexture { get { return mClipTexture; } set { if (mClipTexture != value) { mClipTexture = value; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// /// Clipping position (XY) and size (ZW). /// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead. /// [System.Obsolete("Use 'finalClipRegion' or 'baseClipRegion' instead")] public Vector4 clipRange { get { return baseClipRegion; } set { baseClipRegion = value; } } /// /// Clipping position (XY) and size (ZW). /// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead. /// public Vector4 baseClipRegion { get { return mClipRange; } set { if (Mathf.Abs(mClipRange.x - value.x) > 0.001f || Mathf.Abs(mClipRange.y - value.y) > 0.001f || Mathf.Abs(mClipRange.z - value.z) > 0.001f || Mathf.Abs(mClipRange.w - value.w) > 0.001f) { mResized = true; mClipRange = value; mMatrixFrame = -1; UIScrollView sv = GetComponent(); if (sv != null) sv.UpdatePosition(); if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// /// Final clipping region after the offset has been taken into consideration. XY = center, ZW = size. /// public Vector4 finalClipRegion { get { Vector2 size = GetViewSize(); if (mClipping != UIDrawCall.Clipping.None) { return new Vector4(mClipRange.x + mClipOffset.x, mClipRange.y + mClipOffset.y, size.x, size.y); } return new Vector4(0f, 0f, size.x, size.y); } } #if FUNCELL_MODIFIED /// /// 获取世界坐标的左上和右下的坐标 XY = LeftTop,ZW=RightBottom /// public Vector4 finalClipRectByWorld { get { if (mClipping != UIDrawCall.Clipping.None) { //Debug.Log(":::::Range:" + mClipRange + ";;" + transform.position + ";;"); Vector4 localPos = new Vector4() { x = mClipRange.x + mClipOffset.x - mClipRange.z / 2, y = mClipRange.y + mClipOffset.y - mClipRange.w / 2, z = mClipRange.x + mClipOffset.x + mClipRange.z / 2, w = mClipRange.y + mClipOffset.y + mClipRange.w / 2 }; Vector3 worldClipXY = transform.TransformPoint(localPos.x, localPos.y, 0); Vector3 worldClipZW = transform.TransformPoint(localPos.z, localPos.w, 0); return new Vector4() { x = worldClipXY.x, y = worldClipXY.y, z = worldClipZW.x, w = worldClipZW.y }; } return new Vector4(-50000, -50000, 50000, 50000); } } #endif /// /// Clipping softness is used if the clipped style is set to "Soft". /// public Vector2 clipSoftness { get { return mClipSoftness; } set { if (mClipSoftness != value) { mClipSoftness = value; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } // Temporary variable to avoid GC allocation static Vector3[] mCorners = new Vector3[4]; /// /// Local-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right. /// public override Vector3[] localCorners { get { if (mClipping == UIDrawCall.Clipping.None) { Vector3[] corners = worldCorners; Transform wt = cachedTransform; for (int i = 0; i < 4; ++i) corners[i] = wt.InverseTransformPoint(corners[i]); return corners; } else { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; mCorners[0] = new Vector3(x0, y0); mCorners[1] = new Vector3(x0, y1); mCorners[2] = new Vector3(x1, y1); mCorners[3] = new Vector3(x1, y0); } return mCorners; } } /// /// World-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right. /// public override Vector3[] worldCorners { get { if (mClipping != UIDrawCall.Clipping.None) { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; Transform wt = cachedTransform; mCorners[0] = wt.TransformPoint(x0, y0, 0f); mCorners[1] = wt.TransformPoint(x0, y1, 0f); mCorners[2] = wt.TransformPoint(x1, y1, 0f); mCorners[3] = wt.TransformPoint(x1, y0, 0f); } else if (anchorCamera != null) { Vector3[] corners = mCam.GetWorldCorners(cameraRayDistance); //if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform)) //{ // Vector3 off = cachedTransform.position; // for (int i = 0; i < 4; ++i) // corners[i] += off; //} return corners; } else { Vector2 size = GetViewSize(); float x0 = -0.5f * size.x; float y0 = -0.5f * size.y; float x1 = x0 + size.x; float y1 = y0 + size.y; mCorners[0] = new Vector3(x0, y0); mCorners[1] = new Vector3(x0, y1); mCorners[2] = new Vector3(x1, y1); mCorners[3] = new Vector3(x1, y0); if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform)) { Vector3 off = cachedTransform.position; for (int i = 0; i < 4; ++i) mCorners[i] += off; } } return mCorners; } } /// /// Get the sides of the rectangle relative to the specified transform. /// The order is left, top, right, bottom. /// public override Vector3[] GetSides (Transform relativeTo) { if (mClipping != UIDrawCall.Clipping.None) { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; float hx = (x0 + x1) * 0.5f; float hy = (y0 + y1) * 0.5f; Transform wt = cachedTransform; mSides[0] = wt.TransformPoint(x0, hy, 0f); mSides[1] = wt.TransformPoint(hx, y1, 0f); mSides[2] = wt.TransformPoint(x1, hy, 0f); mSides[3] = wt.TransformPoint(hx, y0, 0f); if (relativeTo != null) { for (int i = 0; i < 4; ++i) mSides[i] = relativeTo.InverseTransformPoint(mSides[i]); } return mSides; } else if (anchorCamera != null && anchorOffset) { Vector3[] sides = mCam.GetSides(cameraRayDistance); Vector3 off = cachedTransform.position; for (int i = 0; i < 4; ++i) sides[i] += off; if (relativeTo != null) { for (int i = 0; i < 4; ++i) sides[i] = relativeTo.InverseTransformPoint(sides[i]); } return sides; } return base.GetSides(relativeTo); } /// /// Invalidating the panel should reset its alpha. /// public override void Invalidate (bool includeChildren, bool onlyAlphaChange = false) { mAlphaFrameID = -1; base.Invalidate(includeChildren, onlyAlphaChange); } /// /// Widget's final alpha, after taking the panel's alpha into account. /// public override float CalculateFinalAlpha (int frameID) { #if UNITY_EDITOR if (mAlphaFrameID != frameID || !Application.isPlaying) #else if (mAlphaFrameID != frameID) #endif { mAlphaFrameID = frameID; UIRect pt = parent; finalAlpha = (pt != null) ? pt.CalculateFinalAlpha(frameID) * mAlpha : mAlpha; } return finalAlpha; } /// /// Set the panel's rectangle. /// public override void SetRect (float x, float y, float width, float height) { int finalWidth = Mathf.FloorToInt(width + 0.5f); int finalHeight = Mathf.FloorToInt(height + 0.5f); finalWidth = ((finalWidth >> 1) << 1); finalHeight = ((finalHeight >> 1) << 1); Transform t = cachedTransform; Vector3 pos = t.localPosition; pos.x = Mathf.Floor(x + 0.5f); pos.y = Mathf.Floor(y + 0.5f); if (finalWidth < 2) finalWidth = 2; if (finalHeight < 2) finalHeight = 2; baseClipRegion = new Vector4(pos.x, pos.y, finalWidth, finalHeight); if (isAnchored) { t = t.parent; if (leftAnchor.target) leftAnchor.SetHorizontal(t, x); if (rightAnchor.target) rightAnchor.SetHorizontal(t, x + width); if (bottomAnchor.target) bottomAnchor.SetVertical(t, y); if (topAnchor.target) topAnchor.SetVertical(t, y + height); #if UNITY_EDITOR NGUITools.SetDirty(this); #endif } } /// /// Returns whether the specified rectangle is visible by the panel. The coordinates must be in world space. /// #if UNITY_FLASH public bool IsVisible (Vector3 aa, Vector3 bb, Vector3 cc, Vector3 dd) #else public bool IsVisible (Vector3 a, Vector3 b, Vector3 c, Vector3 d) #endif { UpdateTransformMatrix(); // Transform the specified points from world space to local space #if UNITY_FLASH // http://www.tasharen.com/forum/index.php?topic=11390.0 Vector3 a = worldToLocal.MultiplyPoint3x4(aa); Vector3 b = worldToLocal.MultiplyPoint3x4(bb); Vector3 c = worldToLocal.MultiplyPoint3x4(cc); Vector3 d = worldToLocal.MultiplyPoint3x4(dd); #else a = worldToLocal.MultiplyPoint3x4(a); b = worldToLocal.MultiplyPoint3x4(b); c = worldToLocal.MultiplyPoint3x4(c); d = worldToLocal.MultiplyPoint3x4(d); #endif mTemp[0] = a.x; mTemp[1] = b.x; mTemp[2] = c.x; mTemp[3] = d.x; float minX = Mathf.Min(mTemp); float maxX = Mathf.Max(mTemp); mTemp[0] = a.y; mTemp[1] = b.y; mTemp[2] = c.y; mTemp[3] = d.y; float minY = Mathf.Min(mTemp); float maxY = Mathf.Max(mTemp); if (maxX < mMin.x) return false; if (maxY < mMin.y) return false; if (minX > mMax.x) return false; if (minY > mMax.y) return false; return true; } /// /// Returns whether the specified world position is within the panel's bounds determined by the clipping rect. /// public bool IsVisible (Vector3 worldPos) { if (mAlpha < 0.001f) return false; if (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip) return true; UpdateTransformMatrix(); Vector3 pos = worldToLocal.MultiplyPoint3x4(worldPos); if (pos.x < mMin.x) return false; if (pos.y < mMin.y) return false; if (pos.x > mMax.x) return false; if (pos.y > mMax.y) return false; return true; } /// /// Returns whether the specified widget is visible by the panel. /// public bool IsVisible (UIWidget w) { UIPanel p = this; Vector3[] corners = null; while (p != null) { if ((p.mClipping == UIDrawCall.Clipping.None || p.mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen) { p = p.mParentPanel; continue; } if (corners == null) corners = w.worldCorners; if (!p.IsVisible(corners[0], corners[1], corners[2], corners[3])) return false; p = p.mParentPanel; } return true; } /// /// Whether the specified widget is going to be affected by this panel in any way. /// public bool Affects (UIWidget w) { if (w == null) return false; UIPanel expected = w.panel; if (expected == null) return false; UIPanel p = this; while (p != null) { if (p == expected) return true; if (!p.hasCumulativeClipping) return false; p = p.mParentPanel; } return false; } /// /// Causes all draw calls to be re-created on the next update. /// [ContextMenu("Force Refresh")] public void RebuildAllDrawCalls () { mRebuild = true; } /// /// Invalidate the panel's draw calls, forcing them to be rebuilt on the next update. /// This call also affects all children. /// public void SetDirty () { //刷新所有drawcall for (int i = 0, imax = drawCalls.Count; i < imax; ++i) drawCalls[i].isDirty = true; Invalidate(true, true); } /// /// Cache components. /// protected override void Awake () { base.Awake(); mHalfPixelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor); // Only DirectX 9 needs the half-pixel offset if (mHalfPixelOffset && SystemInfo.graphicsDeviceVersion.Contains("Direct3D")) mHalfPixelOffset = (SystemInfo.graphicsShaderLevel < 40); } /// /// Find the parent panel, if we have one. /// void FindParent () { Transform parent = cachedTransform.parent; mParentPanel = (parent != null) ? NGUITools.FindInParents(parent.gameObject) : null; #if FUNCELL_MODIFIED if (onParentChanged != null) onParentChanged(this); #endif } /// /// Find the parent panel, if we have one. /// public override void ParentHasChanged () { base.ParentHasChanged(); FindParent(); } /// /// Layer is used to ensure that if it changes, widgets get moved as well. /// protected override void OnStart () { mLayer = cachedGameObject.layer; } /// /// Reset the frame IDs. /// protected override void OnEnable () { mRebuild = true; mAlphaFrameID = -1; mMatrixFrame = -1; OnStart(); base.OnEnable(); mMatrixFrame = -1; } /// /// Mark all widgets as having been changed so the draw calls get re-created. /// protected override void OnInit () { if (idList.Contains(this.GetHashCode())) return; base.OnInit(); FindParent(); #if FUNCELL_MODIFIED /* // Apparently having a rigidbody helps #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (rigidbody == null && mParentPanel == null) #else if (GetComponent() == null && mParentPanel == null) #endif { UICamera uic = (anchorCamera != null) ? mCam.GetComponent() : null; if (uic != null) { if (uic.eventType == UICamera.EventType.UI_3D || uic.eventType == UICamera.EventType.World_3D) { Rigidbody rb = gameObject.AddComponent(); rb.isKinematic = true; rb.useGravity = false; } // It's unclear if this helps 2D physics or not, so leaving it disabled for now. // Note that when enabling this, the 'if (rigidbody == null)' statement above should be adjusted as well. //else //{ // Rigidbody2D rb = gameObject.AddComponent(); // rb.isKinematic = true; //} } } */ #else // Apparently having a rigidbody helps #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (rigidbody == null && mParentPanel == null) #else if (GetComponent() == null && mParentPanel == null) #endif { UICamera uic = (anchorCamera != null) ? mCam.GetComponent() : null; if (uic != null) { if (uic.eventType == UICamera.EventType.UI_3D || uic.eventType == UICamera.EventType.World_3D) { Rigidbody rb = gameObject.AddComponent(); rb.isKinematic = true; rb.useGravity = false; } // It's unclear if this helps 2D physics or not, so leaving it disabled for now. // Note that when enabling this, the 'if (rigidbody == null)' statement above should be adjusted as well. //else //{ // Rigidbody2D rb = gameObject.AddComponent(); // rb.isKinematic = true; //} } } #endif mRebuild = true; mAlphaFrameID = -1; mMatrixFrame = -1; list.Add(this); idList.Add(this.GetHashCode()); listNeedSort = true; #if FUNCELL_MODIFIED SelfUpdate(); #endif } /// /// Destroy all draw calls we've created when this script gets disabled. /// protected override void OnDisable () { for (int i = 0, imax = drawCalls.Count; i < imax; ++i) { UIDrawCall dc = drawCalls[i]; if (dc != null) UIDrawCall.Destroy(dc); } drawCalls.Clear(); //优化调用时长 //list.Remove(this); RemoveFromPanelList(list,idList, this); mAlphaFrameID = -1; mMatrixFrame = -1; if (list.Count == 0) { UIDrawCall.ReleaseAll(); mUpdateFrame = -1; } base.OnDisable(); } /// /// Update the world-to-local transform matrix as well as clipping bounds. /// void UpdateTransformMatrix () { int fc = Time.frameCount; if (cachedTransform.hasChanged) { mTrans.hasChanged = false; mMatrixFrame = -1; } if (mMatrixFrame != fc) { mMatrixFrame = fc; worldToLocal = mTrans.worldToLocalMatrix; Vector2 size = GetViewSize() * 0.5f; float x = mClipOffset.x + mClipRange.x; float y = mClipOffset.y + mClipRange.y; mMin.x = x - size.x; mMin.y = y - size.y; mMax.x = x + size.x; mMax.y = y + size.y; } } /// /// Update the edges after the anchors have been updated. /// protected override void OnAnchor () { // No clipping = no edges to anchor if (mClipping == UIDrawCall.Clipping.None) return; Transform trans = cachedTransform; Transform parent = trans.parent; Vector2 size = GetViewSize(); Vector2 offset = trans.localPosition; float lt, bt, rt, tt; // Attempt to fast-path if all anchors match if (leftAnchor.target == bottomAnchor.target && leftAnchor.target == rightAnchor.target && leftAnchor.target == topAnchor.target) { Vector3[] sides = leftAnchor.GetSides(parent); if (sides != null) { lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute; rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute; bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute; tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute; } else { // Anchored to a single transform Vector2 lp = GetLocalPos(leftAnchor, parent); lt = lp.x + leftAnchor.absolute; bt = lp.y + bottomAnchor.absolute; rt = lp.x + rightAnchor.absolute; tt = lp.y + topAnchor.absolute; } } else { // Left anchor point if (leftAnchor.target) { Vector3[] sides = leftAnchor.GetSides(parent); if (sides != null) { lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute; } else { lt = GetLocalPos(leftAnchor, parent).x + leftAnchor.absolute; } } else lt = mClipRange.x - 0.5f * size.x; // Right anchor point if (rightAnchor.target) { Vector3[] sides = rightAnchor.GetSides(parent); if (sides != null) { rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute; } else { rt = GetLocalPos(rightAnchor, parent).x + rightAnchor.absolute; } } else rt = mClipRange.x + 0.5f * size.x; // Bottom anchor point if (bottomAnchor.target) { Vector3[] sides = bottomAnchor.GetSides(parent); if (sides != null) { bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute; } else { bt = GetLocalPos(bottomAnchor, parent).y + bottomAnchor.absolute; } } else bt = mClipRange.y - 0.5f * size.y; // Top anchor point if (topAnchor.target) { Vector3[] sides = topAnchor.GetSides(parent); if (sides != null) { tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute; } else { tt = GetLocalPos(topAnchor, parent).y + topAnchor.absolute; } } else tt = mClipRange.y + 0.5f * size.y; } // Take the offset into consideration lt -= offset.x + mClipOffset.x; rt -= offset.x + mClipOffset.x; bt -= offset.y + mClipOffset.y; tt -= offset.y + mClipOffset.y; // Calculate the new position, width and height float newX = Mathf.Lerp(lt, rt, 0.5f); float newY = Mathf.Lerp(bt, tt, 0.5f); float w = rt - lt; float h = tt - bt; float minx = Mathf.Max(2f, mClipSoftness.x); float miny = Mathf.Max(2f, mClipSoftness.y); if (w < minx) w = minx; if (h < miny) h = miny; // Update the clipping range baseClipRegion = new Vector4(newX, newY, w, h); if(AnchorChanged != null) { AnchorChanged(cachedTransform); } } static int mUpdateFrame = -1; /// /// Update all panels and draw calls. /// #if FUNCELL_MODIFIED public static void PanelLateUpdate(int frameCount) { if (lateUpdateRate > 0 && frameCount % lateUpdateRate != 0) return; #if UNITY_EDITOR if (mUpdateFrame != frameCount || !Application.isPlaying) #else if (mUpdateFrame != frameCount) #endif { SortPanelList(); mUpdateFrame = Time.frameCount; // Update each panel in order for (int i = 0, imax = list.Count; i < imax; ++i) { list[i].UpdateSelf(); } int rq = 3100; // Update all draw calls, making them draw in the right order for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p.renderQueue == RenderQueue.Automatic) { if (p.startingRenderQueue != rq) { p.startingRenderQueue = rq; if (p.onRenderQueueChanged != null) p.onRenderQueueChanged(rq); } if (p.updateDrawCall) { p.UpdateDrawCalls(); } rq += p.drawCalls.Count; rq += 7; } else if (p.renderQueue == RenderQueue.StartAt) { if (p.updateDrawCall) { p.UpdateDrawCalls(); } if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count); } else // Explicit { if (p.updateDrawCall) { p.UpdateDrawCalls(); } if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + 1); } } } } #else void LateUpdate () { #if UNITY_EDITOR if (mUpdateFrame != Time.frameCount || !Application.isPlaying) #else if (mUpdateFrame != Time.frameCount) #endif { if (IsSuspend) return; SortPanelList(); mUpdateFrame = Time.frameCount; // Update each panel in order for (int i = 0, imax = list.Count; i < imax; ++i) list[i].UpdateSelf(); int rq = 3100; // Update all draw calls, making them draw in the right order for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p.renderQueue == RenderQueue.Automatic) { if (p.startingRenderQueue != rq) { p.startingRenderQueue = rq; #if FUNCELL_MODIFIED if(p.onRenderQueueChanged != null) p.onRenderQueueChanged(rq); #endif } p.UpdateDrawCalls(); rq += p.drawCalls.Count; rq += 5; } else if (p.renderQueue == RenderQueue.StartAt) { p.UpdateDrawCalls(); if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count); } else // Explicit { p.UpdateDrawCalls(); if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + 1); } } } } #endif /// /// Update the panel, all of its widgets and draw calls. /// void UpdateSelf () { #if FUNCELL_MODIFIED if (IsSuspend || (oldFinalAlpha <= 0f && finalAlpha <= 0f)) { updateDrawCall = false; return; } oldFinalAlpha = finalAlpha; updateDrawCall = true; #else if (IsSuspend) return; #endif UpdateTransformMatrix(); UpdateLayers(); UpdateWidgets(); if (mRebuild) { mRebuild = false; FillAllDrawCalls(); } else { for (int i = 0; i < drawCalls.Count; ) { UIDrawCall dc = drawCalls[i]; if (dc.isDirty && !FillDrawCall(dc)) { UIDrawCall.Destroy(dc); drawCalls.RemoveAt(i); continue; } ++i; } } if (mUpdateScroll) { mUpdateScroll = false; UIScrollView sv = GetComponent(); if (sv != null) sv.UpdateScrollbars(); } } /// /// Immediately sort all child widgets. /// public void SortWidgets () { mSortWidgets = false; widgets.Sort(UIWidget.PanelCompareFunc); } //优化NGUI GC static List widgetsInDrawCall = new List(); void FillDrawCallBuffers(UIDrawCall dc, int verticesCount) { dc.CheckCacke(verticesCount); for (int i = 0; i < widgetsInDrawCall.Count; ++i) { var widget = widgetsInDrawCall[i]; if (generateNormals) widget.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans); else widget.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null); } widgetsInDrawCall.Clear(); } //优化NGUI GC /// /// Fill the geometry fully, processing all widgets and re-creating all draw calls. /// public void FillAllDrawCalls() { for (int i = 0, max = drawCalls.Count; i < max; ++i) { UIDrawCall.Destroy(drawCalls[i]); } drawCalls.Clear(); Material mat = null; Texture tex = null; Shader sdr = null; #if FUNCELL_MODIFIED bool isGray = false; bool isFlowLight = false; bool isOverlay = false; Vector3Int flowColor = Vector3Int.zero; Vector3Int flowParam = Vector3Int.zero; #endif UIDrawCall dc = null; //优化NGUI GC int verticesCount = 0; //优化NGUI GC if (mSortWidgets) SortWidgets(); for (int i = 0, max = widgets.Count; i < max; ++i) { UIWidget w = widgets[i]; if (w.isVisible && w.hasVertices) { Material mt = w.material; Texture tx = w.mainTexture; Shader sd = w.shader; #if FUNCELL_MODIFIED bool ig = w.IsGray; bool ifl = w.IsFlowLight; bool iol = w.IsOverlay; Vector3Int ifc = w.FlowColor; Vector3Int ifp = w.FlowParam; #endif #if FUNCELL_MODIFIED if (mat != mt || tex != tx || sdr != sd || ig != isGray || iol != isOverlay || ifl != isFlowLight || (ifl && (ifc != flowColor || ifp != flowParam))) #else if (mat != mt || tex != tx || sdr != sd) #endif { //优化NGUI GC if (dc != null && verticesCount != 0) //#else //if (dc != null && dc.verts.size != 0) //优化NGUI GC { drawCalls.Add(dc); //优化NGUI GC FillDrawCallBuffers(dc, verticesCount); verticesCount = 0; //优化NGUI GC dc.UpdateGeometry(); dc.onRender = mOnRender; mOnRender = null; dc = null; } mat = mt; tex = tx; sdr = sd; #if FUNCELL_MODIFIED isGray = ig; isFlowLight = ifl; isOverlay = iol; flowColor = ifc; flowParam = ifp; #endif } if (mat != null || sdr != null || tex != null) { if (dc == null) { dc = UIDrawCall.Create(this, mat, tex, sdr); dc.depthStart = w.depth; dc.depthEnd = dc.depthStart; #if FUNCELL_MODIFIED dc.IsGray = w.IsGray; dc.IsFlowLight = w.IsFlowLight; dc.IsOverlay = w.IsOverlay; dc.FlowColor = w.FlowColor; dc.FlowParam = w.FlowParam; #endif dc.panel = this; } else { int rd = w.depth; if (rd < dc.depthStart) dc.depthStart = rd; if (rd > dc.depthEnd) dc.depthEnd = rd; } w.drawCall = dc; //#if !OPTIMISE_NGUI_GC_ALLOC //if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans, dc.uv2s); //else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null, dc.uv2s); //#else //优化NGUI GC if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } widgetsInDrawCall.Add(w); verticesCount += w.geometry.verts.size; //优化NGUI GC } } else w.drawCall = null; } //优化NGUI GC if (dc != null && verticesCount != 0) //#else //if (dc != null && dc.verts.size != 0) //优化NGUI GC { drawCalls.Add(dc); //优化NGUI GC FillDrawCallBuffers(dc, verticesCount); //优化NGUI GC dc.UpdateGeometry(); dc.onRender = mOnRender; mOnRender = null; } } UIDrawCall.OnRenderCallback mOnRender; /// /// Fill the geometry for the specified draw call. /// public bool FillDrawCall(UIDrawCall dc) { if (dc != null) { dc.isDirty = false; //优化NGUI GC int verticesCount = 0; //优化NGUI GC for (int i = 0; i < widgets.Count;) { UIWidget w = widgets[i]; if (w == null) { #if UNITY_EDITOR Debug.LogError("This should never happen"); #endif widgets.RemoveAt(i); continue; } if (w.drawCall == dc) { if (w.isVisible && w.hasVertices) { //#if !OPTIMISE_NGUI_GC_ALLOC //if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans, dc.uv2s); //else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null, dc.uv2s); if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } //优化NGUI GC widgetsInDrawCall.Add(w); verticesCount += w.geometry.verts.size; //优化NGUI GC } else w.drawCall = null; } ++i; } //#if !OPTIMISE_NGUI_GC_ALLOC //if (dc.verts.size != 0) //{ //优化NGUI GC if (verticesCount != 0) { FillDrawCallBuffers(dc, verticesCount); //优化NGUI GC dc.UpdateGeometry(); dc.onRender = mOnRender; mOnRender = null; return true; } } return false; } /// /// Update all draw calls associated with the panel. /// void UpdateDrawCalls () { if (IsSuspend) return; Transform trans = cachedTransform; bool isUI = usedForUI; if (clipping != UIDrawCall.Clipping.None) { drawCallClipRange = finalClipRegion; drawCallClipRange.z *= 0.5f; drawCallClipRange.w *= 0.5f; } else drawCallClipRange = Vector4.zero; int w = Screen.width; int h = Screen.height; // Legacy functionality if (drawCallClipRange.z == 0f) drawCallClipRange.z = w * 0.5f; if (drawCallClipRange.w == 0f) drawCallClipRange.w = h * 0.5f; // DirectX 9 half-pixel offset if (halfPixelOffset) { drawCallClipRange.x -= 0.5f; drawCallClipRange.y += 0.5f; } Vector3 pos; if (isUI) { Transform parent = cachedTransform.parent; pos = cachedTransform.localPosition; if (clipping != UIDrawCall.Clipping.None) { pos.x = Mathf.RoundToInt(pos.x); pos.y = Mathf.RoundToInt(pos.y); } if (parent != null) pos = parent.TransformPoint(pos); pos += drawCallOffset; } else pos = trans.position; Quaternion rot = trans.rotation; Vector3 scale = trans.lossyScale; for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; Transform t = dc.cachedTransform; t.position = pos; t.rotation = rot; t.localScale = scale; dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i; dc.alwaysOnScreen = alwaysOnScreen && (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip); dc.sortingOrder = mSortingOrder; dc.clipTexture = mClipTexture; } } /// /// Update the widget layers if the panel's layer has changed. /// void UpdateLayers () { // Always move widgets to the panel's layer if (mLayer != cachedGameObject.layer) { mLayer = mGo.layer; for (int i = 0, imax = widgets.Count; i < imax; ++i) { UIWidget w = widgets[i]; if (w && w.parent == this) w.gameObject.layer = mLayer; } ResetAnchors(); for (int i = 0; i < drawCalls.Count; ++i) drawCalls[i].gameObject.layer = mLayer; } } bool mForced = false; /// /// Update all of the widgets belonging to this panel. /// void UpdateWidgets() { bool changed = false; bool forceVisible = false; bool clipped = hasCumulativeClipping; if (!cullWhileDragging) { for (int i = 0; i < UIScrollView.list.size; ++i) { UIScrollView sv = UIScrollView.list[i]; if (sv.panel == this && sv.isDragging) forceVisible = true; } } if (mForced != forceVisible) { mForced = forceVisible; mResized = true; } var appIsPlaying = Application.isPlaying; // Update all widgets int frame = Time.frameCount; var thisHashCode = this.GetHashCode(); for (int i = 0, imax = widgets.Count; i < imax; ++i) { UIWidget w = widgets[i]; if(w.IsOnlyWidget) { continue; } // If the widget is visible, update it if (w.panel.GetHashCode() == thisHashCode && w.enabled) { #if UNITY_EDITOR // When an object is dragged from Project view to Scene view, its Z is... // odd, to say the least. Force it if possible. if (!appIsPlaying) { Transform t = w.cachedTransform; if (t.hideFlags != HideFlags.HideInHierarchy) { t = (t.parent != null && t.parent.hideFlags == HideFlags.HideInHierarchy) ? t.parent : null; } if (t != null) { for (; ; ) { if (t.parent == null) break; if (t.parent.hideFlags == HideFlags.HideInHierarchy) t = t.parent; else break; } if (t != null) { Vector3 pos = t.localPosition; pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); pos.z = 0f; if (Vector3.SqrMagnitude(t.localPosition - pos) > 0.0001f) t.localPosition = pos; } } } #endif // First update the widget's transform if (w.UpdateTransform(frame) || mResized) { // Only proceed to checking the widget's visibility if it actually moved #if FUNCELL_MODIFIED bool vis = forceVisible || (w.finalAlpha > 0.001f); #else bool vis = forceVisible || (w.CalculateCumulativeAlpha(frame) > 0.001f); #endif w.UpdateVisibility(vis, forceVisible || ((clipped || w.hideIfOffScreen) ? IsVisible(w) : true)); } // Update the widget's geometry if necessary if (w.UpdateGeometry(frame)) { changed = true; //Debug.Log("Geometry changed: " + w.name + " " + frame, w); if (!mRebuild) { // Find an existing draw call, if possible if (w.drawCall != null) w.drawCall.isDirty = true; else FindDrawCall(w); } } } } // Inform the changed event listeners if (changed && onGeometryUpdated != null) onGeometryUpdated(); mResized = false; } /// /// Insert the specified widget into one of the existing draw calls if possible. /// If it's not possible, and a new draw call is required, 'null' is returned /// because draw call creation is a delayed operation. /// public UIDrawCall FindDrawCall (UIWidget w) { if (w.GetType() == widgetType) { return null; } Material mat = w.material; Texture tex = w.mainTexture; int depth = w.depth; bool isGray = w.IsGray; bool isFlowLight = w.IsFlowLight; bool isOverlay = w.IsOverlay; for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; int dcStart = (i == 0) ? int.MinValue : drawCalls[i - 1].depthEnd + 1; int dcEnd = (i + 1 == drawCalls.Count) ? int.MaxValue : drawCalls[i + 1].depthStart - 1; if (dcStart <= depth && dcEnd >= depth) { if (dc.baseMaterial == mat && dc.mainTexture == tex && dc.IsGray == isGray && dc.IsFlowLight == isFlowLight && dc.IsOverlay == isOverlay ) { if (w.isVisible) { w.drawCall = dc; if (w.hasVertices) dc.isDirty = true; return dc; } } else mRebuild = true; return null; } } mRebuild = true; return null; } private static System.Type widgetType = typeof(UIWidget); /// /// Make the following widget be managed by the panel. /// public void AddWidget (UIWidget w) { #if FUNCELL_MODIFIED if(w.GetType() == widgetType && !w.hasBoxCollider) { w.IsOnlyWidget = true; } else { w.IsOnlyWidget = false; } #endif mUpdateScroll = true; if (widgets.Count == 0) { widgets.Add(w); } else if (mSortWidgets) { widgets.Add(w); SortWidgets(); } else if (UIWidget.PanelCompareFunc(w, widgets[0]) == -1) { widgets.Insert(0, w); } else { for (int i = widgets.Count; i > 0; ) { if (UIWidget.PanelCompareFunc(w, widgets[--i]) == -1) continue; widgets.Insert(i+1, w); break; } } FindDrawCall(w); } /// /// Remove the widget from its current draw call, invalidating everything as needed. /// public void RemoveWidget (UIWidget w) { //if (widgets.Remove(w) && w.drawCall != null) if (RemoveFromWidgetList(widgets, w) && w.drawCall != null) { int depth = w.depth; if (depth == w.drawCall.depthStart || depth == w.drawCall.depthEnd) mRebuild = true; w.drawCall.isDirty = true; w.drawCall = null; } } /// /// Immediately refresh the panel. /// public void Refresh () { mRebuild = true; mUpdateFrame = -1; #if FUNCELL_MODIFIED PanelLateUpdate(Time.frameCount); #else if (list.Count > 0) list[0].LateUpdate(); #endif } /// /// Calculate the offset needed to be constrained within the panel's bounds. /// public virtual Vector3 CalculateConstrainOffset (Vector2 min, Vector2 max) { Vector4 cr = finalClipRegion; float offsetX = cr.z * 0.5f; float offsetY = cr.w * 0.5f; Vector2 minRect = new Vector2(min.x, min.y); Vector2 maxRect = new Vector2(max.x, max.y); Vector2 minArea = new Vector2(cr.x - offsetX, cr.y - offsetY); Vector2 maxArea = new Vector2(cr.x + offsetX, cr.y + offsetY); if (softBorderPadding && clipping == UIDrawCall.Clipping.SoftClip) { minArea.x += mClipSoftness.x; minArea.y += mClipSoftness.y; maxArea.x -= mClipSoftness.x; maxArea.y -= mClipSoftness.y; } return NGUIMath.ConstrainRect(minRect, maxRect, minArea, maxArea); } /// /// Constrain the current target position to be within panel bounds. /// public bool ConstrainTargetToBounds (Transform target, ref Bounds targetBounds, bool immediate) { Vector3 min = targetBounds.min; Vector3 max = targetBounds.max; float ps = 1f; if (mClipping == UIDrawCall.Clipping.None) { UIRoot rt = root; if (rt != null) ps = rt.pixelSizeAdjustment; } if (ps != 1f) { min /= ps; max /= ps; } Vector3 offset = CalculateConstrainOffset(min, max) * ps; if (offset.sqrMagnitude > 0f) { if (immediate) { target.localPosition += offset; targetBounds.center += offset; SpringPosition sp = target.GetComponent(); if (sp != null) sp.enabled = false; } else { SpringPosition sp = SpringPosition.Begin(target.gameObject, target.localPosition + offset, 13f); sp.ignoreTimeScale = true; sp.worldSpace = false; } return true; } return false; } /// /// Constrain the specified target to be within the panel's bounds. /// public bool ConstrainTargetToBounds (Transform target, bool immediate) { Bounds bounds = NGUIMath.CalculateRelativeWidgetBounds(cachedTransform, target); return ConstrainTargetToBounds(target, ref bounds, immediate); } /// /// 对Panel的List进行排序 /// static public void SortPanelList() { if (listNeedSort) { list.Sort(CompareFunc); listNeedSort = false; } } /// /// Find the UIPanel responsible for handling the specified transform. /// static public UIPanel Find (Transform trans) { return Find(trans, false, -1); } /// /// Find the UIPanel responsible for handling the specified transform. /// static public UIPanel Find (Transform trans, bool createIfMissing) { return Find(trans, createIfMissing, -1); } /// /// Find the UIPanel responsible for handling the specified transform. /// static public UIPanel Find (Transform trans, bool createIfMissing, int layer) { UIPanel panel = NGUITools.FindInParents(trans); if (panel != null) return panel; while (trans.parent != null) trans = trans.parent; return createIfMissing ? NGUITools.CreateUI(trans, false, layer) : null; } /// /// Get the size of the game window in pixels. /// public Vector2 GetWindowSize () { UIRoot rt = root; Vector2 size = NGUITools.screenSize; if (rt != null) size *= rt.GetPixelSizeAdjustment(Mathf.RoundToInt(size.y)); return size; } /// /// Panel's size -- which is either the clipping rect, or the screen dimensions. /// public Vector2 GetViewSize () { if (mClipping != UIDrawCall.Clipping.None) return new Vector2(mClipRange.z, mClipRange.w); Vector2 size = NGUITools.screenSize; //UIRoot rt = root; //if (rt != null) size *= rt.pixelSizeAdjustment; return size; } public static bool RemoveFromWidgetList(List list, UIWidget widget) { if (widget == null) { return false; } var instId = widget.GetHashCode(); for (int i = 0, max = list.Count; i < max; ++i) { if (list[i].GetHashCode() == instId) { list.RemoveAt(i); return true; } } return false; } public static void RemoveFromPanelList(List list,List idList, UIPanel panel) { if(panel == null) { return; } var instId = panel.GetHashCode(); for (int i = 0, max = list.Count; i < max; ++i) { if(list[i].GetHashCode() == instId) { list.RemoveAt(i); break; } } idList.Remove(instId); } #if FUNCELL_MODIFIED public override void SelfCalculateFinalAlpha(float parentAlpha) { finalAlpha = parentAlpha * mAlpha; for (int i = 0; i < mChildren.size; ++i) { mChildren[i].SelfCalculateFinalAlpha(finalAlpha); } } protected override bool OnUpdate() { //updatealpha if (_oldAlpha != mAlpha) { _oldAlpha = mAlpha; var parentAlpha = 1f; if (parent != null) { parentAlpha = parent.finalAlpha; } SelfCalculateFinalAlpha(parentAlpha); } return true; } #endif #if UNITY_EDITOR /// /// Draw a visible pink outline for the clipped area. /// void OnDrawGizmos () { if (anchorCamera == null) return; bool clip = (mClipping != UIDrawCall.Clipping.None); Transform t = clip ? transform : mCam.transform; Vector3[] corners = worldCorners; for (int i = 0; i < 4; ++i) corners[i] = t.InverseTransformPoint(corners[i]); Vector3 pos = Vector3.Lerp(corners[0], corners[2], 0.5f); Vector3 size = corners[2] - corners[0]; GameObject go = UnityEditor.Selection.activeGameObject; bool isUsingThisPanel = (go != null) && (NGUITools.FindInParents(go) == this); bool isSelected = (UnityEditor.Selection.activeGameObject == gameObject); bool detailedView = (isSelected && isUsingThisPanel); bool detailedClipped = detailedView && mClipping == UIDrawCall.Clipping.SoftClip; Gizmos.matrix = t.localToWorldMatrix; #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (isUsingThisPanel && !clip && mCam.isOrthoGraphic) #else if (isUsingThisPanel && !clip && mCam.orthographic) #endif { UIRoot rt = root; if (rt != null && rt.scalingStyle != UIRoot.Scaling.Flexible) { float width = rt.manualWidth; float height = rt.manualHeight; float x0 = -0.5f * width; float y0 = -0.5f * height; float x1 = x0 + width; float y1 = y0 + height; corners[0] = new Vector3(x0, y0); corners[1] = new Vector3(x0, y1); corners[2] = new Vector3(x1, y1); corners[3] = new Vector3(x1, y0); Vector3 szPos = Vector3.Lerp(corners[0], corners[2], 0.5f); Vector3 szSize = corners[2] - corners[0]; Gizmos.color = new Color(0f, 0.75f, 1f); Gizmos.DrawWireCube(szPos, szSize); } } Gizmos.color = (isUsingThisPanel && !detailedClipped) ? new Color(1f, 0f, 0.5f) : new Color(0.5f, 0f, 0.5f); Gizmos.DrawWireCube(pos, size); if (detailedView) { if (detailedClipped) { Gizmos.color = new Color(1f, 0f, 0.5f); size.x -= mClipSoftness.x * 2f; size.y -= mClipSoftness.y * 2f; Gizmos.DrawWireCube(pos, size); } } } #endif // UNITY_EDITOR }