134 lines
4.1 KiB
C#
134 lines
4.1 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
/// <summary>
|
||
/// 挂载在Canvas上,控制两个背景Image从上往下无限滚动(适配实际屏幕高度间隔)
|
||
/// </summary>
|
||
[RequireComponent(typeof(Canvas))]
|
||
//[ExecuteInEditMode]
|
||
public class BackgroundScroll : MonoBehaviour
|
||
{
|
||
[Header("滚动速度(像素/秒)")]
|
||
public float scrollSpeed = 50f;
|
||
|
||
[Header("是否自动获取子物体的两个Image(取消则手动指定)")]
|
||
public bool autoGetImages = true;
|
||
|
||
[Header("手动指定的两个背景Image(autoGetImages为false时生效)")]
|
||
public Image bgImage1;
|
||
public Image bgImage2;
|
||
|
||
// Image的RectTransform组件
|
||
private RectTransform rt1;
|
||
private RectTransform rt2;
|
||
// Image在屏幕上的实际显示高度(关键:适配Aspect缩放)
|
||
private float actualImageHeight;
|
||
private float rt1ScaleY = 1;
|
||
void Start()
|
||
{
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
// 初始化Image和RectTransform
|
||
InitImages();
|
||
|
||
// 计算Image的实际屏幕高度(适配Aspect模式)
|
||
if (rt1 != null)
|
||
{
|
||
actualImageHeight = GetImageActualHeight(rt1);
|
||
rt1ScaleY = rt1.localScale.y;
|
||
// 初始化第二个Image的位置:在第一个Image顶部上方,间隔实际屏幕高度
|
||
rt2.anchoredPosition = new Vector2(0, rt1.anchoredPosition.y + actualImageHeight);
|
||
//Debug.Log($"图片实际屏幕高度:{actualImageHeight},已初始化第二张图位置");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("未找到有效的背景Image,请检查Canvas下的子物体或手动指定Image!");
|
||
}
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
if (rt1 == null || rt2 == null) return;
|
||
|
||
|
||
if (rt1ScaleY != rt1.localScale.y)
|
||
{
|
||
actualImageHeight = GetImageActualHeight(rt1);
|
||
rt2.anchoredPosition = new Vector2(0, rt1.anchoredPosition.y + actualImageHeight);
|
||
rt1ScaleY = rt1.localScale.y;
|
||
}
|
||
|
||
// 让两个Image向下滚动(anchoredPosition的y轴减小)
|
||
rt1.anchoredPosition -= new Vector2(0, scrollSpeed * Time.deltaTime);
|
||
rt2.anchoredPosition -= new Vector2(0, scrollSpeed * Time.deltaTime);
|
||
|
||
// 检测第一个Image是否完全滚出屏幕下方,重置位置(用实际高度判断)
|
||
if (rt1.anchoredPosition.y <= -actualImageHeight)
|
||
{
|
||
rt1.anchoredPosition = new Vector2(0, rt2.anchoredPosition.y + actualImageHeight);
|
||
}
|
||
|
||
// 检测第二个Image是否完全滚出屏幕下方,重置位置(用实际高度判断)
|
||
if (rt2.anchoredPosition.y <= -actualImageHeight)
|
||
{
|
||
rt2.anchoredPosition = new Vector2(0, rt1.anchoredPosition.y + actualImageHeight);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化Image组件和RectTransform
|
||
/// </summary>
|
||
private void InitImages()
|
||
{
|
||
if (autoGetImages)
|
||
{
|
||
Image[] images = GetComponentsInChildren<Image>();
|
||
if (images.Length >= 2)
|
||
{
|
||
bgImage1 = images[0];
|
||
bgImage2 = images[1];
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("Canvas下的Image数量不足2个,请检查!");
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (bgImage1 != null) rt1 = bgImage1.GetComponent<RectTransform>();
|
||
if (bgImage2 != null) rt2 = bgImage2.GetComponent<RectTransform>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算RectTransform在屏幕上的实际显示高度(适配Aspect缩放)
|
||
/// </summary>
|
||
/// <param name="rt">目标RectTransform</param>
|
||
/// <returns>实际屏幕高度(像素)</returns>
|
||
private float GetImageActualHeight(RectTransform rt)
|
||
{
|
||
// 获取RectTransform的世界空间包围盒
|
||
//Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(transform, rt);
|
||
// 转换为屏幕空间的高度(考虑Canvas的缩放)
|
||
//float canvasScale = GetComponent<Canvas>().scaleFactor;
|
||
return rt.sizeDelta.y * rt.localScale.y;
|
||
}
|
||
|
||
///// <summary>
|
||
///// 编辑器下实时预览(可选)
|
||
///// </summary>
|
||
//private void OnDrawGizmos()
|
||
//{
|
||
// if (Application.isPlaying) return;
|
||
// InitImages();
|
||
// if (rt1 != null)
|
||
// {
|
||
// actualImageHeight = GetImageActualHeight(rt1);
|
||
// if (rt2 != null)
|
||
// {
|
||
// rt2.anchoredPosition = new Vector2(0, actualImageHeight);
|
||
// }
|
||
// }
|
||
//}
|
||
} |