Bezi回来了
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Cielonos.MainGame.Effects.Feedback;
|
||||
using SLSUtilities.General;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
@@ -22,9 +23,6 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
player.landMovementSc.TurnToDirection(direction, 0f);
|
||||
}
|
||||
|
||||
// 计算冲刺方向用于相机震动方向设置
|
||||
// Dash反馈的方向设置将在DashStart中通过新Feedback系统统一处理
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,10 +30,15 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
player.landMovementSc.isDashing = true;
|
||||
player.audioSc.PlayDashSound();
|
||||
|
||||
// 使用新Feedback系统播放Dash反馈
|
||||
player.feedbackSc.PlayFeedback("Dash");
|
||||
|
||||
|
||||
Vector3 playerForward = player.transform.forward.Flatten();
|
||||
Vector3 cameraForward = player.viewSc.playerCamera.transform.forward.Flatten();
|
||||
float forwardDot = Vector3.Dot(playerForward, cameraForward);
|
||||
//如果角色和相机的角度相差120度以上
|
||||
//播放普通Dash反馈
|
||||
//播放背向Dash反馈
|
||||
player.feedbackSc.PlayFeedback(forwardDot < -0.5f ? "Dash_NoCameraRotation" : "Dash");
|
||||
|
||||
//player.renderSc.dashTrails.ForEach(ds => ds.active = true);
|
||||
//player.renderSc.dashTrails.ForEach(ds => ds.Restart());
|
||||
|
||||
|
||||
@@ -117,11 +117,20 @@ namespace Cielonos.MainGame.Characters
|
||||
}
|
||||
};
|
||||
|
||||
inputActions.Player.LockOnTarget.performed += ctx =>
|
||||
inputActions.Player.LockonTarget.performed += ctx =>
|
||||
{
|
||||
if (ctx.performed && isCursorLocked.Value)
|
||||
{
|
||||
operation.LockOnTarget();
|
||||
operation.LockonTarget();
|
||||
}
|
||||
};
|
||||
|
||||
inputActions.Player.SelectLockonTarget.performed += ctx =>
|
||||
{
|
||||
if (ctx.performed && isCursorLocked.Value)
|
||||
{
|
||||
Debug.Log("Value: " + ctx.ReadValue<float>());
|
||||
operation.SelectLockonTarget(ctx.ReadValue<float>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -159,7 +159,12 @@ namespace Cielonos.MainGame.Characters.Inventory
|
||||
comboSm?[comboTreeName].SuspendThenSetup(actionCoolDownTime);
|
||||
if (target != null)
|
||||
{
|
||||
if (autoRotate) player.landMovementSc.TurnToTarget(target);
|
||||
if (autoRotate)
|
||||
{
|
||||
float angleLimit = player.viewSc.lockTargetModule.isLocking ? 240 : 150;
|
||||
player.landMovementSc.SmartTurnToTarget(target, angleLimit);
|
||||
}
|
||||
|
||||
if (keepAdsorption)
|
||||
{
|
||||
funcAnimSm.currentRuntimeFuncAnim.AddUpdateEvent(new SetRootAdsorptionAdjustment.Keep(target, adsorptionMinDistance));
|
||||
@@ -185,13 +190,15 @@ namespace Cielonos.MainGame.Characters.Inventory
|
||||
Debug.LogWarning($"没有找到名为 'Camera' 的轨道,请检查 FeedbackData '{feedBackName}' 的设置。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cameraTrack.clips.Find(clip => clip.action is CameraPositionShakeAction)?.action is CameraPositionShakeAction positionShakeAction)
|
||||
|
||||
var positionShakeAction = feedBackData.Action<CameraPositionShakeAction>("Camera");
|
||||
if (positionShakeAction != null)
|
||||
{
|
||||
positionShakeAction.amplitude = swingPosition;
|
||||
}
|
||||
|
||||
if (cameraTrack.clips.Find(clip => clip.action is CameraRotationShakeAction)?.action is CameraRotationShakeAction rotationShakeAction)
|
||||
|
||||
var rotationShakeAction = feedBackData.Action<CameraRotationShakeAction>("Camera");
|
||||
if (rotationShakeAction != null)
|
||||
{
|
||||
rotationShakeAction.amplitude = swingRotation;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Cielonos.MainGame.Characters
|
||||
eventSm.onHealthChanged.InsertByPriority("UI_HealthBarUpdate", new PrioritizedAction<float>(UI_HealthBarUpdate));
|
||||
eventSm.onEnergyChanged.InsertByPriority("UI_EnergyBarUpdate", new PrioritizedAction<float>(UI_EnergyBarUpdate));
|
||||
|
||||
eventSm.onDodgeStart.InsertByPriority("Feedback_DodgeStart", new PrioritizedAction(() => { feedbackSc.PlayFeedback("PerfectDodge"); }));
|
||||
//eventSm.onDodgeStart.InsertByPriority("Feedback_DodgeStart", new PrioritizedAction(() => { feedbackSc.PlayFeedback("PerfectDodge"); }));
|
||||
eventSm.onNormalDodgeSuccess.InsertByPriority("Feedback_NormalDodge", new PrioritizedAction<AttackAreaBase, DodgeSource>(Feedback_NormalDodge));
|
||||
eventSm.onPerfectDodgeSuccess.InsertByPriority("Feedback_PerfectDodge", new PrioritizedAction<AttackAreaBase, DodgeSource>(Feedback_PerfectDodge));
|
||||
}
|
||||
@@ -113,14 +113,14 @@ namespace Cielonos.MainGame.Characters
|
||||
BreakthroughType breakthroughType = attackArea.attackSm.attackValue.breakthroughType;
|
||||
if(breakthroughType == BreakthroughType.None) return;
|
||||
string feedbackName = "GetHit" + breakthroughType.ToString();
|
||||
feedbackSc[feedbackName]?.Play();
|
||||
feedbackSc.PlayFeedback(feedbackName);
|
||||
}
|
||||
|
||||
private void Feedback_GetAttacked(AttackAreaBase attackArea, AttackResult attackResult)
|
||||
{
|
||||
float ratio = attackResult.finalDamage / (attributeSm["MaximumHealth"] * 0.2f);
|
||||
float intensity = Mathf.Lerp(0.25f, 1f, ratio);
|
||||
feedbackSc["GetAttacked"]?.Play();
|
||||
//feedbackSc.GetFeedbackData("GetAttacked")
|
||||
}
|
||||
|
||||
private void Feedback_PerfectDodge(AttackAreaBase attackArea, DodgeSource dodgeSource)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using Cielonos.MainGame.Effects.Feedback;
|
||||
using DG.Tweening;
|
||||
using SLSUtilities.General;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UniRx;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
@@ -249,6 +251,8 @@ namespace Cielonos.MainGame.Characters
|
||||
float horizontalSpeed = horizontalMovement.magnitude / DeltaTime;
|
||||
float remapFactor = Mathf.InverseLerp(10f, 15f, horizontalSpeed);
|
||||
PostProcessingManager.Instance.speedLinesSm.SetRemap(1 - remapFactor);
|
||||
|
||||
//player.viewSc.cameraFovSm.UpdateFovBySpeed(horizontalSpeed, DeltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace Cielonos.MainGame.Characters
|
||||
public event Action<Vector3, float> OnDash;
|
||||
public event Action<float> OnDodge;
|
||||
|
||||
public event Action OnLockOnTarget;
|
||||
public event Action OnLockonTarget;
|
||||
public event Action<float> OnSelectLockonTarget;
|
||||
|
||||
public event Action OnWalkPress;
|
||||
public event Action OnWalkRelease;
|
||||
@@ -70,7 +71,9 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
public void Dodge(float length = -1) => OnDodge?.Invoke(length);
|
||||
|
||||
public void LockOnTarget() => OnLockOnTarget?.Invoke();
|
||||
public void LockonTarget() => OnLockonTarget?.Invoke();
|
||||
|
||||
public void SelectLockonTarget(float direction) => OnSelectLockonTarget?.Invoke(direction);
|
||||
|
||||
public void WalkPress() => OnWalkPress?.Invoke();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a007afcee9fd864cb29a8405fdc4d71
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;*/
|
||||
|
||||
Reference in New Issue
Block a user