Unity2D实现Content RectTransform传送带式循环平滑滚动问题
解决Unity 2D内容传送带式循环滚动问题
我需要实现2D场景中Content的RectTransform平滑向右滚动,内容从右侧移出后从左侧重新进入,形成持续循环的传送带效果。尝试给Content挂载了以下脚本,但脚本仅能让内容向右移动一小段后就跳回初始位置,无法实现预期的循环滚动:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MovingContent : MonoBehaviour { public RectTransform content; // Reference to the Content RectTransform public float scrollSpeed = 5f; // Speed at which the content scrolls private List<RectTransform> items; // List to keep track of all the child items void Start() { // Initialize the list and populate it with the items items = new List<RectTransform>(); for (int i = 0; i < content.childCount; i++) { items.Add(content.GetChild(i).GetComponent<RectTransform>()); } } void Update() { // Move each item to the right foreach (RectTransform item in items) { item.anchoredPosition += Vector2.right * scrollSpeed * Time.deltaTime; } // Check if the first item has moved past the viewable area if (items[0].anchoredPosition.x > GetRightEdgeX(content)) { // Calculate the width of the first item float itemWidth = items[0].sizeDelta.x; // Move the first item to the end of the list RectTransform firstItem = items[0]; items.RemoveAt(0); items.Add(firstItem); // Place it on the left side of the last item RectTransform lastItem = items[items.Count - 2]; firstItem.anchoredPosition = new Vector2(lastItem.anchoredPosition.x - itemWidth, lastItem.anchoredPosition.y); } } // Utility function to get the right edge X position of the RectTransform private float GetRightEdgeX(RectTransform rt) { return rt.anchoredPosition.x + rt.rect.width; } }
问题分析
- 移出判断条件错误:原脚本用Content自身的右边缘作为判断标准,导致物品还没完全离开可视区域就被重置位置。正确的判断应该基于ScrollRect的Viewport右边缘。
- 位置重置逻辑错误:原代码将第一个物品移到倒数第二个物品左侧,没有考虑物品间距,且未基于可视区域左边缘计算位置,导致滚动时出现跳变。
修复后的脚本
using System.Collections.Generic; using UnityEngine; public class MovingContent : MonoBehaviour { public RectTransform content; // Content的RectTransform引用 public RectTransform viewport; // ScrollRect的Viewport引用 public float scrollSpeed = 5f; // 滚动速度 private List<RectTransform> items; // 子物品列表 void Start() { items = new List<RectTransform>(); // 初始化子物品列表 for (int i = 0; i < content.childCount; i++) { items.Add(content.GetChild(i).GetComponent<RectTransform>()); } // 初始排列物品(确保无缝衔接) ArrangeInitialItems(); } void Update() { // 所有物品向右移动 foreach (RectTransform item in items) { item.anchoredPosition += Vector2.right * scrollSpeed * Time.deltaTime; } // 检查第一个物品是否完全移出可视区域右侧 RectTransform firstItem = items[0]; float itemRightEdge = firstItem.anchoredPosition.x + firstItem.rect.width; float viewportRightEdge = viewport.anchoredPosition.x + viewport.rect.width; if (itemRightEdge > viewportRightEdge) { // 将第一个物品移到列表末尾 items.RemoveAt(0); items.Add(firstItem); // 计算新位置:放在当前最后一个物品的左侧,保持间距 RectTransform lastItem = items[items.Count - 2]; float newX = lastItem.anchoredPosition.x - firstItem.rect.width; firstItem.anchoredPosition = new Vector2(newX, firstItem.anchoredPosition.y); } } // 初始排列物品,确保从左侧开始无缝排列 private void ArrangeInitialItems() { float currentX = 0f; foreach (RectTransform item in items) { item.anchoredPosition = new Vector2(currentX, item.anchoredPosition.y); currentX += item.rect.width; } } // 可选:如果需要支持动态添加物品,可添加此方法 public void AddItem(RectTransform newItem) { items.Add(newItem); RectTransform lastItem = items[items.Count - 2]; newItem.anchoredPosition = new Vector2(lastItem.anchoredPosition.x + lastItem.rect.width, lastItem.anchoredPosition.y); } }
使用说明
- 确保Content的父物体是ScrollRect的Viewport,ScrollRect需开启
Horizontal、关闭Vertical,并禁用Movement Type的弹性效果 - 在Inspector面板中,给脚本赋值
content和viewport的引用 - 调整
scrollSpeed参数控制滚动速度,数值越大滚动越快
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

