• 一、前言 层级菜单在Unity中用到的并不多,主要是做分类的时候用的比较多,今天就给大家分享几个层级代码,扩充一下,写成插件也是不错的。 首先看一下效果吧: ...【Unity3D】UGUI实现层级菜单 第一种实...

    一、前言

    层级菜单在Unity中用到的并不多,主要是做分类的时候用的比较多,今天就给大家分享几个层级代码,扩充一下,写成插件也是不错的。

    首先看一下效果吧:
    1.
    在这里插入图片描述
    2.
    在这里插入图片描述
    3.
    在这里插入图片描述
    在这里插入图片描述
    4.
    在这里插入图片描述
    5.
    在这里插入图片描述

    二、资源下载

    源文件:
    源文件下载
    Github下载地址:
    LayerMenu.unitypackage

    三、正文

    第一种实现效果

    在这里插入图片描述
    实现原理:这个是用系统自带的UGUI Scroll View组件,脚本控制创建父物体,父物体身上挂载有初始化子物体的脚本
    优缺点:
    优点是实现简单,不需要多与的插件,代码量也不大,控制比较方便
    缺点是只能实现两个层级的显示
    实现过程:
    1、新建一个Scrpll View
    在这里插入图片描述
    2、制作预制体
    界面就这么设计就行:
    在这里插入图片描述

    名字改一下
    Content:父节点容器
    ParentMenu:父节点
    TextParent:父节点文本
    ChildMenu:子节点容器
    item:子节点
    TextChild:子节点文本
    在这里插入图片描述
    然后将父节点改名字叫parentMenu,做成预制体:
    在这里插入图片描述
    预制体放到Resources文件夹中:
    在这里插入图片描述
    将子物体也制作成预制体:
    在这里插入图片描述
    3、编写脚本ParentMenu.cs
    这个脚本主要是作用是创建子物体:

    using System.Collections;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class ParentMenu : MonoBehaviour
    {
        private GameObject childMenu;//子菜单的parent
        private RectTransform[] childs;//所有子菜单的rect
        private RectTransform itemRect;//子菜单的prefab
        private Vector3 offset;//单个子菜单的高度
        private int count;//子菜单的个数
        public bool isOpening { get; private set; }//父菜单是否展开
        public bool isCanClick { get; set; }//父菜单是否可以点击
    
        public void Init(RectTransform rect, int count)
        {
            //找到子节点
            childMenu = transform.Find("childMenu").gameObject;
            itemRect = rect;
            this.count = count;
            childs = new RectTransform[this.count];
            offset = new Vector3(0, itemRect.rect.height);
            for (int i = 0; i < this.count; i++)
            {
                childs[i] = Instantiate(itemRect, childMenu.transform);
            }
            childMenu.gameObject.SetActive(false);
            isOpening = false;
            isCanClick = true;
            GetComponent<Button>().onClick.AddListener(OnButtonClick);
        }
    
        void OnButtonClick()
        {
            if (!isCanClick) return;
            if (!isOpening)
                StartCoroutine(ShowChildMenu());
            else
                StartCoroutine(HideChildMenu());
        }
    
        IEnumerator ShowChildMenu()
        {
            childMenu.gameObject.SetActive(true);
            for (int i = 0; i < count; i++)
            {
                childs[i].localPosition -= i * offset;
                yield return new WaitForSeconds(0.1f);
            }
            isCanClick = true;
            isOpening = true;
        }
    
        IEnumerator HideChildMenu()
        {
            for (int i = count - 1; i >= 0; i--)
            {
                childs[i].localPosition += i * offset;
                yield return new WaitForSeconds(0.1f);
            }
            childMenu.gameObject.SetActive(false);
            isCanClick = true;
            isOpening = false;
        }
    }
    
    

    4、编写脚本FoldableMenu.cs
    这个脚本主要是为了创建父物体,以及控制折叠菜单

    using System.Collections;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class FoldableMenu : MonoBehaviour
    {
        private RectTransform content;//父物体的parent
        private TextAsset textAsset;//所有菜单信息
        private RectTransform parentRect;//父菜单的prefab
        private RectTransform[] parentArr;//所有父菜单的数组
        private RectTransform childRect;//子菜单的prefab
        private Vector3 parentOffset;//单个父菜单的高度
        private Vector3 childOffset;//单个父菜单的高度
        private int[] cntArr;//所有父菜单拥有的子菜单个数
    
        void Awake()
        {
            Init();
        }
    
        void Init()
        {
            //获取到父节点
            content = transform.Find("Viewport/Content").GetComponent<RectTransform>();
            //获取到menuinfo里面的信息  3 3 4 4 5 5
            textAsset = Resources.Load<TextAsset>("menuInfo");
            //获取到父物体 设置父物体的高度
            parentRect = Resources.Load<RectTransform>("parentMenu");
            parentOffset = new Vector3(0, parentRect.rect.height);
            //获取到子物体 设置子物体的高度
            childRect = Resources.Load<RectTransform>("item");
            childOffset = new Vector3(0, childRect.rect.height);
            //分割字符串 info = 3 3 4 4 5 5
            var info = textAsset.text.Split(',');//获取子菜单个数信息
            //数组的长度
            cntArr = new int[info.Length];
            //父菜单的数组
            parentArr = new RectTransform[info.Length];
            //初始化content高度 宽度不变 高度是所有父物体的总长
            content.sizeDelta = new Vector2(content.rect.width, parentArr.Length * parentRect.rect.height);
            //i = 6
            for (int i = 0; i < cntArr.Length; i++)
            {
                //创建服务器
                parentArr[i] = Instantiate(parentRect, content.transform);
                //坐标为 上一个父物体的宽度
                parentArr[i].localPosition -= i * parentOffset;
                //赋值
                cntArr[i] = int.Parse(info[i]);
                //父物体上面加载子物体 子物体数量为3 3 4 4 5 5
                parentArr[i].GetComponent<ParentMenu>().Init(childRect, cntArr[i]);
                int j = i;
                //父物体上面的button绑定事件
                parentArr[i].GetComponent<Button>().onClick.AddListener(() => { OnButtonClick(j); });
            }
        }
    
        void OnButtonClick(int i)
        {
            //如果iscanclick为false则return  因为已经点击过了 不能再点击了 除非升起来的时候将isCanClick改为true
            if (!parentArr[i].GetComponent<ParentMenu>().isCanClick)
                return;
            parentArr[i].GetComponent<ParentMenu>().isCanClick = false;
            //isopening 为true 执行 menuup 为flase执行menuDown
            if (!parentArr[i].GetComponent<ParentMenu>().isOpening)
                StartCoroutine(MenuDown(i));
            else
                StartCoroutine(MenuUp(i));
        }
    
        IEnumerator MenuDown(int index)
        {       
            for (int i = 0; i < cntArr[index]; i++)
            {
                //更新content高度
                content.sizeDelta = new Vector2(content.rect.width,
                    content.rect.height + childOffset.y);
                for (int j = index + 1; j < parentArr.Length; j++)
                {
                    parentArr[j].localPosition -= childOffset;
                }
                yield return new WaitForSeconds(0.1f);
            }     
        }
    
        IEnumerator MenuUp(int index)
        {
            for (int i = 0; i < cntArr[index]; i++)
            {
                //更新content高度
                content.sizeDelta = new Vector2(content.rect.width,
                    content.rect.height - childOffset.y);
                for (int j = index + 1; j < parentArr.Length; j++)
                {
                    parentArr[j].localPosition += childOffset;
                }
                yield return new WaitForSeconds(0.1f);
            }
        }
    }
    
    

    将这个脚本挂载到Scroll View上面:
    在这里插入图片描述
    运行,搞定!

    第二种实现效果

    在这里插入图片描述
    实现原理:这个也是用UGUI做的,不一样的是不需要容器组件,主要是寻找父节点,然后保存父节点的信息,下一个节点以父节点为目标进行偏移,或者以父节点为目标做子节点
    优缺点:
    优点是代码清晰,可扩展性强,不需要设计UGUI
    缺点结构比较简单,没有实现多层级的功能
    实现过程:
    1、创建预制体
    在这里插入图片描述
    结构比较简单,两个Image,箭头的图片带Button组件(可以下拉和合并)
    然后将预制体放到Resources文件夹中:
    在这里插入图片描述
    2、编写PublicData.cs脚本
    一个数据类

    using UnityEngine;
    
    public class PublicData
    {
        public static Transform parent;
        public static Vector2 currentPosition;
    }
    
    

    3、编写脚本Options_Triangle.cs
    初始化子节点的函数

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class Options_Triangle : MonoBehaviour
    {
        public Button triangle;
        public Image content;
        public List<Transform> children = new List<Transform>();
        void Start()
        {
            triangle.onClick.AddListener(() =>
            {
                if (triangle.transform.eulerAngles.z == 270)
                {
                    triangle.transform.eulerAngles = Vector3.zero;
                    for (int i = 0; i < children.Count; i++)
                    {
                        children[i].gameObject.SetActive(false);
                    }
                }
                else
                {
                    triangle.transform.eulerAngles = new Vector3(0, 0, -90);
                    for (int i = 0; i < children.Count; i++)
                    {
                        children[i].gameObject.SetActive(true);
                    }
                }
            });
    
        }
    }
    
    

    4、编写ClickEvent.cs
    这是一个层级菜单的编辑功能的脚本

    using UnityEngine;
    using UnityEngine.UI;
    
    public class ClickEvent : MonoBehaviour
    {
        public Button add_options_t;
        public Button add_options;
        public Transform canvasParent;
    
        void Start()
        {
            add_options_t.onClick.AddListener(() =>
            {
                if (PublicData.parent == null)
                {
                    PublicData.parent = Instantiate(Resources.Load<Transform>("Options_triangle"));
                    PublicData.parent.transform.SetParent(canvasParent, false);
                    PublicData.currentPosition = new Vector2(PublicData.parent.position.x, PublicData.parent.position.y);
                }
                else
                {
                    Transform option = Instantiate(Resources.Load<Transform>("Options_triangle"));
                    option.transform.SetParent(PublicData.parent, false);
                    option.transform.position = new Vector3(PublicData.currentPosition.x + 30, PublicData.currentPosition.y - 32, 0);
                    PublicData.parent.GetComponent<Options_Triangle>().triangle.transform.eulerAngles = new Vector3(0, 0, -90);
                    PublicData.parent.GetComponent<Options_Triangle>().children.Add(option);
                    PublicData.parent = option;
                    PublicData.currentPosition = new Vector2(PublicData.parent.position.x, PublicData.parent.position.y);
                }
    
            });
            add_options.onClick.AddListener(() =>
            {
                if (PublicData.parent == null)
                {
                    return;
                }
                PublicData.parent.GetComponent<Options_Triangle>().triangle.transform.eulerAngles = new Vector3(0, 0, -90);
                Transform content = Instantiate(Resources.Load<Transform>("Options"));
                content.transform.SetParent(PublicData.parent, false);
                content.transform.position = new Vector3(PublicData.currentPosition.x + 16, PublicData.currentPosition.y - 32, 0);
                PublicData.parent.GetComponent<Options_Triangle>().children.Add(content);
                PublicData.currentPosition = new Vector2(content.position.x - 16, content.position.y);
    
            });
        }
    }
    
    

    OK。将ClickEvent脚本挂载在场景中的任一物体身上就可以了

    第三种实现效果

    在这里插入图片描述
    实现原理:这个也是用UGUI做的,比较有特点的地方是没有使用一行代码,使用VerticalLayoutGroup和ContentSizeFitter组件的自动排序功能和Button的OnClick组件控制子物体的显示与隐藏来实现层级菜单的功能。
    优缺点:
    优点是不需要代码控制,简单易用
    缺点是需要提前堆砌UI,工作量比较大,然后改动的时候耗费精力大
    实现过程:
    1、新建Scroll View
    在这里插入图片描述
    2、父节点
    在这里插入图片描述
    在这里插入图片描述
    父节点有一个Button和一个隐藏的Image

    Button
    在这里插入图片描述
    有两个功能
    在这里插入图片描述
    第一个就是显示跟自己位置坐标一样的子物体BtnSelecteStyle,因为BtnSelecteStyle是Button的子物体,所以BtnSelecteStyle就会挡住Button,为啥要挡住呢,因为还需要BtnSelecteStyle的OnClick将子节点收起来
    BtnSelecteStyle的OnClick挂载的功能:
    在这里插入图片描述
    第二个就是显示子节点的容器也就是ImgBtnParentLayout

    这个ImgBtnParentLayout就是子节点的容器
    在这里插入图片描述
    下面是几个子节点
    在这里插入图片描述

    OK。可以了

    第四种实现效果

    在这里插入图片描述
    实现原理:这个是用代码动态生成的,其中一个脚本主要用来创建父物体和子物体,以及父级关系,另一个脚本是设置位置,箭头变化,按钮功能的初始化
    优缺点:
    优点是代码清晰,结构明了,可以实现层级多级显示、多级目录的设置、树级菜单等
    缺点是没有判断最后一个节点的代码,最后一个节点无法设置图片,最后一个节点的功能没有添加
    实现过程:
    1、首先也是制作预制体
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ArrowButton和ArrowButton2都是为了控制子节点的关闭和显示,不同的是ArrowButton是左边的小按钮,还有一个图片显示的功能,ArrowButton2是整体的按钮,不显示,但是点击整体都可以实现显示和隐藏子节点的功能

    资源:
    在这里述
    在这里插入图片描述
    在这里插入图片描述
    图片是白的,仔细看一下还是能看到的 - -,然后保存下载,放到项目中去

    2、编写脚本ItemPanelBase.cs
    这个脚本是设置节点的位置,以及箭头切换的脚本

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public enum NameSort
    {
        Default,
        Active,
        Passive
    }
    public class ItemPanelBase : MonoBehaviour
    {
        private List<ItemPanelBase> childList;//子物体集合
        [HideInInspector]
        public Button downArrow;//下箭头按钮
        public Button downArrow2;//下箭头按钮
        public Sprite down, right, dot;
        public bool isOpen { get; set; }//子物体开启状态
        private Vector2 startSize;//起始大小
    
        NameSort m_NameSore = NameSort.Default;
        string m_Name;
    
        private void Awake()
        {
            childList = new List<ItemPanelBase>();
            downArrow = this.transform.Find("ContentPanel/ArrowButton").GetComponent<Button>();
            downArrow.onClick.AddListener(() =>
            {
                if (isOpen)
                {
                    CloseChild();
                    isOpen = false;
                }
                else
                {
                    OpenChild();
                    isOpen = true;
                }
            });
            downArrow2 = this.transform.Find("ContentPanel/ArrowButton2").GetComponent<Button>();
            downArrow2.onClick.AddListener(() =>
            {
                if (isOpen)
                {
                    CloseChild();
                    isOpen = false;
                }
                else
                {
                    OpenChild();
                    isOpen = true;
                }
            });
            startSize = this.GetComponent<RectTransform>().sizeDelta;
            isOpen = false;
        }
    
        //添加子物体到集合
        private void AddChild(ItemPanelBase parentItemPanelBase)
        {
            childList.Add(parentItemPanelBase);
            if (childList.Count >= 1)
            {
                downArrow.GetComponent<Image>().sprite = right;
            }
        }
    
        //设置当前对象的名字值
        public void SetName(string _name,NameSort m_sort)
        {
            m_Name = _name;
            m_NameSore = m_sort;
        }
    
        /// <summary>
        /// 设置父物体,父物体不为一级菜单
        /// </summary>
        /// <param name="parentItemPanelBase"></param>
        public void SetItemParent(ItemPanelBase parentItemPanelBase)
        {
            this.transform.parent = parentItemPanelBase.transform;
            parentItemPanelBase.AddChild(this);
            this.GetComponent<VerticalLayoutGroup>().padding = new RectOffset((int)parentItemPanelBase.downArrow.GetComponent<RectTransform>().sizeDelta.x, 0, 0, 0);
            if (parentItemPanelBase.isOpen)
            {
    
                this.GetComponent<ItemPanelBase>().AddParentSize((int)this.gameObject.GetComponent<RectTransform>().sizeDelta.y);
            }
            else
            {
                this.transform.gameObject.SetActive(false);
            }
        }
    
        /// <summary>
        /// 设置父物体,父物体为一级菜单
        /// </summary>
        /// <param name="tran"></param>
        public void SetBaseParent(Transform tran)
        {
            this.transform.parent = tran;
        }
    
        /// <summary>
        /// 填充Item数据
        /// </summary>
        /// <param name="_name">名字</param>
        public void InitPanelContent(string _name)
        {
            transform.Find("ContentPanel/Text").GetComponent<Text>().text = _name;
        }
    
        /// <summary>
        /// 增加一个子物体后更新Panel大小
        /// </summary>
        /// <param name="change"></param>
        public void UpdateRectTranSize(int change)
        {
            this.gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(startSize.x, this.gameObject.GetComponent<RectTransform>().sizeDelta.y + change);
        }
        /// <summary>
        /// 增加父物体高度
        /// </summary>
        /// <param name="parentItem"></param>
        /// <param name="change"></param>
        public void AddParentSize(int change)
        {
            if (this.transform.parent.GetComponent<ItemPanelBase>() != null)
            {
                this.transform.parent.GetComponent<ItemPanelBase>().UpdateRectTranSize(change);
                this.transform.parent.GetComponent<ItemPanelBase>().AddParentSize(change);
            }
        }
    
        /// <summary>
        /// 关闭子物体列表
        /// </summary>
        public void CloseChild()
        {
            if (childList.Count == 0) return;
            foreach (ItemPanelBase child in childList)
            {
                child.gameObject.SetActive(false);
                child.GetComponent<ItemPanelBase>().AddParentSize(-(int)child.gameObject.GetComponent<RectTransform>().sizeDelta.y);
            }
            downArrow.GetComponent<Image>().sprite = right;
        }
    
        /// <summary>
        /// 打开子物体列表
        /// </summary>
        public void OpenChild()
        {
            if (childList.Count == 0)
            {
                if (m_Name == "125K读卡器" && m_NameSore == NameSort.Active)
                {
                    Debug.Log("125k设备");
                }
                return;
            }
    
            foreach (ItemPanelBase child in childList)
            {
                child.gameObject.SetActive(true);
                child.GetComponent<ItemPanelBase>().AddParentSize((int)child.gameObject.GetComponent<RectTransform>().sizeDelta.y);
            }
            downArrow.GetComponent<Image>().sprite = down;
    
        }
    }
    
    

    3、编写脚本PullDownList.cs
    这个就是创建层级菜单的脚本:
    比较繁琐

    using System.Collections.Generic;
    using UnityEngine;
    
    public class PullDownList : MonoBehaviour
    {
        private List<GameObject> itemPanelList;
        public GameObject itemPanel;
    
        private void Awake()
        {
            itemPanelList = new List<GameObject>();
        }
    
        void Start()
        {
            for (int i = 0; i < 27; i++)
            {
                //一级菜单
                if(i == 0)
                {
                    GameObject newItemPanel = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel);
                    newItemPanel.GetComponent<ItemPanelBase>().SetBaseParent(this.transform);
                    newItemPanel.GetComponent<ItemPanelBase>().InitPanelContent("层级一");
                }
                //二级菜单
                if (i == 1)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[0].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级二");
                }
                else if (i == 2)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[0].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级二");
                }
                //三级菜单
                else if (i == 3)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[1].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 4)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[1].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 5)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[1].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 6)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[1].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 7)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[2].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 8)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[2].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 9)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[2].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                else if (i == 10)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[2].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级三");
                }
                //四级菜单
                else if (i == 11)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[3].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 12)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[3].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 13)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[4].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 14)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[4].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 15)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[5].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 16)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[5].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 17)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[6].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 18)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[6].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Active);
                }
                else if (i == 19)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[7].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 20)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[7].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 21)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[8].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 22)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[8].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 23)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[9].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 24)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[9].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 25)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[10].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
                else if (i == 26)
                {
                    GameObject newItemPanel2 = Instantiate(itemPanel);
                    itemPanelList.Add(newItemPanel2);
                    newItemPanel2.GetComponent<ItemPanelBase>().SetItemParent(itemPanelList[10].GetComponent<ItemPanelBase>());
                    newItemPanel2.GetComponent<ItemPanelBase>().InitPanelContent("层级四");
                    newItemPanel2.GetComponent<ItemPanelBase>().SetName("层级四", NameSort.Passive);
                }
            }
        }
    }
    
    

    将脚本挂载在Panel上面
    在这里插入图片描述

    OK,大功告成

    第五种实现效果

    在这里插入图片描述
    实现原理:这个是用UI硬堆砌起来的层级菜单,然后通过代码控制对象的隐藏和显示,即可实现层级菜单的折叠与下拉功能,主要用到GridLayoutGroup组件来排序与更新
    优缺点:
    优点是操作简单,代码也简单,不需要太多的理解,然后可以显示多级菜单,多级内容,以及最后一个节点的功能与图片的设置功能
    缺点是需要提前堆砌UI,可扩容性差,前期工作量大,然后后期修改工作量大,最重要的是我觉得这种实现方式蛮low的
    实现过程:
    1、显示制作UI
    Panel上面挂载GridLayoutGroup组件
    在这里插入图片描述
    制作UI
    在这里插入图片描述
    在这里插入图片描述
    UI的话就很简单,一个Button下面两个子物体一个text一个Image,text是显示内容,image是显示箭头

    这时候就有人问了,那子物体怎么办,子物体也是同样的结构在这里插入图片描述
    就是把image往后拉了一下

    三级菜单也一样:
    在这里插入图片描述
    再加一个一级菜单:
    在这里插入图片描述

    是不是so easy…哈哈哈 真的好low

    脚本功能就很简单
    一级菜单控制它往下的所有子节点的隐藏于显示
    在这里插入图片描述
    二级菜单控制它往下的所有子节点的隐藏于显示
    在这里插入图片描述

    以此类推。。。。

    2、编辑代码PullDown.cs

    using UnityEngine;
    using UnityEngine.UI;
    
    public class PullDown : MonoBehaviour
    {
        public Button m_Btn1;//一级菜单按钮
        public Button m_Btn2;//二级菜单按钮
        public Button m_Btn3;//三级菜单按钮
    
        bool m_is1;//全局参数 控制开关
        bool m_is2;//全局参数 控制开关
    
        void Start()
        {
            m_is1 = true;
            m_is2 = true;
            m_Btn1.onClick.AddListener(Btn1_Event);
            m_Btn2.onClick.AddListener(Btn2_Event);
        }
    
        public void Btn1_Event()
        {
            if (m_is1)
            {
                m_Btn2.gameObject.SetActive(false);
                m_Btn3.gameObject.SetActive(false);
                m_is1 = false;
            }
            else
            {
                m_Btn2.gameObject.SetActive(true);
                m_Btn3.gameObject.SetActive(true);
                m_is1 = true;
            }
        }
    
        public void Btn2_Event()
        {
            if (m_is2)
            {
                m_Btn3.gameObject.SetActive(false);
                m_is2 = false;
            }
            else
            {
                m_Btn3.gameObject.SetActive(true);
                m_is1 = true;
            }
        }
    }
    

    OK了,快去试试吧

    展开全文
  • 在使用unity3d开发游戏项目时,层级的问题往往伴随着UI的开发,而在引入了3D模型、粒子特效后,层级的问题就变得有些扑朔迷离了,甚至会牵扯到Unity的渲染顺序。本篇主要从UGUI的角度出发,浅析UGUI中影响层级的因素...

    0x00 写在前面
    在使用unity3d开发游戏项目时,层级的问题往往伴随着UI的开发,而在引入了3D模型、粒子特效后,层级的问题就变得有些扑朔迷离了,甚至会牵扯到Unity的渲染顺序。本篇主要从UGUI的角度出发,浅析UGUI中影响层级的因素。后续会分析UI与3D对象,UI与粒子特效之间层级的关系。

    0x01 影响层级的因素
    前提条件:
    - Camera-Clear Flags
    - Canvas-Render Mode

    影响层级的因素:

    • Camera
      • depth
    • Canvas
      • Hierarchy中的排列顺序
      • sorting layer
        • order in layer
    • Shader中的RenderQueue

    0x02 Camera中的Clear Flags
    skybox
    屏幕上的空白处将会以以当前camera的skybox填充。
    solid color
    屏幕上的空白处将会以当前camera的background color填充。
    Depth only
    每次绘制前,只是清空深度缓冲区,但是并没有清空颜色缓冲区。(一般适用于多个camera的情况)
    Don’t Clear
    该模式不清除任何颜色或者深度缓存。每帧绘制在下一帧之上,造成涂片效果

    camera的clear Flags选定Don’t Clear 或者 当我们只有一个camera时选定Depth only 会出现以下涂片效果:
    涂片效果]

    参考资料:https://docs.unity3d.com/Manual/class-Camera.html

    0x03 Canvas的Render Mode
    Render Mode主要用于定义UI如何渲染于屏幕之上。通常一个Scene只需一个Canvas即可,不过Canvas自身也是支持嵌套的,默认情况下,子Canvas与父Canvas的Render Mode保持一致。
    Screen Space-Overlay
    此模式下,Canvas会被缩放以适应屏幕,然后直接渲染到屏幕上,无需任何摄像机。屏幕尺寸或者分辨率改变了,UI会自动进行缩放,UI会覆盖所有其他摄像机的画面。
    这里写图片描述
    该模式下需要特别注意:Canvas需要放在Hierarchy所有元素的顶层,否则UI可能会从视图中消失。这是Unity内置的限制。
    原文:Note: The Screen Space - Overlay canvas needs to be stored at the top level of the hierarchy. If this is not used then the UI may disappear from the view. This is a built-in limitation. Keep the Screen Space - Overlay canvas at the top level of the hierarchy to get expected results.


    Screen Space-Camera
    此模式下,Canvas会渲染于摄像机前面指定距离的一个平面上。UI在屏幕上的大小并不随此距离变化而变化(有点像正交投影)。场景中的物件可能与UI遮挡。
    [图片-Camera]


    World Space
    此模式下,UI被看作是场景中的一个平面物体。UI此时可以不朝向Camera,其他场景中的物件除了可以与UI遮挡外,还可能与UI穿插。
    [图片-World]
    参考资料:https://docs.unity3d.com/Manual/class-Canvas.html

    0x04 UI与3D物体
    通常的游戏项目会采用两个Camera,一个UICamera用于绘制UI,一个GameCamera用于绘制游戏中的3D对象。这时候就引入了新的复杂度,多个Camera如何管理,又如何协同工作的问题。不考虑3DUI的普遍情况下,UI往往位于场景中的3D模型上方。
    这里写图片描述

    GameCamera的Depth = -1,Culling Mask为everything不进行剔除操作,ClearFlags的标志为skybox,表示空白的地方以天空盒填充。


    这里写图片描述
    UICamera的Depth = 0,Culling Mask为UI,UICamera嘛盯着UI就够了。Projection一般选Orthographic就好,选择PerspectiveUI可能会出现类似透视Camera下的旋转和扭曲等奇怪的现象。去除Audio Listener是为了避免unity中2 audio listeners的报错。


    这里写图片描述
    将Canvas的Render Mode设置为Screen Space-Camera。


    最后的效果如图:
    这里写图片描述

    展开全文
  • Unity中的渲染顺序自上而下大致分为三层。 最高层为Camera层,可以在Camera的depth那里设置,设置之后,图形的渲染顺序就是先绘制depth低的相机下的物体,再绘制depth高的相机下的物体,也就是说,depth高的相机会...

    Unity中的渲染顺序自上而下大致分为三层。 最高层为Camera层,可以在Camera的depth那里设置,设置之后,图形的渲染顺序就是先绘制depth低的相机下的物体,再绘制depth高的相机下的物体,也就是说,depth高的相机会覆盖depth低的相机(具体的覆盖关系有don't clear, solid color等等几种)

     

    比Camera层稍低一层的是sorting layer层, 随便找一个可以设置sorting layer的地方,选择sorting layer,点添加按钮,就可以看到当前所有的sorting layer,并且可以更改sorting layer的顺序,排位靠后的sorting layer会覆盖排位靠前的sorting layer。 设置好sorting layer的相互关系之后,就可以给任何一个继承于Renderer类,或者有renderer的子类作为field的对象设置sorting layer了。 注意这些sorting layer的遮挡关系是在同一个camera的层级下的。 不同camera下的renderer渲染顺序以camera的depth为准。 有的component的sorting layer可以直接在unity editor里面设置,比如Sprite Renderer。 有的则需要用代码来设置,比如设置Particle system的sorting layer, 就需要在代码中取到 ParticleSystem.Renderer.SortingLayer 来进行设置。

     

    比sorting layer再低一层的是sorting order, 这个数字指代的是在同一个sorting layer下的渲染顺序,用法很明显就不赘述了。

     

    需要注意不要混淆的是gameobject的layer,和renderer的sorting layer。 gameObject的layer个人理解是一个逻辑上的分层,用于camera的culling mask等。 而renderer的sorting layer则用于渲染。只有继承与renderer或者有renderer作为filed的component才需要设置sorting layer。

     

    另外需要指出的是,常用的NGUI的widget depth其本质也是一个sorting layer下的sorting order。 NGUI好像用的是一个叫做“UI"的sorting layer。 由此大家如果有需要,也可以自己取Hack NGUI的代码,把NGUI的sorting layer暴露出来供自己定制。

     

    简单总结一下,决定Unity渲染关系的层级顺序是:

    Camera 

    sorting layer

    sorting order

    展开全文
  • Unity3D渲染层级

    2018-05-12 13:15:19
    渲染层级的优先级(从上往下降序排列)Camera sorting layer (类似不同的文件夹)sorting order(类似文件夹下的文件 数值越大越后渲染 例:2&gt;1 所以当2和1 重叠放置的时候 2覆盖1 2在1上边 你可以看见2 ...

    渲染层级的优先级(从上往下降序排列)

    Camera 

    sorting layer (类似不同的文件夹)

    sorting order(类似文件夹下的文件 数值越大越后渲染  例:2>1 所以当2和1 重叠放置的时候 2覆盖1 2在1上边 你可以看见2 但是看不见1)

    简单的关系

    展开全文
  • 直接看代码简单明了:   public class UIDepth : MonoBehaviour { public int order; public bool isUI = true; void Start() { if (isUI) ... Canvas canvas = this.GetComponent();...

        直接看代码简单明了:

         

    	public class UIDepth : MonoBehaviour
    	{
    		public int  order;
    		public bool isUI = true;
    
    		void Start() 
    		{
    			if (isUI)
    			{
    				Canvas canvas = this.GetComponent<Canvas>();
    				
    				if( canvas == null){
    					canvas = this.gameObject.AddComponent<Canvas>();
    					this.gameObject.AddComponent<GraphicRaycaster>();
    				}
    				
    				canvas.overrideSorting = true;
    				canvas.sortingOrder    = order;
    			}
    			else
    			{
    				Renderer[] renders = this.GetComponentsInChildren<Renderer>(true);
    				
    				foreach (Renderer renderer in renders)
    				{
    					renderer.sortingOrder = order;
    				}
    			}
    		}
        

        挂载到GameObject上,运行时根据order控制绘制次序。


        如果是针对ui控制次序,我们就动态添加Canvas并且设置sortingOrder和GraphicRaycaster。一个是控制绘制次序,一个是让这个canvas组件可以接受事件。ui默认在default layer的order都是0。


        如果是模型或是粒子,统一获得Renderer对象来设置sortingOrder。粒子系统的renderer默认是在default layer的order也是0。


       首先是layer的绘制顺序,同layer就是sortingOrder的绘制顺序,同sortingOrder然后就是ugui自己的绘制顺序就是节点在场景里的顺序,粒子和模型的自己顺序是依靠position z来控制的。这里设置的order会直接影响sortingOrder,组件的绘制顺序。


        ui我们最好以窗口作为单位,来设定一个整体的order,然后内部依然利用ugui自己的规则排序。一个窗口内部的粒子和模型需要和这个窗口order一致才能正确显示。不同的窗口不同的次序,这样可以正确的区分每个窗口的层级和里面包含的粒子与模型顺序。

        

        

    展开全文
  • 出自Unity3d官网学习文档:http://edu.china.unity3d.com/learning_document 在这写出自己也就当边学习边记录了,也希望能帮到大家。 层级视图 (Hierarchy) 层级视图 (Hierarchy) 包含当前场景中的...
  • 在项目中,我们经常需要处理显示对象的层级关系或规划层级结构,那么Unity中主要有哪些主要的层级关系及他们的优先级是怎么样的呢? Camera 首先是Camera,Camera的depth值越大的在上面,越小的在下面,比如场景...
  • Unity层级面板

    2020-03-31 13:35:51
    Unity层级面板 入坑程序员也差不多一年有余了,但是一直没有养成写博客的良好习惯,这是不好滴,正好心血来潮,记录自己的一次学习心得,也供大家参考学习,大神请绕道走。 主要实现Unity中的Hierarchy层级面板...
  • Unity3d技巧
  • UI框架中UI窗体的“层级管理”,最核心的问题是如何进行窗体的显示管理。窗体(预设)的显示我们前面定义了三种类型: 普通、隐藏其他、反向切换。 “普通显示”模式允许多个窗体同时显示,这种类型应用最多。 ...
  • 今天有个同事问我如何在程序中修改子物体的层级关系来改变遮挡关系,我给他敲出来一句代码。 UI的层级关系是通过渲染表现出来的,在canvas下的物体,排序越靠前的越先被渲染,这样一来就会 被后来渲染的遮挡。总结...
  • 在动态创建物体时,通常先创建的层级会被后创建的层级低,从而被遮挡,
  • Unity2D 渲染层级

    2018-02-13 17:58:41
    Unity 渲染层级 渲染效果:谁被在下面,谁在上面。 -渲染层级 camera(摄像机) Depth(值越高物体越在上面) 在同一个camera中 sorting layer(越在下面的sorting layer 越在上面) 例如:player ...
  • UNITY3D模型显示在UI层级上的思路 一般UI是处理于显示最高层级的, 因此这里的做法是使用镜子效果,做镜子可使用renderTexture 然后启用一个摄像机对renderTexture进行数据填充, 然后在ui上使用Raw...
  • /// 修改UI背景图的层级 /// *******背景图和显示图层必须在同意级别********** /// &lt;/summary&gt; /// &lt;param name="Trans_Background"&gt;背景图&lt;/param&gt; ///...
  • 粒子特效的默认渲染层级比UI的渲染层级低。 UI默认的渲染层级为3000,把粒子特效的渲染层级改到3000以上就可以了。 public static void SetMaterialRenderQueue(Transform trans, int renderQueue) {...
  • UGUI在Screen Space - Overlay渲染模式下,由于不依赖摄像机渲染,使得其无法通过修改Z轴的方式修改物体间的层级关系,以下是解决方案: 我创建了一个空的工程,然后创建了一个Image,然后复制成了一样...
  • 2、unity渲染顺序控制方式 3、NGUI的控制 4、UGUI的控制 5、模型深度的控制 6、粒子特效深度控制 7、NGUI与模型和粒子特效穿插层级管理 8、UGUI与模型和粒子特效穿插层级管理写在前面这篇笔记是整理了之前做的...
  • Unity渲染层级关系

    2018-01-24 11:35:33
    第一:UGUI中: 一、条件:Render Mode都是Screen Space-Camera时的渲染顺序 1.遵循刷油漆规则 ...2.依次由Render Camera的Depth值、Sorting Layer先后顺序、Order in Layer值决定 ...Render Camera不同时,由...
1 2 3 4 5 ... 20
收藏数 4,014
精华内容 1,605