2025-12-23 19:47:06 -05:00
|
|
|
|
using DG.Tweening;
|
2025-12-17 04:19:38 -05:00
|
|
|
|
using Sirenix.OdinInspector;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
using SLSFramework.General;
|
|
|
|
|
|
using UnityEngine;
|
2025-12-23 19:47:06 -05:00
|
|
|
|
using Ease = DG.Tweening.Ease;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
namespace Cielonos.MainGame.Characters
|
|
|
|
|
|
{
|
|
|
|
|
|
public class CameraRotationSubmodule : SubmoduleBase<PlayerViewSubcontroller>
|
|
|
|
|
|
{
|
|
|
|
|
|
private Player player => owner.player;
|
|
|
|
|
|
private PlayerViewSubcontroller viewSc => owner;
|
|
|
|
|
|
private PlayerInputSubcontroller inputSc => player.inputSc;
|
|
|
|
|
|
|
|
|
|
|
|
private const float RotateThreshold = 0.01f;
|
|
|
|
|
|
|
2025-12-17 04:19:38 -05:00
|
|
|
|
[Title("Cinemachine Settings")]
|
2025-11-25 08:19:33 -05:00
|
|
|
|
public float cinemachineTargetYaw;
|
|
|
|
|
|
public float cinemachineEndLockYaw;
|
|
|
|
|
|
public float cinemachineTargetPitch;
|
|
|
|
|
|
public float topClamp = 70.0f;
|
|
|
|
|
|
public float bottomClamp = -30.0f;
|
|
|
|
|
|
public bool lockCameraPosition = false;
|
2025-12-17 04:19:38 -05:00
|
|
|
|
|
|
|
|
|
|
[Title("Combat Recenter Settings")]
|
|
|
|
|
|
public float recenterSmoothTime = 0.1f; // 平滑时间,越小转得越快
|
|
|
|
|
|
private float recenterVelocity; // SmoothDamp使用的速度变量
|
|
|
|
|
|
private float targetRecenterYaw; // 目标角度
|
|
|
|
|
|
private bool isRecentering = false; // 是否正在校准
|
|
|
|
|
|
private float recenterTimer = 0.0f; // 校准剩余时间
|
|
|
|
|
|
|
2025-11-25 08:19:33 -05:00
|
|
|
|
public CameraRotationSubmodule(PlayerViewSubcontroller owner, float initialYaw) : base(owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.cinemachineTargetYaw = initialYaw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (inputSc.Look.sqrMagnitude >= RotateThreshold && !lockCameraPosition)
|
|
|
|
|
|
{
|
2025-12-17 04:19:38 -05:00
|
|
|
|
isRecentering = false;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
float deltaTimeMultiplier = inputSc.CurrentScheme == "KeyboardMouse" ? 1.0f : Time.deltaTime;
|
2026-01-03 18:19:39 -05:00
|
|
|
|
cinemachineTargetYaw += inputSc.Look.x * deltaTimeMultiplier;
|
|
|
|
|
|
cinemachineTargetPitch += inputSc.Look.y * deltaTimeMultiplier;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
2025-12-17 04:19:38 -05:00
|
|
|
|
else if (isRecentering)
|
|
|
|
|
|
{
|
|
|
|
|
|
recenterTimer -= Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
|
|
if (recenterTimer <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
isRecentering = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
cinemachineTargetYaw = Mathf.SmoothDampAngle(cinemachineTargetYaw, targetRecenterYaw, ref recenterVelocity, recenterSmoothTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
cinemachineTargetYaw = MathExtensions.ClampAngle(cinemachineTargetYaw, float.MinValue, float.MaxValue);
|
|
|
|
|
|
cinemachineTargetPitch = MathExtensions.ClampAngle(cinemachineTargetPitch, bottomClamp, topClamp);
|
2025-12-23 19:47:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (viewSc.lockTargetModule.isUsingLockTargetCamera)
|
2025-12-22 23:27:18 -05:00
|
|
|
|
{
|
2025-12-23 19:47:06 -05:00
|
|
|
|
cinemachineEndLockYaw = viewSc.lockingTargetCamera.transform.eulerAngles.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-01-03 18:19:39 -05:00
|
|
|
|
viewSc.cameraRoot.rotation = Quaternion.Euler(cinemachineTargetPitch, cinemachineTargetYaw, 0.0f);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
2025-12-17 04:19:38 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// [新增] 触发相机战斗校准
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="attackDirection">攻击的方向向量 (通常是 player.transform.forward)</param>
|
|
|
|
|
|
/// <param name="duration">校准持续时间 (建议 0.2f ~ 0.5f)</param>
|
|
|
|
|
|
public void TriggerCameraRecenter(Vector3 attackDirection, float duration = 0.2f)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (attackDirection.sqrMagnitude < 0.01f) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算目标角度
|
|
|
|
|
|
Quaternion targetRot = Quaternion.LookRotation(attackDirection);
|
|
|
|
|
|
targetRecenterYaw = targetRot.eulerAngles.y;
|
|
|
|
|
|
|
|
|
|
|
|
// 激活状态
|
|
|
|
|
|
recenterTimer = duration;
|
|
|
|
|
|
isRecentering = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-23 19:47:06 -05:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 同步相机旋转到当前摄像机朝向
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void SyncRotationWithCamera()
|
2025-12-17 04:19:38 -05:00
|
|
|
|
{
|
2025-12-23 19:47:06 -05:00
|
|
|
|
// 确保获取的是当前正在起作用的锁定相机的旋转
|
|
|
|
|
|
var camera = viewSc.currentCamera;
|
2025-12-17 04:19:38 -05:00
|
|
|
|
Vector3 currentEuler = camera.transform.eulerAngles;
|
2025-12-23 19:47:06 -05:00
|
|
|
|
|
|
|
|
|
|
float yaw = currentEuler.y;
|
|
|
|
|
|
float pitch = currentEuler.x;
|
|
|
|
|
|
|
|
|
|
|
|
// --- 核心修复:处理欧拉角跨度问题 ---
|
|
|
|
|
|
// 如果 pitch > 180 (例如 355), 则转为负数 ( -5 )
|
|
|
|
|
|
if (pitch > 180) pitch -= 360;
|
|
|
|
|
|
|
2025-12-17 04:19:38 -05:00
|
|
|
|
isRecentering = false;
|
2025-12-23 19:47:06 -05:00
|
|
|
|
|
|
|
|
|
|
// 更新目标值
|
|
|
|
|
|
cinemachineTargetYaw = yaw;
|
|
|
|
|
|
cinemachineTargetPitch = pitch;
|
|
|
|
|
|
|
|
|
|
|
|
// --- 立即应用旋转 ---
|
|
|
|
|
|
// 强制立即更新一次 cameraRoot,防止等待下一帧 Update 产生的跳变
|
|
|
|
|
|
viewSc.cameraRoot.rotation = Quaternion.Euler(cinemachineTargetPitch, cinemachineTargetYaw, 0.0f);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|