⭐ Unity 实现UI视差滚动效果(Parallax)鼠标控制、可拓展陀螺仪与脚本控制
✨ 效果如下
在许多游戏、APP 或动效页面中,我们常见的一种视觉效果是 视差滚动(Parallax Scrolling):前景、中景、背景在鼠标或设备移动时以不同速率轻微移动,从而营造出一种空间感和深度感。
目前遇到这样一个需求 所以在 Unity 中实现一个支持鼠标控制、陀螺仪控制和脚本控制的 UI 视差脚本,并提供完整源码、注释及使用方法,适合用于启动页、主菜单、信息卡片界面等多种场景。
🧠 实现原理
核心思想是:
每个 UI 图层记录起始位置;
根据输入设备(鼠标或陀螺仪),获取目标参考位置(通常是屏幕坐标归一化到
[0,1]
);用
Lerp
缓动插值方式移动 UI 图层,使其偏移方向和输入方向一致;每个图层的移动速度和最大移动范围可以独立配置。
📦 脚本结构概述
我们将视差系统封装为一个 MonoBehaviour 脚本,名为 MMParallaxUI
,结构清晰、易于扩展:
名称 | 说明 |
---|---|
ParallaxLayer | 子类,表示每一层的参数设置(RectTransform、速度、幅度、是否启用等) |
Modes | 视差控制模式(鼠标 / 陀螺仪 / 脚本) |
ParallaxLayers | 图层列表,可在 Inspector 中直接配置 |
AmplitudeMultiplier | 所有图层的幅度乘数 |
SpeedMultiplier | 所有图层的速度乘数 |
🧩 完整源码(含中文注释)
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()
控制。
// 示例:手动控制参考位置
parallaxUI.SetReferencePosition(new Vector2(0.5f, 0.5f)); // 回中
🎮 目前我使用的阈值如下
👇 均为透明png实现
按我这个阈值去配置 可以得到首图的效果
这个脚本目前直接挂载使用即可,陀螺仪方面还未拖拽完毕,也可以增加“自动回中”逻辑,在鼠标或输入松开后回归中心位置。如需图片素材做参考,或者你有新的思路和实现方式 可以私信我或在评论区留言。