134 lines
4.1 KiB
C#
134 lines
4.1 KiB
C#
using Cielonos.MainGame.Effects.Feedback;
|
||
using DG.Tweening;
|
||
using Unity.Cinemachine;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame.Characters
|
||
{
|
||
public class CameraFovSubmodule : SubmoduleBase<PlayerViewSubcontroller>
|
||
{
|
||
private Player player => owner.player;
|
||
private PlayerViewSubcontroller viewSc => owner;
|
||
|
||
[Header("基础FOV配置")] [Tooltip("静止时的基础FOV")]
|
||
public float baseFov = 45f;
|
||
|
||
[Tooltip("FOV最小值")] public float minFov = 40f;
|
||
|
||
[Tooltip("FOV最大值(疾奔时)")] public float maxFov = 55f;
|
||
|
||
[Header("速度阈值")] [Tooltip("开始FOV变化的最小速度")]
|
||
public float speedThreshold = 3f;
|
||
|
||
[Tooltip("达到最大FOV的速度")] public float maxSpeedThreshold = 15f;
|
||
|
||
[Header("过渡设置")] [Tooltip("FOV变化的速度")] public float fovChangeSpeed = 5f;
|
||
|
||
[Tooltip("是否平滑过渡FOV")] public bool useSmoothTransition = true;
|
||
|
||
private float currentFov;
|
||
private float targetFov;
|
||
private CinemachineCamera currentCamera => viewSc.currentCamera;
|
||
|
||
public CameraFovSubmodule(PlayerViewSubcontroller owner, float baseFov, float minFov,
|
||
float maxFov, float speedThreshold, float maxSpeedThreshold, float fovChangeSpeed, bool useSmoothTransition) : base(owner)
|
||
{
|
||
this.baseFov = baseFov;
|
||
this.minFov = minFov;
|
||
this.maxFov = maxFov;
|
||
this.speedThreshold = speedThreshold;
|
||
this.maxSpeedThreshold = maxSpeedThreshold;
|
||
this.fovChangeSpeed = fovChangeSpeed;
|
||
this.useSmoothTransition = useSmoothTransition;
|
||
this.currentFov = baseFov;
|
||
this.targetFov = baseFov;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据水平速度更新FOV
|
||
/// </summary>
|
||
/// <param name="horizontalSpeed">水平速度(单位/秒)</param>
|
||
/// <param name="deltaTime">帧时间</param>
|
||
public void UpdateFovBySpeed(float horizontalSpeed, float deltaTime)
|
||
{
|
||
// 计算目标FOV
|
||
targetFov = CalculateTargetFov(horizontalSpeed);
|
||
|
||
// 平滑过渡
|
||
if (useSmoothTransition)
|
||
{
|
||
currentFov = Mathf.Lerp(currentFov, targetFov, deltaTime * fovChangeSpeed);
|
||
}
|
||
else
|
||
{
|
||
currentFov = targetFov;
|
||
}
|
||
|
||
// 应用FOV
|
||
ApplyFov(currentFov);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据速度计算目标FOV
|
||
/// </summary>
|
||
private float CalculateTargetFov(float speed)
|
||
{
|
||
if (speed < speedThreshold)
|
||
{
|
||
return baseFov;
|
||
}
|
||
|
||
// 使用InverseLerp将速度映射到0-1范围
|
||
float t = Mathf.InverseLerp(speedThreshold, maxSpeedThreshold, speed);
|
||
// 使用SmoothStep使过渡更平滑
|
||
t = Mathf.SmoothStep(0f, 1f, t);
|
||
|
||
return Mathf.Lerp(baseFov, maxFov, t);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用FOV到相机
|
||
/// </summary>
|
||
private void ApplyFov(float fov)
|
||
{
|
||
fov = Mathf.Clamp(fov, minFov, maxFov);
|
||
|
||
LensSettings lens = currentCamera.Lens;
|
||
lens.FieldOfView = fov;
|
||
currentCamera.Lens = lens;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 立即设置FOV(不使用平滑过渡)
|
||
/// </summary>
|
||
public void SetFovImmediate(float fov)
|
||
{
|
||
currentFov = fov;
|
||
targetFov = fov;
|
||
ApplyFov(fov);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 平滑过渡到指定FOV
|
||
/// </summary>
|
||
public void SetFovSmooth(float targetFovValue, float duration)
|
||
{
|
||
DOTween.To(() => currentFov, x =>
|
||
{
|
||
currentFov = x;
|
||
ApplyFov(x);
|
||
}, targetFovValue, duration)
|
||
.SetEase(Ease.OutQuad);
|
||
|
||
targetFov = targetFovValue;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置为默认FOV
|
||
/// </summary>
|
||
public void ResetToBaseFov()
|
||
{
|
||
targetFov = baseFov;
|
||
}
|
||
}
|
||
} |