zoukankan      html  css  js  c++  java
  • UGUI制作类似Unity的Hierarchy(层级视图)

    最近在使用unity,实现unity中部分功能。

    其中有一部分是类似Unity的Hierarchy(层级视图)。

    加载模型的时候展示模型节点信息,最开始直接使用ScrollView组件。

    每个Transform组件就是一个节点,这导致这个模型子物体有成千上万个的时候,节点生成的巨多,导致Drawcall巨多,卡成屎。

    然后想到之前见过的无限滚动ScrollView,想过直接用别人造的轮子跑,但是找了好多跟我想要达到的功能并不一致。

    得了,自己造吧。

    先展示一个动图:

    点选节点可以实现对应模型的操作。按住Ctrl可以多选。

    首先要有个大致思路:

    有两个问题需要解决:1.怎么能让节点列表折叠 / 打开显示?2.怎么让节点无限利用起来?

    第一个问题:我这里用一个List储存一下所有的节点,再用一个List储存一下所有的可见节点。

            /// <summary>
            /// 所有的节点 
            /// </summary>public List<NodeItemSerializable> allNodesInfo = new List<NodeItemSerializable>();
    
            /// <summary>
            /// 当前可以显示的节点
            /// </summary>
            List<NodeItemSerializable> canShowNodes = new List<NodeItemSerializable>();

    每次当有折叠/打开的操作时候,把canShowNodes列表刷新一下就解决了这个问题。

    第二个问题:卡顿,原因就是,节点太多,那么不生成看不到的节点就可了,每次动态调整场景中的可见节点。

    至于动态的滑动:

    当滑条向下滑的时候将顶部的物体超出视野的拿走,同时将底部的空缺使用顶部拿走的物体补上

    当滑条向上滑的时候,反之。

    先用一张图理解一下:

    所以真正在场景中用户可见的节点列表就是上图黄色区域。 

    向下滑动,

    就从黄色区域第一个节点,塞进绿色区域最后一个位置,

    再从红色区域拿第一个节点,塞到黄色区域最后一个位置。(脑海中浮现了人体蜈蚣,哈哈哈)

    理解了图片,我们再来看动态更改列表的操作:

            /// <summary>
            /// 当前显示的物体最后一个所引值
            /// </summary>
            public int curShowObjLastIndex;

    这里用了一个int变量记录一下最后一个显示在列表中的节点索引值。

            /// <summary>
            /// 在可显示物体之前的节点信息
            /// </summary>
            Stack<NodeItemSerializable> beforeNodes = new Stack<NodeItemSerializable>();
            /// <summary>
            /// 在可显示物体之后的节点信息
            /// </summary>
            Stack<NodeItemSerializable> afterNodes = new Stack<NodeItemSerializable>();

    这两个变量用了Stack,利用栈的特性,先进先出,方便存取信息。

    下面的offsetY就是获取的鼠标滑动操作: offsetY = -Input.GetAxis("Mouse ScrollWheel") * 1000;

                 if (offsetY > 0)
                        {
                   //这里的 cueShowObjLastIndex 是在场景中节点的最后一位索引
    if (curShowObjLastIndex >= canShowNodes.Count) { offsetY = 0; } //Debug.Log("向上拽,item向下移动,最上头的item给before,最下层从after取出"); float tempY = parent.anchoredPosition.y; tempY += offsetY; if (offsetY != 0 && tempY >= tempItemHeight && afterNodes.Count > 0) { beforeNodes.Push(canShowNodes[curShowObjLastIndex - allNodeObjs.Count]); DestroyImmediate(allNodeObjs[0]); allNodeObjs.RemoveAt(0); GameObject tempAddGo = Instantiate(tempChildRect.gameObject, parent); SetNodeObjInfo(tempAddGo, afterNodes.Pop()); allNodeObjs.Add(tempAddGo); tempY = 0; curShowObjLastIndex += 1; SetScrollBarValue(); } parent.anchoredPosition = new Vector2(parent.anchoredPosition.x, tempY); } else if (offsetY < 0) { //当前索引减去总显示物体数量==0就代表拉到最顶端了 if (curShowObjLastIndex - allNodeObjs.Count <= 0) { offsetY = 0; } //Debug.Log("向下拽" + offsetY); float tempY = parent.anchoredPosition.y; tempY += offsetY; if (offsetY != 0 && tempY <= -tempItemHeight && beforeNodes.Count > 0) { afterNodes.Push(canShowNodes[curShowObjLastIndex - 1]); DestroyImmediate(allNodeObjs[allNodeObjs.Count - 1]); allNodeObjs.RemoveAt(allNodeObjs.Count - 1); GameObject tempAddGo = Instantiate(tempChildRect.gameObject, parent); tempAddGo.transform.SetAsFirstSibling(); SetNodeObjInfo(tempAddGo, beforeNodes.Pop()); allNodeObjs.Insert(0, tempAddGo); tempY = 0; curShowObjLastIndex -= 1; SetScrollBarValue(); } parent.anchoredPosition = new Vector2(parent.anchoredPosition.x, tempY); }

    这里不断的使用destroy和Instantiate,也会造成性能下降,可以搞个对象池解决。

    源码:https://github.com/wtb521thl/InfiniteRollingScrollViewDemo

    就这样。拜拜~

  • 相关阅读:
    侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (三)
    侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (二)
    侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (一)
    Android使用NFC模拟M卡实现 (二)
    scala中eq,==和equals的区别
    scala @BeanProperty 自动添加getter 和setter
    Scala 可变参数
    Flink 侧输出流 DEMO
    Flink 写数据到MySql (JDBC Sink)
    Fink 写数据到kafka (kafka sink)
  • 原文地址:https://www.cnblogs.com/yzxhz/p/14247678.html
Copyright © 2011-2022 走看看