Bezi回来了

This commit is contained in:
SoulliesOfficial
2026-04-28 15:46:32 -04:00
parent 7379583165
commit 0902ca8a9e
56 changed files with 3285 additions and 3803 deletions

View File

@@ -0,0 +1,134 @@
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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1a007afcee9fd864cb29a8405fdc4d71

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using DG.Tweening;
using SickscoreGames.HUDNavigationSystem;
using UniRx;
@@ -31,8 +32,13 @@ namespace Cielonos.MainGame.Characters
/// 是否正在使用锁定目标摄像机
/// </summary>
public bool isUsingLockTargetCamera => isLocking && isAutoRotate;
public bool isDuringSwitch;
public bool isDuringCameraSwitch;
private const float CameraSwitchCooldown = 0.25f;
public CharacterBase lockTarget;
private float lastTargetSwitchTime;
private const float TargetSwitchCooldown = 0.25f;
public Transform targetPoint;
private Tweener iconTween;
@@ -40,20 +46,27 @@ namespace Cielonos.MainGame.Characters
{
isLocking = false;
isAutoRotate = false;
isDuringSwitch = false;
isDuringCameraSwitch = false;
lockTarget = null;
targetPoint = null;
}
public void Update()
{
if (isUsingLockTargetCamera && !isDuringSwitch)
if (isUsingLockTargetCamera && !isDuringCameraSwitch)
{
viewSc.cameraRoot.LookAt(targetPoint);
float distance = (targetPoint.position - viewSc.cameraRoot.transform.position).Flatten().magnitude;
if (isUsingLockTargetCamera && distance < 1f)
if (targetPoint != null)
{
UnlockTarget();
// 平滑跟随目标
Vector3 currentRotation = viewSc.cameraRoot.eulerAngles;
Vector3 targetDirection = targetPoint.position - viewSc.cameraRoot.position;
Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
viewSc.cameraRoot.rotation = Quaternion.Slerp(
viewSc.cameraRoot.rotation,
targetRotation,
1f - Mathf.Exp(-10f * Time.deltaTime)
);
}
}
}
@@ -75,7 +88,7 @@ namespace Cielonos.MainGame.Characters
public void LockTarget(bool isAutoRotate)
{
if(isDuringSwitch) return;
if(isDuringCameraSwitch) return;
CharacterBase target = BattleManager.EnemySm.GetNearestEnemy(50f);
@@ -84,7 +97,7 @@ namespace Cielonos.MainGame.Characters
this.isLocking = true;
this.isAutoRotate = isAutoRotate;
this.lockTarget = target;
this.isDuringSwitch = true;
this.isDuringCameraSwitch = true;
if (isAutoRotate)
{
@@ -94,14 +107,14 @@ namespace Cielonos.MainGame.Characters
viewSc.stateDrivenCamera.GetComponent<Animator>().SetBool("isLockTarget", true);
viewSc.cameraRoot.DOLookAt(targetPoint.position, 0.5f)
.SetEase(Ease.InOutSine)
.OnComplete(() => { isDuringSwitch = false; })
.OnComplete(() => { isDuringCameraSwitch = false; })
.Play();
}
else
{
Observable.Timer(TimeSpan.FromSeconds(0.5f)).First().Subscribe(_ =>
{
isDuringSwitch = false;
isDuringCameraSwitch = false;
});
}
@@ -114,7 +127,7 @@ namespace Cielonos.MainGame.Characters
public void UnlockTarget()
{
if(isDuringSwitch) return;
if(isDuringCameraSwitch) return;
Vector3 currentEuler = viewSc.playerCamera.transform.rotation.eulerAngles;
@@ -134,12 +147,76 @@ namespace Cielonos.MainGame.Characters
orbitalFollow.HorizontalAxis.Value = newYaw;
orbitalFollow.VerticalAxis.Value = newPitch;
if (lockTarget != null)
{
lockTarget.navigationElement.showIndicator = false;
}
this.isLocking = false;
this.isAutoRotate = false;
this.lockTarget.navigationElement.showIndicator = false;
this.lockTarget = null;
this.targetPoint = null;
viewSc.stateDrivenCamera.GetComponent<Animator>().SetBool("isLockTarget", false);
}
/// <summary>
/// 切换锁定目标
/// </summary>
public void SwitchTarget(float direction)
{
if (!isLocking || isDuringCameraSwitch) return;
if (Time.time - lastTargetSwitchTime < TargetSwitchCooldown) return;
List<CharacterBase> sortedEnemies = BattleManager.EnemySm.GetVisibleEnemiesSortedByScreenX();
if (sortedEnemies.Count <= 1) return;
int currentIndex = sortedEnemies.IndexOf(lockTarget);
if (currentIndex < 0)
{
currentIndex = 0;
}
int dir = direction > 0 ? -1 : 1;
int newIndex = currentIndex + dir;
// 边界检查(无循环)
if (newIndex < 0 || newIndex >= sortedEnemies.Count)
{
return;
}
CharacterBase newTarget = sortedEnemies[newIndex];
// 目标相同检查
if (newTarget == lockTarget)
{
return;
}
lastTargetSwitchTime = Time.time;
SetNewTarget(sortedEnemies[newIndex]);
}
private void SetNewTarget(CharacterBase newTarget)
{
if (lockTarget != null)
{
lockTarget.navigationElement.showIndicator = false;
}
lockTarget = newTarget;
targetPoint = newTarget.bodyPartsSc.cameraLockingPoint ?? newTarget.bodyPartsSc.staticCenterPoint;
if (isUsingLockTargetCamera)
{
viewSc.lockingTargetCamera.LookAt = targetPoint;
}
lockTarget.navigationElement.showIndicator = true;
Image icon = lockTarget.navigationElement.Indicator.OnscreenIcon;
iconTween?.Kill(true);
iconTween = icon.GetComponent<RectTransform>().DOScale(1f, 0.3f).From(0.5f).SetEase(Ease.OutQuart).Play();
}
}
}

View File

@@ -21,6 +21,7 @@ namespace Cielonos.MainGame.Characters
public CinemachineCamera lockingTargetCamera;
public CharacterBase testEnemy;
public CameraFovSubmodule cameraFovSm;
public CameraRotationSubmodule cameraRotationSm;
public OcclusionFadeSubmodule occlusionFadeSm;
public LockTargetSubmodule lockTargetModule;
@@ -30,10 +31,14 @@ namespace Cielonos.MainGame.Characters
public override void Initialize()
{
base.Initialize();
cameraFovSm = new CameraFovSubmodule(this, 30f, 30f, 40f, 0.1f, 10f, 5f, true);
cameraRotationSm = new CameraRotationSubmodule(this, player.transform.eulerAngles.y);
occlusionFadeSm = new OcclusionFadeSubmodule(this);
lockTargetModule = new LockTargetSubmodule(this);
cameraFOV = new LerpFloat(30f, 2f);
player.operationSc.OnLockonTarget += lockTargetModule.SwitchLockState;
player.operationSc.OnSelectLockonTarget += lockTargetModule.SwitchTarget;
}
private void Start()
@@ -43,11 +48,6 @@ namespace Cielonos.MainGame.Characters
private void Update()
{
if (Keyboard.current.tabKey.wasPressedThisFrame)
{
lockTargetModule.SwitchLockState();
}
/*cameraFOV.targetValue = owner.landMovementSc.isSprinting ? 40f : 30f;
cameraFOV.Update(owner.selfTimeSm.DeltaTime);
freeLookCamera.Lens.FieldOfView = cameraFOV.currentValue;*/