Files
Cielonos/Assets/Scripts/MainGame/Characters/Player/View/CameraRotationSubmodule.cs
SoulliesOfficial eaa688c7a9 调整
2025-12-22 23:27:18 -05:00

130 lines
5.3 KiB
C#

using Sirenix.OdinInspector;
using SLSFramework.General;
using UnityEngine;
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;
[Title("Cinemachine Settings")]
public float cinemachineTargetYaw;
public float cinemachineEndLockYaw;
public float cinemachineTargetPitch;
public float topClamp = 70.0f;
public float bottomClamp = -30.0f;
public float cameraAngleOverride = 0.0f;
public bool lockCameraPosition = false;
[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; // 校准剩余时间
public CameraRotationSubmodule(PlayerViewSubcontroller owner, float initialYaw) : base(owner)
{
this.cinemachineTargetYaw = initialYaw;
}
public void Update()
{
if (inputSc.Look.sqrMagnitude >= RotateThreshold && !lockCameraPosition)
{
isRecentering = false;
float deltaTimeMultiplier = inputSc.CurrentScheme == "KeyboardMouse" ? 1.0f : Time.deltaTime;
//if (!viewSc.lockTargetModule.isLockedMelee)
{
cinemachineTargetYaw += inputSc.Look.x * deltaTimeMultiplier;
cinemachineTargetPitch += inputSc.Look.y * deltaTimeMultiplier;
}
}
else if (isRecentering)
{
recenterTimer -= Time.deltaTime;
if (recenterTimer <= 0)
{
isRecentering = false;
}
else
{
cinemachineTargetYaw = Mathf.SmoothDampAngle(cinemachineTargetYaw, targetRecenterYaw, ref recenterVelocity, recenterSmoothTime);
}
}
cinemachineTargetYaw = MathExtensions.ClampAngle(cinemachineTargetYaw, float.MinValue, float.MaxValue);
cinemachineTargetPitch = MathExtensions.ClampAngle(cinemachineTargetPitch, bottomClamp, topClamp);
viewSc.cameraRoot.rotation = Quaternion.Euler(
cinemachineTargetPitch + cameraAngleOverride /*- viewSc.muzzleLiftModule.currentMuzzlePositionY*/, cinemachineTargetYaw, 0.0f);
if (viewSc.isLockingTarget)
{
cinemachineEndLockYaw = viewSc.lockOnCamera.transform.eulerAngles.y;
}
/*
if (player.motionController.characterRotationType == PlayerMotionController.CharacterRotationType.ByAiming)
{
player.transform.rotation = Quaternion.Euler(0.0f, cinemachineTargetYaw, 0.0f);
if (viewSc.lockTargetModule.isLockedMelee)
{
//cinemachineEndLockYaw = player.viewController.lockingCamera.transform.eulerAngles.y;
//player.transform.rotation = Quaternion.Euler(0.0f, cinemachineEndLockYaw, 0.0f);
}
}
else
{
if (viewSc.lockTargetModule.isLockedMelee)
{
cinemachineEndLockYaw = viewSc.lockingCamera.transform.eulerAngles.y;
}
}
*/
}
/// <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;
}
// 将此方法添加到你控制相机旋转的脚本中 (例如 PlayerCameraController)
public void SyncRotationWithCamera(Camera camera = null)
{
camera ??= viewSc.playerCamera;
Vector3 currentEuler = camera.transform.eulerAngles;
cinemachineTargetYaw = currentEuler.y;
float currentPitch = currentEuler.x;
if (currentPitch > 180)
{
currentPitch -= 360;
}
cinemachineTargetPitch = currentPitch - cameraAngleOverride;
isRecentering = false;
// 强制执行一次旋转更新,防止下一帧才生效导致的微小跳动 (可选)
// viewSc.cameraRoot.rotation = Quaternion.Euler(
// cinemachineTargetPitch + cameraAngleOverride, cinemachineTargetYaw, 0.0f);
}
}
}