做不出来

This commit is contained in:
SoulliesOfficial
2026-06-30 01:48:58 -04:00
parent 9a9e48f8a5
commit ddd387ef35
132 changed files with 8945 additions and 2943 deletions

View File

@@ -0,0 +1,326 @@
using System.Collections.Generic;
using SLSUtilities.Feedback;
using Unity.Cinemachine;
using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
public class CameraOrbitShakeInstance : ShakeInstanceBase
{
// Yaw 设置
public bool enableYaw;
public CameraOrbitAction.OrbitMode yawMode;
public FloatCurveChannel horizontalCurve;
public float startHorizontalValue;
public float worldEndHorizontalValue;
public AnimationCurve yawEaseCurve;
// Pitch 设置
public bool enablePitch;
public CameraOrbitAction.OrbitMode pitchMode;
public FloatCurveChannel verticalCurve;
public float startVerticalValue;
public float worldEndVerticalValue;
public AnimationCurve pitchEaseCurve;
public CameraOrbitShakeInstance(FeedbackTimeSettings timeSettings, IFeedbackTimeProvider timeProvider,
CameraOrbitAction action, float startH, float startV, float worldEndH, float worldEndV, float duration)
: base(timeSettings, timeProvider, duration)
{
this.enableYaw = action.enableYaw;
this.yawMode = action.yawMode;
this.horizontalCurve = action.horizontalCurve;
this.startHorizontalValue = startH;
this.worldEndHorizontalValue = worldEndH;
this.yawEaseCurve = action.yawEaseCurve;
this.enablePitch = action.enablePitch;
this.pitchMode = action.pitchMode;
this.verticalCurve = action.verticalCurve;
this.startVerticalValue = startV;
this.worldEndVerticalValue = worldEndV;
this.pitchEaseCurve = action.pitchEaseCurve;
}
/// <summary>
/// 在 TargetValue 模式下,根据归一化时间计算当前水平角度。
/// </summary>
public float EvaluateHorizontal(float normalizedTime)
{
if (yawMode == CameraOrbitAction.OrbitMode.Additive)
{
return horizontalCurve.Evaluate(normalizedTime);
}
float t = yawEaseCurve != null ? yawEaseCurve.Evaluate(Mathf.Clamp01(normalizedTime)) : normalizedTime;
return Mathf.LerpUnclamped(startHorizontalValue, worldEndHorizontalValue, t);
}
/// <summary>
/// 在 TargetValue 模式下,根据归一化时间计算当前垂直角度。
/// </summary>
public float EvaluateVertical(float normalizedTime)
{
if (pitchMode == CameraOrbitAction.OrbitMode.Additive)
{
return verticalCurve.Evaluate(normalizedTime);
}
float t = pitchEaseCurve != null ? pitchEaseCurve.Evaluate(Mathf.Clamp01(normalizedTime)) : normalizedTime;
return Mathf.LerpUnclamped(startVerticalValue, worldEndVerticalValue, t);
}
}
public struct CameraOrbitEvent
{
private static event ShakeDelegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RuntimeInitialization() { OnEvent = null; }
public delegate void ShakeDelegate(
FeedbackContext feedbackContext,
CameraOrbitAction action,
bool stop
);
public static void Register(ShakeDelegate callback) { OnEvent += callback; }
public static void Unregister(ShakeDelegate callback) { OnEvent -= callback; }
public static void Trigger(
FeedbackContext feedbackContext,
CameraOrbitAction action,
bool stop = false)
{
OnEvent?.Invoke(feedbackContext, action, stop);
}
}
[AddComponentMenu("Cielonos/Feedback Shakers/Camera Orbit Shaker")]
[RequireComponent(typeof(CinemachineCamera))]
[RequireComponent(typeof(CinemachineOrbitalFollow))]
public class CameraOrbitShaker : MonoBehaviour
{
private CinemachineCamera _camera;
private CinemachineOrbitalFollow _orbitalFollow;
private CinemachineInputAxisController _inputController;
[Tooltip("目标参考的 Transform。当 CameraOrbitAction 处于 TargetValue 模式时,将以此为基准转换 endHorizontalValue 为世界空间角度。" +
"如果为空,则默认使用 MainGameManager.Player.transform若仍为空则回退到相机的 Follow 目标。")]
[SerializeField] private Transform targetReference;
private float _baseHorizontalValue;
private float _baseVerticalValue;
private bool _hasBaseValuesCaptured;
private readonly List<CameraOrbitShakeInstance> _activeShakes = new List<CameraOrbitShakeInstance>();
public float CurrentHorizontalOffset { get; private set; }
public float CurrentVerticalOffset { get; private set; }
public bool HasActiveShakes => _activeShakes.Count > 0;
private void Awake()
{
_camera = GetComponent<CinemachineCamera>();
_orbitalFollow = GetComponent<CinemachineOrbitalFollow>();
_inputController = GetComponent<CinemachineInputAxisController>();
}
private void OnEnable()
{
CameraOrbitEvent.Register(OnShakeEvent);
}
private void OnDisable()
{
CameraOrbitEvent.Unregister(OnShakeEvent);
StopAll();
}
private void Update()
{
if (_orbitalFollow == null) return;
if (_activeShakes.Count == 0)
{
CurrentHorizontalOffset = 0f;
CurrentVerticalOffset = 0f;
if (_hasBaseValuesCaptured)
{
// 所有 Shake 结束:恢复玩家输入控制器
if (_inputController != null && !_inputController.enabled)
{
_inputController.enabled = true;
}
_hasBaseValuesCaptured = false;
}
return;
}
// 首次触发时捕获当前相机角度作为基准
if (!_hasBaseValuesCaptured)
{
_baseHorizontalValue = _orbitalFollow.HorizontalAxis.Value;
_baseVerticalValue = _orbitalFollow.VerticalAxis.Value;
_hasBaseValuesCaptured = true;
}
// 区分模式与轨道进行独立计算
float finalHorizontal = _baseHorizontalValue;
float finalVertical = _baseVerticalValue;
for (int i = _activeShakes.Count - 1; i >= 0; i--)
{
CameraOrbitShakeInstance shake = _activeShakes[i];
shake.Tick();
float normalizedTime = shake.timer / shake.duration;
// 独立水平轴计算
if (shake.enableYaw)
{
if (shake.yawMode == CameraOrbitAction.OrbitMode.Additive)
{
finalHorizontal += shake.EvaluateHorizontal(normalizedTime);
}
else
{
finalHorizontal = shake.EvaluateHorizontal(normalizedTime);
}
}
// 独立垂直轴计算
if (shake.enablePitch)
{
if (shake.pitchMode == CameraOrbitAction.OrbitMode.Additive)
{
finalVertical += shake.EvaluateVertical(normalizedTime);
}
else
{
finalVertical = shake.EvaluateVertical(normalizedTime);
}
}
if (shake.IsFinished)
{
_activeShakes.RemoveAt(i);
}
}
// 管理玩家输入控制器状态(有任何活跃 Orbit Shake 时必定禁用输入)
if (_inputController != null && _inputController.enabled)
{
_inputController.enabled = false;
}
// 计算提供给锁锁相机的当前偏差量
CurrentHorizontalOffset = finalHorizontal - _baseHorizontalValue;
CurrentVerticalOffset = finalVertical - _baseVerticalValue;
// 检查当前是否在使用锁定相机的硬锁状态,若是,则由 LockTargetSubmodule 接管赋值,避免冲突
bool isLocking = MainGameManager.Player != null &&
MainGameManager.Player.viewSc.lockTargetModule != null &&
MainGameManager.Player.viewSc.lockTargetModule.isUsingLockTargetCamera &&
gameObject == MainGameManager.Player.viewSc.lockingTargetCamera.gameObject;
if (!isLocking)
{
// 非锁定状态下直接赋值
_orbitalFollow.HorizontalAxis.Value = finalHorizontal;
_orbitalFollow.VerticalAxis.Value = finalVertical;
}
}
private void OnShakeEvent(
FeedbackContext feedbackContext,
CameraOrbitAction action,
bool stop)
{
if (stop) { StopAll(); return; }
// 仅在当前组件附加的虚拟相机是当前激活相机时,才响应 Orbit 动作,防止后台相机数据被污染
bool isActiveCamera = MainGameManager.Player != null &&
MainGameManager.Player.viewSc.currentCamera != null &&
gameObject == MainGameManager.Player.viewSc.currentCamera.gameObject;
if (!isActiveCamera) return;
// 检查当前是否在使用锁定相机的硬锁状态
bool isLocking = MainGameManager.Player != null &&
MainGameManager.Player.viewSc.lockTargetModule != null &&
MainGameManager.Player.viewSc.lockTargetModule.isUsingLockTargetCamera &&
gameObject == MainGameManager.Player.viewSc.lockingTargetCamera.gameObject;
// 根据当前相机状态与配置决定是否生效
if (isLocking && !action.enableInLockTarget) return;
if (!isLocking && !action.enableInFreeLook) return;
// 获取当前轴值作为 TargetValue 模式的起始值
float currentH = _orbitalFollow != null ? _orbitalFollow.HorizontalAxis.Value : 0f;
float currentV = _orbitalFollow != null ? _orbitalFollow.VerticalAxis.Value : 0f;
// 解析水平目标值与垂直目标值
float worldEndH = currentH;
float worldEndV = action.endVerticalValue;
// 水平 (Yaw) 解析
if (action.enableYaw && action.yawMode == CameraOrbitAction.OrbitMode.TargetValue)
{
Transform reference = targetReference != null ? targetReference : (MainGameManager.Player != null ? MainGameManager.Player.transform : _camera?.Follow);
float playerYaw = reference != null ? reference.eulerAngles.y : 0f;
float targetAngle = playerYaw + action.endHorizontalValue;
if (action.shortestPath)
{
worldEndH = currentH + Mathf.DeltaAngle(currentH, targetAngle);
}
else
{
worldEndH = targetAngle;
}
}
// 垂直 (Pitch) 解析
if (action.enablePitch && action.pitchMode == CameraOrbitAction.OrbitMode.TargetValue)
{
if (isLocking)
{
// 硬锁相机下垂直仰角Pitch的 TargetValue 是相对于触发时的基准仰角的相对偏移
worldEndV = currentV + action.endVerticalValue;
}
else
{
worldEndV = action.endVerticalValue;
}
}
var instance = new CameraOrbitShakeInstance(
feedbackContext.timeSettings,
feedbackContext.player.TimeProvider,
action,
currentH,
currentV,
worldEndH,
worldEndV,
feedbackContext.duration
);
_activeShakes.Add(instance);
}
private void StopAll()
{
_activeShakes.Clear();
if (_hasBaseValuesCaptured && _orbitalFollow != null)
{
_orbitalFollow.HorizontalAxis.Value = _baseHorizontalValue;
_orbitalFollow.VerticalAxis.Value = _baseVerticalValue;
}
if (_inputController != null)
{
_inputController.enabled = true;
}
_hasBaseValuesCaptured = false;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 646548dbf6035f04a8a01e875996d327