using Cinemachine; using UnityEngine; /// /// 按屏幕方向切换虚拟相机的跟随距离。 /// /// 挂在 Canvas 或任意「拉伸铺满」的 UI 节点上(这类节点的尺寸会随屏幕变化,Unity 才会回调), /// 再把要改的虚拟相机拖到 virtualCamera 字段。该虚拟相机的 Body 必须是 Framing Transposer /// (Camera Distance 是 Body 上的字段,不在虚拟相机组件本身)。 /// /// 触发时机:Unity 只在 RectTransform 尺寸变化时调用 OnRectTransformDimensionsChange, /// 所以这里没有 Update、不轮询、初始化时不写值;只有屏幕方向真的翻转那一次才写一次距离。 /// (尺寸变了但方向没变——比如布局调整——也不会写。) /// [DisallowMultipleComponent] public class CameraDistanceByOrientation : MonoBehaviour { [Header("引用(必须在 Inspector / 预制体里指定)")] [Tooltip("要改跟随距离的虚拟相机;它的 Body 必须是 Framing Transposer")] [SerializeField] private CinemachineVirtualCamera virtualCamera; [Header("相机距离")] [Tooltip("横屏时的 Camera Distance")] [SerializeField] private float landscapeDistance = 13f; [Tooltip("竖屏时的 Camera Distance")] [SerializeField] private float portraitDistance = 30f; private CinemachineFramingTransposer _framingTransposer; private bool _isPortrait; private void Awake() { if (GetComponent() == null) Debug.LogError("[CameraDistanceByOrientation] 这个物体没有 RectTransform,收不到尺寸变化回调;" + "请挂到 Canvas 或任意拉伸铺满的 UI 节点上。", this); if (virtualCamera == null) { Debug.LogError("[CameraDistanceByOrientation] 没有指定 virtualCamera,请在 Inspector 里拖入。", this); return; } _framingTransposer = virtualCamera.GetCinemachineComponent(); if (_framingTransposer == null) Debug.LogError("[CameraDistanceByOrientation] 虚拟相机的 Body 不是 Framing Transposer,改不了 Camera Distance。", this); // 只记下开局方向,不写相机 _isPortrait = IsPortrait(); } /// RectTransform 尺寸变化时由 Unity 调用(屏幕旋转、分辨率变化都会触发)。 private void OnRectTransformDimensionsChange() { bool portrait = IsPortrait(); if (portrait == _isPortrait) return; // 尺寸变了但方向没变,不动相机 _isPortrait = portrait; // 只在翻转的这一次写值 if (_framingTransposer == null) return; // Awake 已经报过错 _framingTransposer.m_CameraDistance = portrait ? portraitDistance : landscapeDistance; } /// 屏幕高度大于宽度算竖屏。编辑器里拖动 Game 视图尺寸也能触发,方便验证。 private static bool IsPortrait() => Screen.height > Screen.width; }