98 lines
4.2 KiB
C#
98 lines
4.2 KiB
C#
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 根据屏幕宽高比,对 gameplay 相机做分辨率适配,让宽屏下轨道观感更接近设计(16:9)。
|
||
///
|
||
/// 需求(用户指定):越宽的屏幕(21:9/32:9)轨道越缩在中间、显细,左右与 UI 空出大黑缝。
|
||
/// 解决方案:宽屏时把相机从设计基准(z=-8, X=-40°)逐步插值到"z 更高 + X 更朝水平"的目标位姿,
|
||
/// 让轨道透视放大、铺满视野,同时保持判定线距离/视距/业务逻辑不变(音符/判定用世界坐标,不受相机缩放影响)。
|
||
///
|
||
/// 操作对象:**直接改相机本体(Main Camera 子物体)自身的 local z 高度与 local X 旋转**,
|
||
/// 不动其父/祖父 pivot(drift/skill pivot)。通过 effectEventController.SetResolutionCameraSelf 施加,
|
||
/// 由该方法处理与 SmoothShake(写相机 local)、冲刺(写相机 local z)的共享——空闲时写入持久生效,
|
||
/// 抖动/冲刺触发时会以当前 local 重新捕获基准。不碰任何 UI:UI 贴边逻辑独立,本脚本只改相机位姿。
|
||
///
|
||
/// 用一个 bool(enableTuning)开关。关闭时恢复设计基准(与未加此脚本逐像素一致)。
|
||
/// 16:9 及更窄(平板 1.6、竖屏)保持设计基准不动;宽屏线性插值;21:9 及更宽夹在最大偏移(用户指定的上限)。
|
||
/// </summary>
|
||
[DisallowMultipleComponent]
|
||
public sealed class CameraResolutionTuner : MonoBehaviour
|
||
{
|
||
[Tooltip("是否启用按分辨率微调相机。关闭则恢复设计基准。")]
|
||
public bool enableTuning = true;
|
||
|
||
[Tooltip("设计基准宽高比。16:9 = 1.7778。此比例及更窄时无微调。")]
|
||
public float designAspect = 16f / 9f;
|
||
|
||
[Tooltip("最大偏移的宽高比上限。21:9 = 2.3333。达到或超过此比例时夹在最大偏移。")]
|
||
public float maxOffsetAspect = 21f / 9f;
|
||
|
||
[Header("21:9 时相机本体(Main Camera)的目标 local 位姿(最大偏移)")]
|
||
[Tooltip("21:9 时相机本体的目标 local Z 高度。用户指定 2.5(相机自身 z=2.5)。")]
|
||
public float targetCameraY = -2.13f;
|
||
|
||
public float targetCameraZ = 3.6f;
|
||
|
||
[Tooltip("21:9 时相机本体的目标 local X 旋转角度。用户指定 5(相机自身 X=5°)。")]
|
||
public float targetCameraRotX = -10f;
|
||
|
||
private float _lastAspect = -1f;
|
||
private bool _lastEnabled;
|
||
private bool _applied; // 上次 Apply 是否成功写入相机(相机/单例未就绪时为 false,下一帧重试)
|
||
|
||
private void OnEnable()
|
||
{
|
||
_lastAspect = -1f;
|
||
_applied = false;
|
||
Apply();
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
float aspect = (float)Screen.width / Mathf.Max(1, Screen.height);
|
||
// 宽高比/开关变化,或此前尚未成功写入(相机/单例未就绪),则重试。
|
||
if (!_applied || Mathf.Abs(aspect - _lastAspect) > 0.0001f || enableTuning != _lastEnabled)
|
||
{
|
||
Apply();
|
||
}
|
||
}
|
||
|
||
private void Apply()
|
||
{
|
||
var eff = effectEventController.Instance;
|
||
if (eff == null) { _applied = false; return; }
|
||
|
||
float aspect = (float)Screen.width / Mathf.Max(1, Screen.height);
|
||
_lastAspect = aspect;
|
||
_lastEnabled = enableTuning;
|
||
|
||
if (!enableTuning)
|
||
{
|
||
// 关闭:t=0 → 相机本体回到 local 设计基准(运行时为 0/identity)。
|
||
_applied = eff.SetResolutionCameraSelf(0f, targetCameraRotX, targetCameraZ, targetCameraY);
|
||
return;
|
||
}
|
||
|
||
// 16:9 及更窄:t=0(无微调,与设计逐像素一致)。
|
||
// 16:9 ~ 21:9:线性插值 t ∈ [0,1]。
|
||
// 21:9 及更宽:t=1(夹在最大偏移上限)。
|
||
float t = 0f;
|
||
if (aspect > designAspect)
|
||
{
|
||
if (aspect >= maxOffsetAspect)
|
||
{
|
||
t = 1f; // 超宽屏:夹在最大偏移
|
||
}
|
||
else
|
||
{
|
||
// 插值区间:designAspect(16:9≈1.778) → maxOffsetAspect(21:9≈2.333)
|
||
t = (aspect - designAspect) / Mathf.Max(0.0001f, maxOffsetAspect - designAspect);
|
||
t = Mathf.Clamp01(t);
|
||
}
|
||
}
|
||
// aspect <= designAspect:t=0(无微调)。
|
||
|
||
_applied = eff.SetResolutionCameraSelf(t, targetCameraRotX, targetCameraZ, targetCameraY);
|
||
}
|
||
}
|