using UnityEngine; namespace LightGlue.Unity.Game { /// /// 全局光标/跟随平滑设置(可挂在全局预制上,与 LightGlueManager 同节点或独立)。 /// - 供 SimpleCameraPositionMarker、LightGlueCameraAimController 等读取,统一调节平滑参数。 /// - 支持本地持久化(PlayerPrefs),启动时自动加载,修改后需调用 SaveToLocal() 保存。 /// public class LightGlueCursorSettings : MonoBehaviour { public static LightGlueCursorSettings Instance { get; private set; } private const string KeyPrefix = "LightGlueCursor_"; private const string KeyMarkerSmooth = KeyPrefix + "MarkerSmooth"; private const string KeyMarkerLerp = KeyPrefix + "MarkerLerp"; private const string KeyMarkerJitter = KeyPrefix + "MarkerJitter"; private const string KeyCameraSmooth = KeyPrefix + "CameraSmooth"; private const string KeyCameraLerp = KeyPrefix + "CameraLerp"; private const string KeyCameraJitter = KeyPrefix + "CameraJitter"; [Header("标记器跟随(SimpleCameraPositionMarker)")] [Tooltip("是否对 UI 标记位置做平滑插值")] public bool markerEnableSmoothFollow = true; [Tooltip("位置平滑插值速度,值越大响应越快")] public float markerPositionLerpSpeed = 100f; [Tooltip("抖动阈值(像素),小于该距离的位移将被忽略")] public float markerJitterThresholdPixels = 25f; [Tooltip("平滑曲线:横轴为进度 [0,1],纵轴为插值系数。由快到慢用缓出")] public AnimationCurve markerSmoothCurve = new AnimationCurve( new Keyframe(0f, 0f, 0f, 2f), new Keyframe(1f, 1f, 2f, 0f)); [Header("相机朝向跟随(LightGlueCameraAimController)")] [Tooltip("是否对 CameraToLook 的旋转做平滑插值")] public bool cameraAimEnableSmoothRotation = true; [Tooltip("旋转平滑插值速度,值越大响应越快")] public float cameraAimRotationLerpSpeed = 100f; [Tooltip("旋转抖动阈值(角度,度),小于该角度变化将被忽略")] public float cameraAimRotationJitterThresholdDeg = 0.5f; [Tooltip("旋转平滑曲线:横轴为进度 [0,1],纵轴为插值系数")] public AnimationCurve cameraAimSmoothCurve = new AnimationCurve( new Keyframe(0f, 0f, 0f, 2f), new Keyframe(1f, 1f, 2f, 0f)); /// 是否在 Awake 时从本地加载已保存的参数。 [Header("持久化")] [Tooltip("启动时是否从本地(PlayerPrefs)加载上次保存的参数")] public bool loadFromLocalOnAwake = true; [Header("显示控制")] [Tooltip("要控制显示/隐藏的 UI 根节点。不指定则使用本 GameObject")] public GameObject panelRoot; private void Awake() { if (Instance != null && Instance != this) { gameObject.SetActive(false); Destroy(gameObject); return; } Instance = this; if(panelRoot != null) panelRoot.SetActive(false); DontDestroyOnLoad(gameObject); if (loadFromLocalOnAwake) LoadFromLocal(); } private void OnDestroy() { if (Instance == this) Instance = null; } /// /// 从本地(PlayerPrefs)加载已保存的参数;若无记录则保持当前 Inspector 默认值。 /// public void LoadFromLocal() { if (PlayerPrefs.HasKey(KeyMarkerSmooth)) markerEnableSmoothFollow = PlayerPrefs.GetInt(KeyMarkerSmooth) != 0; if (PlayerPrefs.HasKey(KeyMarkerLerp)) markerPositionLerpSpeed = PlayerPrefs.GetFloat(KeyMarkerLerp); if (PlayerPrefs.HasKey(KeyMarkerJitter)) markerJitterThresholdPixels = PlayerPrefs.GetFloat(KeyMarkerJitter); if (PlayerPrefs.HasKey(KeyCameraSmooth)) cameraAimEnableSmoothRotation = PlayerPrefs.GetInt(KeyCameraSmooth) != 0; if (PlayerPrefs.HasKey(KeyCameraLerp)) cameraAimRotationLerpSpeed = PlayerPrefs.GetFloat(KeyCameraLerp); if (PlayerPrefs.HasKey(KeyCameraJitter)) cameraAimRotationJitterThresholdDeg = PlayerPrefs.GetFloat(KeyCameraJitter); } /// /// 将当前参数保存到本地(PlayerPrefs),下次启动将自动加载。 /// public void SaveToLocal() { PlayerPrefs.SetInt(KeyMarkerSmooth, markerEnableSmoothFollow ? 1 : 0); PlayerPrefs.SetFloat(KeyMarkerLerp, markerPositionLerpSpeed); PlayerPrefs.SetFloat(KeyMarkerJitter, markerJitterThresholdPixels); PlayerPrefs.SetInt(KeyCameraSmooth, cameraAimEnableSmoothRotation ? 1 : 0); PlayerPrefs.SetFloat(KeyCameraLerp, cameraAimRotationLerpSpeed); PlayerPrefs.SetFloat(KeyCameraJitter, cameraAimRotationJitterThresholdDeg); PlayerPrefs.Save(); } /// /// 恢复为代码默认值并保存到本地。 /// public void ResetToDefaultAndSave() { markerEnableSmoothFollow = true; markerPositionLerpSpeed = 100f; markerJitterThresholdPixels = 25f; cameraAimEnableSmoothRotation = true; cameraAimRotationLerpSpeed = 100f; cameraAimRotationJitterThresholdDeg = 0.5f; SaveToLocal(); } /// 获取实际控制显示隐藏的 GameObject(panelRoot 为空则为本物体)。 private GameObject GetPanelRoot() { return panelRoot != null ? panelRoot : gameObject; } /// 显示设置面板。 public void ShowPanel() { GetPanelRoot().SetActive(true); } /// 隐藏设置面板。 public void HidePanel() { GetPanelRoot().SetActive(false); } /// 切换设置面板显示状态。 public void TogglePanel() { GameObject root = GetPanelRoot(); root.SetActive(!root.activeSelf); } /// 当前面板是否处于显示状态。 public bool IsPanelVisible() { return GetPanelRoot().activeSelf; } } }