前言:项目准备新增一个竞技场排行榜,策划规定只显示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(),列表上移时调用

  1. public class LoopScroll
  2. {
  3. private Dictionary<int, Transform> dic;
  4. private int[] keys;
  5. private float gap = 0;
  6. public LoopScroll(float gap,params Transform[] items)
  7. {
  8. this.gap = gap;
  9. dic = new Dictionary<int, Transform>(items.Length);
  10. keys = new int[items.Length];
  11. for (int i = 0; i < items.Length; i++)
  12. {
  13. dic.Add(i, items[i]);
  14. keys[i] = i;
  15. }
  16. }
  17. private LoopScroll()
  18. {
  19.  
  20. }
  21.  
  22. public void DownMove()
  23. {
  24. //TODO 将顶部Trs移动到尾部
  25. int top = keys[0];
  26. for (int i = 0; i < keys.Length-1; i++)
  27. {
  28. keys[i] = keys[i + 1];
  29. }
  30. keys[keys.Length - 1] = top;
  31. int key = keys[keys.Length - 2];
  32. Vector3 pos = dic[top].localPosition;
  33. pos.Set(pos.x, dic[key].localPosition.y - gap, pos.z);
  34. dic[top].localPosition = pos;
  35. }
  36.  
  37. public void UpMove()
  38. {
  39. //TODO 将尾部Trs移动到顶部
  40. int down = keys[keys.Length - 1];
  41. for (int i = keys.Length-1; i > 0; i--)
  42. {
  43. keys[i] = keys[i - 1];
  44. }
  45. keys[0] = down;
  46. int key = keys[1];
  47. Vector3 pos = dic[down].localPosition;
  48. pos.Set(pos.x, dic[key].localPosition.y+gap, pos.z);
  49. dic[down].localPosition = pos;
  50. }
  51. }

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

三、具体实现

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

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

  1. public class TestDragScroll : MonoBehaviour
  2. {
  3. public Transform startItem;
  4. public List<Transform> listTrs;
  5. public Transform move;
  6. private const float GAPY = 110f;
  7. private const float PerMoveDetal = 110f;
  8. private LoopScroll scorll;
  9.  
  10. private float prePosY;
  11.  
  12. private float movePrePosY;
  13.  
  14. private void OnValidate()
  15. {
  16. Vector3 startPos = startItem.localPosition;
  17. float startY = startPos.y;
  18. for (int i = 0; i < listTrs.Count; i++)
  19. {
  20. listTrs[i].localPosition = new Vector3(startPos.x, startY, startPos.z);
  21. startY -= GAPY;
  22. }
  23. }
  24. // Start is called before the first frame update
  25. void Start()
  26. {
  27. scorll = new LoopScroll(GAPY, listTrs.ToArray());
  28. prePosY = Input.mousePosition.y;
  29. movePrePosY = move.localPosition.y;
  30. }
  31.  
  32. // Update is called once per frame
  33. void Update()
  34. {
  35. if (Input.GetMouseButton(0))
  36. {
  37. float detal = Input.mousePosition.y - prePosY;
  38. if (Mathf.Abs(detal)>=1f)
  39. {
  40. prePosY = Input.mousePosition.y;
  41. Vector3 pos = move.localPosition;
  42. if (detal>0)
  43. {
  44. pos.Set(pos.x, pos.y + 4f, pos.z);
  45. }
  46. else
  47. {
  48. pos.Set(pos.x, pos.y - 4f, pos.z);
  49. }
  50. move.localPosition = pos;
  51. }
  52. }
  53.  
  54. float moveDetal = move.localPosition.y - movePrePosY;
  55. if (Mathf.Abs(moveDetal)>=PerMoveDetal)
  56. {
  57. if (moveDetal>0)
  58. {
  59. scorll.DownMove();
  60. Debug.Log("Down");
  61. }
  62. else
  63. {
  64. scorll.UpMove();
  65. Debug.Log("Up");
  66. }
  67. movePrePosY = move.localPosition.y;
  68. }
  69. }
  70. }

四、项目实现效果

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

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

Unity-UGUI-无限循环列表的更多相关文章

  1. Unity UGUI —— 无限循环List

    还记得大学毕业刚工作的时候是做flash的开发,那时候看到别人写的各种各样的UI组件就非常佩服,后来自己也慢慢尝试着写,发现其实也就那么回事.UI的开发其实技术的成分相对来说不算多,但是一个好的UI是 ...

  2. Unity UGUI —— 无限循环List(转载)

    using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI; ...

  3. unity 背景无限循环滚动效果

    背景无限循环滚动效果如下示: 步骤如下: 导入背景图片后,设置图片的格式,如下图: 2.图片格式也可以设置是Texture格式,但是Wrap Mode 一定要是Repeat[重复发生]:然后记得App ...

  4. 详细分析Android viewpager 无限循环滚动图片

    由于最近在忙于项目,就没时间更新博客了,于是趁着周日在房间把最近的在项目中遇到的技术总结下.最近在项目中要做一个在viewpager无限滚动图片的需求,其实百度一下有好多的例子,但是大部分虽然实现了, ...

  5. AlloyTouch之无限循环select插件

    写在前面 当滚动的内容很多,比如闹钟里设置秒,一共有60项.让使用者从59ms滚回01ms是一件很痛苦的事情,所以: 在列表项太多的情况下,我们希望能够有个无限循环的滚动.00ms和01ms是无缝链接 ...

  6. Unity UGUI图文混排源码(二)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  7. 自定义完美的ViewPager 真正无限循环的轮播图

    网上80%的思路关于Android轮播图无限循环都是不正确的,不是真正意义上的无限循环, 其思路大多是将ViewPager的getCount方法返回值设置为Integer.MAX_VALUE, 然后呢 ...

  8. 理解 vue-router的beforeEach无限循环的问题

    在理解beforeEach无限循环之前,我们先来看一下beforeEach相关的知识点,该篇文章的项目是基于 express+vue+mongodb+session实现注册登录 这篇文章项目基础之上进 ...

  9. C#开发Unity游戏教程循环遍历做出判断及Unity游戏示例

    C#开发Unity游戏教程循环遍历做出判断及Unity游戏示例 Unity中循环遍历每个数据,并做出判断 很多时候,游戏在玩家做出判断以后,游戏程序会遍历玩家身上大量的所需数据,然后做出判断,即首先判 ...

随机推荐

  1. mybatis-day1入门案例

    首先应先创建maven工程 (jar包要导入,五个核心jar包) 如果测试运行时出现了不支持版本5,则要修改以下内容 类的路径如下 1.配置pom.xml依赖 <?xml version=&qu ...

  2. Spring5-IOC底层原理

    1.什么是IOC (1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理 (2)使用IOC目的:为了降低耦合度 2.IOC底层原理 (1)xml解析.工厂模式.反射

  3. ansible模块解析及使用

    模块一:setup(收集远程主机信息) [root@zabbix30 /]# ansible test -m setup 模块二:ping(测试主机是否在线) [root@zabbix30 /]# a ...

  4. 帝国CMS内容页模板过滤清理简介smalltext前后空格的方法!

    在内容模板你需要调用的地方使用如下代码输出简介即可过滤简介smalltext前后的空格了: <? $qian=array(" "," ","\t ...

  5. ADO访问Excel

    需要安装驱动:Microsoft Access Database Engine,可搜索下载,有64位和32位之分. 随便新建一个后缀名为udl的文件,双击打开.注意,现如今一般都是64位系统,双击打开 ...

  6. JQuery学习高级

    ## 今日内容:     1. JQuery 高级         1. 动画         2. 遍历         3. 事件绑定         4. 案例         5. 插件 ## ...

  7. el-transfer增加拖拽功能

    el-transfer增加拖拽排序,左右互相拖拽功能: npm i sortablejs <template> <el-transfer ref="transfer&quo ...

  8. 6.2 计划任务crond

    创建.编辑计划任务的命令为crontab -e,查看当前计划任务的命令为crontab -l,删除某条计划任务的命令为crontab -r. 参数 作用 -e 编辑计划任务 -u 指定用户名称 -l ...

  9. 攻防世界-MISC:János-the-Ripper

    这是攻防世界MISC高手进阶区的题目: 点击下载附件一,解压后得到一个没有后缀的文件,老规矩用010editor打开,发现存在一个flag.txt文件 用foremost分离一下: flag.txt被 ...

  10. Libco Hook 机制浅析

    Libco Hook 机制浅析 之前的文章里我们提到过 Libco 有一套 Hook 机制,可以通过协程的让出(yield)原语将系统的阻塞系统调用改造为非阻塞的,这篇文章我们将深入解析 Hook 机 ...