您的位置:首页 > 产品设计 > UI/UE

NGUI自动设置 Panel 深度、自动设置UIWidget(Sprite/Label等)深度(按照Hierarchy 顺序从上到下 Depth 递增)

2016-09-05 01:54 344 查看
最开始使用 NGUI的时候,一直在接收NGUI的各种设定。后面项目用UGUI,相比NGUI更方便些,但是可控性却少了,现在又开始新项目,重归NGUI。
但是又开始纠结Panel的深度管理。

项目中设计的是所有界面共用一个 UIRoot,就不用考虑 Camera的Depth问题。剩下的就是Panel的深度问题。
比如主界面设置 Depth 为1,那么背包界面自然设置为2,然后道具信息界面设置为3?
这是不确定的,因为背包界面可能有其它的子 Panel 。比如道具滑动页。
如果是一个人制作的话,会考虑到。但是项目中一般是多人协作,沟通起来会产生问题。
所以还是尝试在游戏中自动设置Panel的Depth。
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

最开始尝试在WindowManager中,每打开一个窗口,都遍历UIPanel,设置Depth,但是这样的话,动态加载的界面又不能照顾到。

然后在WindowManager的Update函数中,去遍历设置,这样是Ok的。
void Update()
{
Profiler.BeginSample("WindowManager Depth");

ProfilerTimer.BeginSample("WindowManager Depth");
int tmpNodeCount = GetNodeCount(mTransformUIRoot);
ProfilerTimer.EndSample();

Profiler.EndSample();

if (mChildrenCount !=tmpNodeCount )
{
//获取所有的Panel
UIPanel[] tmpPanels = mTransformUIRoot.GetComponentsInChildren<UIPanel>(true);

//遍历Panel,Depth 递增
for (int i = 0; i < tmpPanels.Length; i++)
{
tmpPanels[i].depth = mWindowPanelDepthBegin + i;
}
}

mWindowPanelDepthBegin = 1;
mChildrenCount = tmpNodeCount;

}

int GetNodeCount(Transform varTransform)
{
int tmpCount = varTransform.childCount;
for(int i=0;i<varTransform.childCount;i++)
{
tmpCount += varTransform.GetChild(i).childCount;
}
return tmpCount;
}

效率上其实并没有什么问题。但是心有总有疙瘩,而且这样没有通用性。
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

最后还是选择修改 UIPanel,在OnStart中,遍历修改Depth
/// <summary>
/// Layer is used to ensure that if it changes, widgets get moved as well.
/// </summary>

protected override void OnStart ()
{
mLayer = mGo.layer;

//获取所有的Panel
UIPanel[] tmpPanels = transform.root.GetComponentsInChildren<UIPanel>(true);

//遍历Panel,Depth 递增
for (int i = 0; i < tmpPanels.Length; i++)
{
tmpPanels[i].depth = 1 + i;
}

}
按照这种设置的话,在Hierarchy 顺序从上到下 ,Depth是递增的。在编辑器状态下也会执行。

又想到了其它问题。
在编辑器状态下,每次新建 UIPanel后都会自动排序。但是如果UIPanel的GameObject被拖动,那排序在编辑器状态下就失效了。所以,为了确保这种情况下也可以自动排序,就在 Update中也进行排序操作吧。
在UIPanel中添加下面代码。

protected override void OnUpdate()
{
    base.OnUpdate();

#if UNITY_EDITOR

    if(Application.isPlaying==false)
    {
        //获取所有的Panel
        UIPanel[] tmpPanels = transform.root.GetComponentsInChildren<UIPanel>(true);

        //遍历Panel,Depth 递增
        for (int i = 0; i < tmpPanels.Length; i++)
        {
            tmpPanels[i].depth = 1 + i;
        }
    }
#endif
}这样不管怎么拖动,Panel都会自动设置了。
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

Panel的自动排序设置好了,下面来看下 Sprite、Label这些 UIWidget 的自动排序。
因为对于UIWidget来说,都是以Panel 为父节点的。所以这里的UIWidget排序都是对一个Panel下的UIWidget排序。
而且一般我们做好Prefab之后,很少在游戏中去改变 UIWidget的Depth。一般没有这个必要。
所以对于UIWidget,我这里只做编辑器状态下的排序。
修改 UIWidget 代码
/// <summary>
/// Ensure we have a panel to work with.
/// </summary>

protected override void OnUpdate ()
{
    if (panel == null) CreatePanel();
#if UNITY_EDITOR
    else if (!mPlayMode) ParentHasChanged();

    if(Application.isPlaying==false)
    {
        //获取所有的UIWidget
        Transform tmpRootPanel = GetRootPanel(transform);
        UIWidget[] tmpWidgets = tmpRootPanel.GetComponentsInChildren<UIWidget>(true);

        //遍历UIWidget,Depth 递增
        for (int i = 0; i < tmpWidgets.Length; i++)
        {
            tmpWidgets[i].depth = 1 + i;
        }
    }
#endif
}

Transform GetRootPanel(Transform varTransform)
{
    Transform tmpParent=varTransform.parent;
    if(tmpParent!=null)
    {
        if(tmpParent.GetComponent<UIPanel>()!=null)
        {
            return tmpParent;
        }
        else
        {
            tmpParent = GetRootPanel(tmpParent);
        }
        return tmpParent;
    }
    else
    {
        return varTransform;
    }
}


效果是这样



现在应该已经可以不用在编辑器调整 Depth了,那就在编辑器中隐藏 Depth的设置按钮吧
首先是Panel的,修改 UIPanelInspector 代码,注释掉Depth 设置按钮区域
protected override bool ShouldDrawProperties ()
{
float alpha = EditorGUILayout.Slider("Alpha", mPanel.alpha, 0f, 1f);

if (alpha != mPanel.alpha)
{
NGUIEditorTools.RegisterUndo("Panel Alpha", mPanel);
mPanel.alpha = alpha;
}

//GUILayout.BeginHorizontal();
//{
// EditorGUILayout.PrefixLabel("Depth");

// int depth = mPanel.depth;
// if (GUILayout.Button("Back", GUILayout.Width(60f))) --depth;
// depth = EditorGUILayout.IntField(depth, GUILayout.MinWidth(20f));
// if (GUILayout.Button("Forward", GUILayout.Width(68f))) ++depth;

// if (mPanel.depth != depth)
// {
// NGUIEditorTools.RegisterUndo("Panel Depth", mPanel);
// mPanel.depth = depth;

// if (UIPanelTool.instance != null)
// UIPanelTool.instance.Repaint();

// if (UIDrawCallViewer.instance != null)
// UIDrawCallViewer.instance.Repaint();
// }
//}
//GUILayout.EndHorizontal();


然后是UIWidget的,修改UIWidgetInspector,注释掉 Depth 设置区域
/// <summary>
/// Draw widget's depth.
/// </summary>

static void DrawDepth (SerializedObject so, UIWidget w, bool isPrefab)
{
if (isPrefab) return;

GUILayout.Space(2f);
//GUILayout.BeginHorizontal();
//{
// EditorGUILayout.PrefixLabel("Depth");

// if (GUILayout.Button("Back", GUILayout.MinWidth(46f)))
// {
// foreach (GameObject go in Selection.gameObjects)
// {
// UIWidget pw = go.GetComponent<UIWidget>();
// if (pw != null) pw.depth = w.depth - 1;
// }
// }

// NGUIEditorTools.DrawProperty("", so, "mDepth", GUILayout.MinWidth(20f));

// if (GUILayout.Button("Forward", GUILayout.MinWidth(60f)))
// {
// foreach (GameObject go in Selection.gameObjects)
// {
// UIWidget pw = go.GetComponent<UIWidget>();
// if (pw != null) pw.depth = w.depth + 1;
// }
// }
//}
//GUILayout.EndHorizontal();

int matchingDepths = 1;

UIPanel p = w.panel;

if (p != null)
{
for (int i = 0, imax = p.widgets.Count; i < imax; ++i)
{
UIWidget pw = p.widgets[i];
if (pw != w && pw.depth == w.depth)
++matchingDepths;
}
}

if (matchingDepths > 1)
{
EditorGUILayout.HelpBox(matchingDepths + " widgets are sharing the depth value of " + w.depth, MessageType.Info);
}
}
就是这样了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐