using UnityEngine; /// /// 按屏幕宽高比动态拉长轨道视觉物体(track1-5)的 Y 缩放,让宽屏下轨道更饱满。 /// /// 原理:宽屏时水平视野大、轨道相对缩在中间显细。降相机高度+抬头能让轨道透视放大, /// 但仍不够饱满。再叠加"拉长轨道 Y 缩放"填满纵向视野,视觉更满。 /// /// 关键:轨道只是背景视觉,判定是几何驱动(音符世界 Y vs 判定线世界 Y)。 /// 缩放轨道 localScale 不影响音符生成/下落/判定——它们全用世界坐标,与轨道视觉无关。 /// /// 用法:挂到场景任意物体(会自动找 track1-5 或指定 trackParent)。运行时自动扫描并缩放。 /// [DisallowMultipleComponent] public sealed class TrackScaler : MonoBehaviour { [Tooltip("是否启用轨道缩放。关闭则恢复基准值 2.5。")] public bool enableScaling = true; [Tooltip("设计基准宽高比。16:9 = 1.7778。此比例下缩放为基准值。")] public float designAspect = 16f / 9f; [Tooltip("轨道 Y 缩放的基准值(场景序列化的初始值)。从这个值开始按宽高比放大。")] public float baseScaleY = 2.5f; [Header("宽屏(aspect > 设计)缩放")] [Tooltip("每偏离设计宽高比 1.0,额外叠加的 Y 缩放倍数。宽屏拉长轨道让视觉更满。")] public float widePerAspectScaleY = 0.8f; [Tooltip("Y 缩放的绝对上限。避免极端超宽屏拉得过长。")] public float maxScaleY = 4.5f; [Tooltip("(可选)轨道的父节点。留空则自动全场景查找 track1-5。")] public Transform trackParent; private Transform[] _tracks; private float _lastAspect = -1f; private bool _lastEnabled; private void OnEnable() { FindTracks(); _lastAspect = -1f; Apply(); } private void Update() { float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); if (Mathf.Abs(aspect - _lastAspect) > 0.0001f || enableScaling != _lastEnabled) { Apply(); } } private void FindTracks() { if (trackParent != null) { // 从指定父节点下找 _tracks = new Transform[5]; for (int i = 0; i < trackParent.childCount; i++) { Transform child = trackParent.GetChild(i); if (child.name == "track1") _tracks[0] = child; else if (child.name == "track2") _tracks[1] = child; else if (child.name == "track3") _tracks[2] = child; else if (child.name == "track4") _tracks[3] = child; else if (child.name == "track5") _tracks[4] = child; } } else { // 全场景查找(慢,但兜底) _tracks = new Transform[5]; GameObject go1 = GameObject.Find("track1"); GameObject go2 = GameObject.Find("track2"); GameObject go3 = GameObject.Find("track3"); GameObject go4 = GameObject.Find("track4"); GameObject go5 = GameObject.Find("track5"); if (go1 != null) _tracks[0] = go1.transform; if (go2 != null) _tracks[1] = go2.transform; if (go3 != null) _tracks[2] = go3.transform; if (go4 != null) _tracks[3] = go4.transform; if (go5 != null) _tracks[4] = go5.transform; } } private void Apply() { if (_tracks == null || _tracks.Length == 0) { FindTracks(); // 重试 if (_tracks == null || _tracks.Length == 0) return; } float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); _lastAspect = aspect; _lastEnabled = enableScaling; float targetScaleY = baseScaleY; if (enableScaling && aspect > designAspect) { // 宽屏:额外拉长 Y float dev = aspect - designAspect; float extra = widePerAspectScaleY * dev; targetScaleY = Mathf.Min(baseScaleY + extra, maxScaleY); } // aspect <= designAspect 或关闭:保持基准值 // 应用到所有轨道 for (int i = 0; i < _tracks.Length; i++) { if (_tracks[i] == null) continue; Vector3 scale = _tracks[i].localScale; scale.y = targetScaleY; _tracks[i].localScale = scale; } } }