✨ 效果如下

在许多游戏、APP 或动效页面中,我们常见的一种视觉效果是 视差滚动(Parallax Scrolling):前景、中景、背景在鼠标或设备移动时以不同速率轻微移动,从而营造出一种空间感和深度感。
目前遇到这样一个需求 所以在 Unity 中实现一个支持鼠标控制、陀螺仪控制和脚本控制的 UI 视差脚本,并提供完整源码、注释及使用方法,适合用于启动页、主菜单、信息卡片界面等多种场景。
🧠 实现原理
核心思想是:
-
每个 UI 图层记录起始位置;
-
根据输入设备(鼠标或陀螺仪),获取目标参考位置(通常是屏幕坐标归一化到
[0,1]
); -
用
Lerp
缓动插值方式移动 UI 图层,使其偏移方向和输入方向一致; -
每个图层的移动速度和最大移动范围可以独立配置。
📦 脚本结构概述
我们将视差系统封装为一个 MonoBehaviour 脚本,名为 MMParallaxUI
,结构清晰、易于扩展:
名称 | 说明 |
---|---|
ParallaxLayer |
子类,表示每一层的参数设置(RectTransform、速度、幅度、是否启用等) |
Modes |
视差控制模式(鼠标 / 陀螺仪 / 脚本) |
ParallaxLayers |
图层列表,可在 Inspector 中直接配置 |
AmplitudeMultiplier |
所有图层的幅度乘数 |
SpeedMultiplier |
所有图层的速度乘数 |
🧩 完整源码(含中文注释)
cs
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 用于实现UI视差滚动效果的组件(Parallax)
/// 支持鼠标控制、陀螺仪控制(移动端)、或通过代码控制
/// </summary>
public class MMParallaxUI : MonoBehaviour
{
/// <summary>
/// 用于存储每个视差图层的设置
/// </summary>
[Serializable]
public class ParallaxLayer
{
[Tooltip("该图层的 RectTransform 组件")]
public RectTransform Rect;
[Tooltip("该图层移动的速度")]
public float Speed = 2f;
[Tooltip("该图层相对初始位置最大移动距离(幅度)")]
public float Amplitude = 50f;
[HideInInspector]
public Vector2 StartPosition; // 图层的初始位置(运行时记录)
[Tooltip("是否启用该图层的视差效果")]
public bool Active = true;
}
/// <summary>
/// 控制视差输入的模式类型
/// </summary>
public enum Modes
{
Mouse, // 使用鼠标位置控制(适用于PC)
Gyroscope, // 使用陀螺仪控制(适用于移动设备)
Script // 外部脚本通过 SetReferencePosition 控制
}
[Header("基础设置")]
[Tooltip("当前使用的控制模式")]
public Modes Mode = Modes.Mouse;
[Tooltip("控制所有图层振幅的倍率")]
public float AmplitudeMultiplier = 1f;
[Tooltip("控制所有图层速度的倍率")]
public float SpeedMultiplier = 1f;
[Tooltip("参与视差移动的图层列表")]
public List<ParallaxLayer> ParallaxLayers;
// 内部变量
protected Vector2 _referencePosition; // 当前输入参考位置(归一化)
protected Vector3 _newPosition; // 图层的新位置
protected Vector2 _mousePosition; // 鼠标当前位置(屏幕坐标)
/// <summary>
/// Start 时初始化所有图层的起始位置
/// </summary>
protected virtual void Start()
{
Initialization();
}
/// <summary>
/// 初始化:记录每个图层的起始位置
/// </summary>
public virtual void Initialization()
{
foreach (ParallaxLayer layer in ParallaxLayers)
{
if (layer.Rect != null)
{
layer.StartPosition = layer.Rect.position;
}
}
}
/// <summary>
/// 每帧更新:移动所有图层
/// </summary>
protected virtual void Update()
{
MoveLayers();
}
/// <summary>
/// 根据控制模式更新 _referencePosition 并移动图层
/// </summary>
protected virtual void MoveLayers()
{
// 根据控制模式获取输入
switch (Mode)
{
case Modes.Gyroscope:
// 示例:你可以接入 Input.gyro.rotationRate 或 attitude(仅限移动设备)
// _referencePosition = new Vector2(Input.gyro.rotationRate.x, Input.gyro.rotationRate.y);
break;
case Modes.Mouse:
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
_mousePosition = UnityEngine.InputSystem.Mouse.current.position.ReadValue(); // 新输入系统
#else
_mousePosition = Input.mousePosition; // 旧输入系统
#endif
// 将鼠标屏幕坐标转为归一化视口坐标(0~1)
_referencePosition = Camera.main.ScreenToViewportPoint(_mousePosition);
break;
case Modes.Script:
// 由外部通过 SetReferencePosition() 设置
break;
}
// 遍历每个图层并移动位置
foreach (ParallaxLayer layer in ParallaxLayers)
{
if (layer.Active && layer.Rect != null)
{
// X轴移动(缓动)
_newPosition.x = Mathf.Lerp(
layer.Rect.position.x,
layer.StartPosition.x + _referencePosition.x * layer.Amplitude * AmplitudeMultiplier,
layer.Speed * SpeedMultiplier * Time.deltaTime
);
// Y轴移动(缓动)
_newPosition.y = Mathf.Lerp(
layer.Rect.position.y,
layer.StartPosition.y + _referencePosition.y * layer.Amplitude * AmplitudeMultiplier,
layer.Speed * SpeedMultiplier * Time.deltaTime
);
_newPosition.z = 0f;
// 更新图层位置
layer.Rect.position = _newPosition;
}
}
}
/// <summary>
/// 设置一个新的输入参考位置(仅在 Script 模式下使用)
/// 值通常在 (0,0) 到 (1,1) 之间
/// </summary>
public virtual void SetReferencePosition(Vector3 newReferencePosition)
{
_referencePosition = newReferencePosition;
}
}
🛠️ 使用方法
1️⃣ 添加组件
-
在 Canvas 下创建一个空 GameObject,命名为
UIParallaxRoot
。 -
挂载
MMParallaxUI
脚本。 -
在 Inspector 中配置
ParallaxLayers
列表,添加你希望参与视差效果的图层(Image/Text 等 UI 元素)。 -
配置每层的
Speed
和Amplitude
。
2️⃣ 设置控制模式
-
Mouse
(默认):使用鼠标位置控制(适用于PC)。 -
Gyroscope
:适用于移动端,可扩展为接入Input.gyro
。 -
Script
:通过代码调用SetReferencePosition()
控制。
cs
// 示例:手动控制参考位置
parallaxUI.SetReferencePosition(new Vector2(0.5f, 0.5f)); // 回中
🎮 目前我使用的阈值如下
👇 均为透明png实现
按我这个阈值去配置 可以得到首图的效果

这个脚本目前直接挂载使用即可,陀螺仪方面还未拖拽完毕,也可以增加"自动回中"逻辑,在鼠标或输入松开后回归中心位置。如需图片素材做参考,或者你有新的思路和实现方式 可以私信我或在评论区留言。