ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Unity-UGUI-无限循环列表

2022-05-21 21:32:10  阅读:157  来源: 互联网

标签:localPosition keys pos private 列表 int Unity UGUI dic


前言:项目准备新增一个竞技场排行榜,策划规定只显示0-400名的玩家。我一想,生成四百个游戏物体,怕不是得把手机给卡死?回想原来在GitHub上看到过一个实现思路就是无限循环列表,所以就想自己试试。公司用的是NGUI,花了1个多小时还是没做出来,但是基本思路有了,又到了下班时间,不想赖在公司怕带坏了风气,就回来用自己电脑上的UGUI实现。

实现思路:假设屏幕只显示五行玩家排名,那么就预备十行,上面多两行,下面多三行。每次移动单位距离(一行玩家排名占高),就移动一端的物体到另一端,这样就实现了无限循环。

实现过程:

一、搭建UI

1.先在UI搭建好面板,其中SV物体添加RectMask2D组件,模拟ScrollView的裁剪;将无限循环列表脚本挂在SV上

2.在SV下添加一个Grid(Grid并非组件而是名字)物体,用于模拟移动整个列表

3.Grid物体下添加十个Item,前面隐藏两个,中间显示五个,后面隐藏三个。为什么要多放几个呢?因为想滑动时更加顺滑

 

 

 二、实现LoopScroll类

1.类中包含字段int[] keys,用于记录下标变换;Dictionary<int,Transform> dic,用于保存下标与Transform之间的映射关系;int gap,用于计算Transform之间应该间隔的距离

2.类中包含方法DownMove(),列表下移时调用;UpMove(),列表上移时调用

public class LoopScroll
{
    private Dictionary<int, Transform> dic;
    private int[] keys;
    private float gap = 0;
    public LoopScroll(float gap,params Transform[] items)
    {
        this.gap = gap;
        dic = new Dictionary<int, Transform>(items.Length);
        keys = new int[items.Length];
        for (int i = 0; i < items.Length; i++)
        {
            dic.Add(i, items[i]);
            keys[i] = i;
        }
    }
    private LoopScroll()
    {

    }

    public void DownMove()
    {
        //TODO 将顶部Trs移动到尾部
        int top = keys[0];
        for (int i = 0; i < keys.Length-1; i++)
        {
            keys[i] = keys[i + 1];
        }
        keys[keys.Length - 1] = top;
        int key = keys[keys.Length - 2];
        Vector3 pos = dic[top].localPosition;
        pos.Set(pos.x, dic[key].localPosition.y - gap, pos.z);
        dic[top].localPosition = pos;
    }

    public void UpMove()
    {
        //TODO 将尾部Trs移动到顶部
        int down = keys[keys.Length - 1];
        for (int i = keys.Length-1; i > 0; i--)
        {
            keys[i] = keys[i - 1];
        }
        keys[0] = down;
        int key = keys[1];
        Vector3 pos = dic[down].localPosition;
        pos.Set(pos.x, dic[key].localPosition.y+gap, pos.z);
        dic[down].localPosition = pos;
    }
}

讲解:每次移动时,对keys做循环类似的操作,操作完keys后,再通过下标获取对应的Transform,将Transform插入到对应的Position。为什么不直接用Transform[] 数组处理呢?因为我担心移动时会出现,因引用类型的特性,而导致位置混乱,还不如多用一个keys,keys是值类型,操作简单。

三、具体实现

1.因为我是自己做的滑动,所以代码里需要自己写。当按下鼠标左键,并且拖动一定距离时,触发移动方法。在移动方法中判断移动的偏移值的正负性,是向上?还是向下?然后move的position是加还是减?

2.move移动后,判断move移动的距离是否大于等于单位距离(一个item的高),如果移动了单位距离,则触发循环方法。移动的距离是正还是负?可得知是执行DownMove还是UpMove。

public class TestDragScroll : MonoBehaviour
{
    public Transform startItem;
    public List<Transform> listTrs;
    public Transform move;
    private const float GAPY = 110f;
    private const float PerMoveDetal = 110f;
    private LoopScroll scorll;

    private float prePosY;

    private float movePrePosY;

    private void OnValidate()
    {
        Vector3 startPos = startItem.localPosition;
        float startY = startPos.y;
        for (int i = 0; i < listTrs.Count; i++)
        {
            listTrs[i].localPosition = new Vector3(startPos.x, startY, startPos.z);
            startY -= GAPY;
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        scorll = new LoopScroll(GAPY, listTrs.ToArray());
        prePosY = Input.mousePosition.y;
        movePrePosY = move.localPosition.y;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            float detal = Input.mousePosition.y - prePosY;
            if (Mathf.Abs(detal)>=1f)
            {
                prePosY = Input.mousePosition.y;
                Vector3 pos = move.localPosition;
                if (detal>0)
                {
                    pos.Set(pos.x, pos.y + 4f, pos.z);
                }
                else
                {
                    pos.Set(pos.x, pos.y - 4f, pos.z);
                }
                move.localPosition = pos;
            }
        }

        float moveDetal = move.localPosition.y - movePrePosY;
        if (Mathf.Abs(moveDetal)>=PerMoveDetal)
        {
            if (moveDetal>0)
            {
                scorll.DownMove();
                Debug.Log("Down");
            }
            else
            {
                scorll.UpMove();
                Debug.Log("Up");
            }
            movePrePosY = move.localPosition.y;
        }
    }
}

四、项目实现效果

在自己电脑上用UGUI实现了并非适合项目场景。最终实现时,因为Update中判断移动距离的方法并不可靠,移动距离每次不可能都=113,而我的判断时只要>=113就执行一次循环,那么我滑动226呢?还是只移动了一个item。所以此方法行不通。我的主程告诉我,400个item并不一定要用无限循环列表,如果短时间内做不出来就不要再做了,项目进度要紧。建议我用协程分帧生成400个item,不会卡住的。由于我心烦气乱,最终没有做循环列表的方案。

但是循环列表的雏形是有的,以前都只知道循环列表的思路而未真正实现过,这次实践是第一次,收获颇丰,特写随笔记录

 

标签:localPosition,keys,pos,private,列表,int,Unity,UGUI,dic
来源: https://www.cnblogs.com/JunJiang-Blog/p/16296070.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有