Bezi回来了
This commit is contained in:
@@ -74,7 +74,7 @@ namespace Cielonos.MainGame.Characters.AI
|
||||
|
||||
if (willTurnToTargetAtStart)
|
||||
{
|
||||
self.movementSc.TurnToTarget(target);
|
||||
self.movementSc.SmartTurnToTarget(target);
|
||||
}
|
||||
|
||||
if (willAdjustAdsorption)
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Cielonos.MainGame.Characters.AI
|
||||
|
||||
if (willTurnToTarget)
|
||||
{
|
||||
self.movementSc.TurnToTarget(target);
|
||||
self.movementSc.SmartTurnToTarget(target);
|
||||
}
|
||||
|
||||
if (willAdjustAdsorption)
|
||||
|
||||
@@ -47,9 +47,28 @@ namespace Cielonos.MainGame.Characters
|
||||
}
|
||||
}
|
||||
|
||||
public void TurnToTarget(CharacterBase target, float duration = 0.2f)
|
||||
public void SmartTurnToTarget(CharacterBase target, float maxTurnAngle = 150f)
|
||||
{
|
||||
characterTransform.DOLookAt(target.transform.position, duration, AxisConstraint.Y).Play();
|
||||
Vector3 directionToTarget = (target.centerPoint.position - owner.centerPoint.position).Flatten();
|
||||
if (directionToTarget.sqrMagnitude < 0.001f) return;
|
||||
|
||||
float angleToTarget = Vector3.SignedAngle(owner.transform.forward, directionToTarget, Vector3.up);
|
||||
float absAngle = Mathf.Abs(angleToTarget);
|
||||
|
||||
// 超过最大角度不转身
|
||||
if (absAngle > maxTurnAngle) return;
|
||||
|
||||
// 小角度瞬间转身
|
||||
if (absAngle <= 45f)
|
||||
{
|
||||
owner.transform.rotation = Quaternion.LookRotation(directionToTarget);
|
||||
}
|
||||
// 大角度平滑转身
|
||||
else
|
||||
{
|
||||
float duration = Mathf.Lerp(0.1f, 0.2f, (absAngle - 45f) / 135f);
|
||||
owner.transform.DORotateQuaternion(Quaternion.LookRotation(directionToTarget), duration).Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void TurnToTargetByAngle(CharacterBase target, float angularSpeed)
|
||||
|
||||
@@ -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;*/
|
||||
|
||||
@@ -12,29 +12,21 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
[Serializable]
|
||||
public struct FloatCurveChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否启用此通道。
|
||||
/// </summary>
|
||||
public bool active;
|
||||
|
||||
/// <summary>
|
||||
/// 震动曲线,X轴为归一化时间[0,1],Y轴为强度[0,1]。
|
||||
/// </summary>
|
||||
[ShowIf("active")]
|
||||
[ShakeCurvePreset]
|
||||
public AnimationCurve curve;
|
||||
|
||||
/// <summary>
|
||||
/// 曲线值0对应的实际数值。
|
||||
/// </summary>
|
||||
[ShowIf("active")]
|
||||
[LabelText("Remap Min")]
|
||||
public float remapMin;
|
||||
|
||||
/// <summary>
|
||||
/// 曲线值1对应的实际数值。
|
||||
/// </summary>
|
||||
[ShowIf("active")]
|
||||
[LabelText("Remap Max")]
|
||||
public float remapMax;
|
||||
|
||||
@@ -47,11 +39,10 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
/// <summary>
|
||||
/// 创建默认的曲线通道。
|
||||
/// </summary>
|
||||
public static FloatCurveChannel CreateDefault(bool active = true, float remapMin = 0f, float remapMax = 1f, bool relativeToInitial = true)
|
||||
public static FloatCurveChannel CreateDefault(float remapMin = 0f, float remapMax = 1f, bool relativeToInitial = true)
|
||||
{
|
||||
return new FloatCurveChannel
|
||||
{
|
||||
active = active,
|
||||
curve = new AnimationCurve(
|
||||
new Keyframe(0f, 0f),
|
||||
new Keyframe(0.5f, 1f),
|
||||
@@ -68,7 +59,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
/// </summary>
|
||||
public readonly float Evaluate(float normalizedTime)
|
||||
{
|
||||
if (!active || curve == null) return 0f;
|
||||
if (curve == null) return 0f;
|
||||
float t = Mathf.Clamp01(normalizedTime);
|
||||
float curveValue = curve.Evaluate(t);
|
||||
return Mathf.LerpUnclamped(remapMin, remapMax, curveValue);
|
||||
@@ -81,15 +72,9 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
[Serializable]
|
||||
public struct ColorCurveChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否启用此通道。
|
||||
/// </summary>
|
||||
public bool active;
|
||||
|
||||
/// <summary>
|
||||
/// 颜色渐变。
|
||||
/// </summary>
|
||||
[ShowIf("active")]
|
||||
[LabelText("颜色渐变")]
|
||||
public Gradient gradient;
|
||||
|
||||
@@ -100,7 +85,6 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
return new ColorCurveChannel
|
||||
{
|
||||
active = true,
|
||||
gradient = new Gradient()
|
||||
};
|
||||
}
|
||||
@@ -110,7 +94,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
/// </summary>
|
||||
public Color Evaluate(float normalizedTime)
|
||||
{
|
||||
if (!active || gradient == null) return Color.white;
|
||||
if (gradient == null) return Color.white;
|
||||
return gradient.Evaluate(Mathf.Clamp01(normalizedTime));
|
||||
}
|
||||
}
|
||||
@@ -121,23 +105,17 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
[Serializable]
|
||||
public struct Vector2CurveChannel
|
||||
{
|
||||
public bool active;
|
||||
|
||||
[ShowIf("active")]
|
||||
[LabelText("曲线 X")]
|
||||
[ShakeCurvePreset]
|
||||
public AnimationCurve curveX;
|
||||
|
||||
[ShowIf("active")]
|
||||
|
||||
[LabelText("曲线 Y")]
|
||||
[ShakeCurvePreset]
|
||||
public AnimationCurve curveY;
|
||||
|
||||
[ShowIf("active")]
|
||||
|
||||
[LabelText("Remap Min")]
|
||||
public Vector2 remapMin;
|
||||
|
||||
[ShowIf("active")]
|
||||
|
||||
[LabelText("Remap Max")]
|
||||
public Vector2 remapMax;
|
||||
|
||||
@@ -153,7 +131,6 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
return new Vector2CurveChannel
|
||||
{
|
||||
active = true,
|
||||
curveX = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f)),
|
||||
curveY = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f)),
|
||||
remapMin = Vector2.zero,
|
||||
@@ -164,9 +141,8 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
/// <summary>
|
||||
/// 根据归一化时间计算Vector2值。
|
||||
/// </summary>
|
||||
public Vector2 Evaluate(float normalizedTime, Vector2 initialValue)
|
||||
public readonly Vector2 Evaluate(float normalizedTime, Vector2 initialValue)
|
||||
{
|
||||
if (!active) return Vector2.zero;
|
||||
float t = Mathf.Clamp01(normalizedTime);
|
||||
float x = curveX?.Evaluate(t) ?? 0f;
|
||||
float y = curveY?.Evaluate(t) ?? 0f;
|
||||
|
||||
@@ -39,26 +39,19 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
/// 将给定的本地空间向量根据当前设置转换到世界空间。
|
||||
/// 如果两个方向都开启,角色方向优先。
|
||||
/// </summary>
|
||||
/// <param name="localAmplitude">本地空间下的振幅向量</param>
|
||||
/// <param name="standardScreenVector">在摄像机和角色相同朝向时,屏幕空间的振幅向量</param>
|
||||
/// <param name="ownerTransform">角色 Transform(可能为 null)</param>
|
||||
/// <returns>经方向变换后的振幅向量</returns>
|
||||
public Vector3 TransformAmplitude(Vector3 localAmplitude, Transform ownerTransform)
|
||||
public Vector3 TransformAmplitude(Vector3 standardScreenVector, Transform ownerTransform)
|
||||
{
|
||||
if (affectedByCharacterDirection && ownerTransform != null)
|
||||
{
|
||||
return ownerTransform.TransformDirection(localAmplitude);
|
||||
}
|
||||
Camera mainCamera = MainGameManager.Instance?.player?.viewSc?.playerCamera;
|
||||
if (mainCamera == null) return standardScreenVector;
|
||||
|
||||
if (affectedByCameraDirection)
|
||||
{
|
||||
Camera mainCamera = MainGameManager.Instance.player.viewSc.playerCamera;
|
||||
if (mainCamera != null)
|
||||
{
|
||||
return mainCamera.transform.TransformDirection(localAmplitude);
|
||||
}
|
||||
}
|
||||
Quaternion characterRotation = ownerTransform?.rotation ?? Quaternion.identity;
|
||||
Quaternion cameraRotation = mainCamera.transform.rotation;
|
||||
|
||||
return localAmplitude;
|
||||
Quaternion deltaRotation = Quaternion.Inverse(cameraRotation) * characterRotation;
|
||||
return deltaRotation * standardScreenVector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
[TitleGroup("FOV设置")]
|
||||
[LabelText("FOV曲线")]
|
||||
public FloatCurveChannel fovCurve = FloatCurveChannel.CreateDefault(remapMax: 10f);
|
||||
public FloatCurveChannel fovCurve = FloatCurveChannel.CreateDefault();
|
||||
|
||||
protected override void TriggerEvent(FeedbackContext context)
|
||||
{
|
||||
@@ -30,11 +30,6 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
public override bool Validate(out string error)
|
||||
{
|
||||
if (!fovCurve.active)
|
||||
{
|
||||
error = "FOV curve is not enabled.";
|
||||
return false;
|
||||
}
|
||||
error = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
Vector3 finalAmplitude = directionSettings.TransformAmplitude(amplitude, context.owner);
|
||||
float intensityMultiplier = ComputeAttenuation(context);
|
||||
CameraRotationShakeEvent.Trigger(context, intensityCurve, finalAmplitude * intensityMultiplier);
|
||||
CameraPositionShakeEvent.Trigger(context, intensityCurve, finalAmplitude * intensityMultiplier);
|
||||
}
|
||||
|
||||
protected override void StopEvent(FeedbackContext context)
|
||||
@@ -66,11 +66,6 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
public override bool Validate(out string error)
|
||||
{
|
||||
if (!intensityCurve.active)
|
||||
{
|
||||
error = "Intensity curve is not enabled.";
|
||||
return false;
|
||||
}
|
||||
error = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
public Vector3 amplitude;
|
||||
|
||||
[LabelText("X轴曲线")]
|
||||
public FloatCurveChannel intensityCurve = FloatCurveChannel.CreateDefault(remapMax: 5f);
|
||||
public FloatCurveChannel intensityCurve = FloatCurveChannel.CreateDefault();
|
||||
|
||||
public CameraDirectionSettings directionSettings = new CameraDirectionSettings();
|
||||
|
||||
@@ -40,8 +39,8 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
protected override void TriggerEvent(FeedbackContext context)
|
||||
{
|
||||
Vector3 finalAmplitude = directionSettings.TransformAmplitude(amplitude, context.owner);
|
||||
float intensityMultiplier = ComputeAttenuation(context);
|
||||
CameraRotationShakeEvent.Trigger(context, intensityCurve, finalAmplitude * intensityMultiplier);
|
||||
float attenuation = ComputeAttenuation(context);
|
||||
CameraRotationShakeEvent.Trigger(context, intensityCurve, finalAmplitude * attenuation);
|
||||
}
|
||||
|
||||
protected override void StopEvent(FeedbackContext context)
|
||||
|
||||
@@ -58,11 +58,11 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
AnimeACESShakeEvent.Trigger(
|
||||
context,
|
||||
exposureChannel,
|
||||
contrastChannel,
|
||||
saturationChannel,
|
||||
hueChannel,
|
||||
colorFilterChannel
|
||||
modifyExposure, exposureChannel,
|
||||
modifyContrast, contrastChannel,
|
||||
modifySaturation, saturationChannel,
|
||||
modifyHue, hueChannel,
|
||||
modifyColorFilter, colorFilterChannel
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,16 @@ using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
public class BloomAction : CurveShakeAction
|
||||
public class BloomAction : PostprocessingActionBase
|
||||
{
|
||||
|
||||
protected override void TriggerEvent(FeedbackContext context)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void StopEvent(FeedbackContext context)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.Feedback;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
/// <summary>
|
||||
/// RGB分离故障反馈动作,通过 RGBSplitGlitchShakeEvent 触发 RGBSplitGlitchShaker。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[FeedbackActionColor(1f, 0.3f, 0.8f)]
|
||||
public class RGBSplitGlitchAction : PostprocessingActionBase
|
||||
{
|
||||
public override string DisplayName => "RGB Split Glitch";
|
||||
|
||||
[LabelText("强度曲线")]
|
||||
public FloatCurveChannel intensityCurve = FloatCurveChannel.CreateDefault(remapMax: 1f);
|
||||
|
||||
[LabelText("修改速度")]
|
||||
public bool modifySpeed;
|
||||
|
||||
[ShowIf("modifySpeed")]
|
||||
[LabelText("速度曲线")]
|
||||
public FloatCurveChannel speedCurve = FloatCurveChannel.CreateDefault(remapMax: 50f);
|
||||
|
||||
[HideIf("modifySpeed")]
|
||||
[LabelText("速度")]
|
||||
[Range(0f, 100f)]
|
||||
public float speed = 30f;
|
||||
|
||||
protected override void TriggerEvent(FeedbackContext context)
|
||||
{
|
||||
FloatCurveChannel finalSpeedCurve = modifySpeed
|
||||
? speedCurve
|
||||
: new FloatCurveChannel
|
||||
{
|
||||
curve = AnimationCurve.Constant(0f, 1f, speed),
|
||||
relativeToInitial = false
|
||||
};
|
||||
|
||||
RGBSplitGlitchShakeEvent.Trigger(
|
||||
context,
|
||||
intensityCurve,
|
||||
finalSpeedCurve
|
||||
);
|
||||
}
|
||||
|
||||
protected override void StopEvent(FeedbackContext context)
|
||||
{
|
||||
RGBSplitGlitchShakeEvent.Trigger(context, intensityCurve, stop: true);
|
||||
}
|
||||
|
||||
public override bool Validate(out string error)
|
||||
{
|
||||
error = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc20b82d80b720247a0ef6db8513af02
|
||||
@@ -14,73 +14,53 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
public override string DisplayName => "Vignette";
|
||||
|
||||
|
||||
public FloatCurveChannel intensityCurve = FloatCurveChannel.CreateDefault(remapMax: 1f);
|
||||
|
||||
/// <summary>
|
||||
/// 是否修改暗角中心点。
|
||||
/// </summary>
|
||||
[LabelText("修改中心点")]
|
||||
public bool modifyCenter;
|
||||
|
||||
/// <summary>
|
||||
/// 模糊中心的屏幕坐标 (0-1)。(0.5, 0.5) 为屏幕正中心。
|
||||
/// </summary>
|
||||
[HideIf("modifyCenter")]
|
||||
[LabelText("中心点")]
|
||||
public Vector2 center = new Vector2(0.5f, 0.5f);
|
||||
|
||||
[ShowIf("modifyCenter")]
|
||||
[LabelText("中心点曲线")]
|
||||
public Vector2CurveChannel centerCurve = Vector2CurveChannel.CreateDefault();
|
||||
|
||||
/// <summary>
|
||||
/// 是否修改颜色。
|
||||
/// </summary>
|
||||
[LabelText("修改颜色")]
|
||||
public bool modifyColors;
|
||||
|
||||
[HideIf("modifyColors")]
|
||||
public Color outColor;
|
||||
|
||||
[HideIf("modifyColors")]
|
||||
public Color innerColor;
|
||||
|
||||
/// <summary>
|
||||
/// 外圈颜色。
|
||||
/// </summary>
|
||||
[ShowIf("modifyColors")]
|
||||
[LabelText("外圈颜色")]
|
||||
public Color outColor = Color.black;
|
||||
|
||||
[HideIf("modifyColors")]
|
||||
[LabelText("内圈颜色")]
|
||||
public Color innerColor = Color.black;
|
||||
|
||||
[ShowIf("modifyColors")]
|
||||
[LabelText("外圈颜色曲线")]
|
||||
public ColorCurveChannel outerColorCurve = ColorCurveChannel.CreateDefault();
|
||||
|
||||
/// <summary>
|
||||
/// 内圈颜色。
|
||||
/// </summary>
|
||||
[ShowIf("modifyColors")]
|
||||
[LabelText("内圈颜色")]
|
||||
[LabelText("内圈颜色曲线")]
|
||||
public ColorCurveChannel innerColorCurve = ColorCurveChannel.CreateDefault();
|
||||
|
||||
/// <summary>
|
||||
/// 是否修改形状。
|
||||
/// </summary>
|
||||
[LabelText("修改形状")]
|
||||
public bool modifyShape;
|
||||
|
||||
[HideIf("modifyShape")]
|
||||
public float smoothness;
|
||||
[LabelText("柔和度")]
|
||||
public float smoothness = 0.5f;
|
||||
|
||||
[HideIf("modifyShape")]
|
||||
public float roundness;
|
||||
[LabelText("圆度")]
|
||||
public float roundness = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// 柔和度曲线。
|
||||
/// </summary>
|
||||
[ShowIf("modifyShape")]
|
||||
[LabelText("柔和度曲线")]
|
||||
public FloatCurveChannel smoothnessCurve = FloatCurveChannel.CreateDefault(remapMax: 0.5f);
|
||||
|
||||
/// <summary>
|
||||
/// 圆度曲线。
|
||||
/// </summary>
|
||||
[ShowIf("modifyShape")]
|
||||
[LabelText("圆度曲线")]
|
||||
public FloatCurveChannel roundnessCurve = FloatCurveChannel.CreateDefault(remapMax: 1f);
|
||||
@@ -91,13 +71,18 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
context,
|
||||
intensityCurve,
|
||||
modifyCenter,
|
||||
center,
|
||||
modifyCenter ? centerCurve : default,
|
||||
modifyCenter ? center : default(Vector2),
|
||||
modifyColors,
|
||||
outerColorCurve,
|
||||
innerColorCurve,
|
||||
modifyColors ? outerColorCurve : default,
|
||||
modifyColors ? innerColorCurve : default,
|
||||
modifyColors ? outColor : default,
|
||||
modifyColors ? innerColor : default,
|
||||
modifyShape,
|
||||
smoothnessCurve,
|
||||
roundnessCurve
|
||||
modifyShape ? smoothnessCurve : default,
|
||||
modifyShape ? roundnessCurve : default,
|
||||
modifyShape ? smoothness : 0f,
|
||||
modifyShape ? roundness : 0f
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,15 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
public delegate void ShakeDelegate(
|
||||
FeedbackContext feedbackContext,
|
||||
bool modifyExposure,
|
||||
FloatCurveChannel exposureCurve,
|
||||
bool modifyContrast,
|
||||
FloatCurveChannel contrastCurve,
|
||||
bool modifySaturation,
|
||||
FloatCurveChannel saturationCurve,
|
||||
bool modifyHue,
|
||||
FloatCurveChannel hueCurve,
|
||||
bool modifyColorFilter,
|
||||
ColorCurveChannel colorFilterCurve,
|
||||
bool stop
|
||||
);
|
||||
@@ -30,14 +35,32 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
public static void Trigger(
|
||||
FeedbackContext feedbackContext,
|
||||
bool modifyExposure = false,
|
||||
FloatCurveChannel exposureCurve = default,
|
||||
bool modifyContrast = false,
|
||||
FloatCurveChannel contrastCurve = default,
|
||||
bool modifySaturation = false,
|
||||
FloatCurveChannel saturationCurve = default,
|
||||
bool modifyHue = false,
|
||||
FloatCurveChannel hueCurve = default,
|
||||
bool modifyColorFilter = false,
|
||||
ColorCurveChannel colorFilterCurve = default,
|
||||
bool stop = false)
|
||||
{
|
||||
OnEvent?.Invoke(feedbackContext, exposureCurve, contrastCurve, saturationCurve, hueCurve, colorFilterCurve, stop);
|
||||
OnEvent?.Invoke(
|
||||
feedbackContext,
|
||||
modifyExposure,
|
||||
exposureCurve,
|
||||
modifyContrast,
|
||||
contrastCurve,
|
||||
modifySaturation,
|
||||
saturationCurve,
|
||||
modifyHue,
|
||||
hueCurve,
|
||||
modifyColorFilter,
|
||||
colorFilterCurve,
|
||||
stop
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,26 +69,45 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
/// </summary>
|
||||
public class AnimeACESShakeInstance : ShakeInstanceBase
|
||||
{
|
||||
public readonly FloatCurveChannel ExposureCurve;
|
||||
public readonly FloatCurveChannel ContrastCurve;
|
||||
public readonly FloatCurveChannel SaturationCurve;
|
||||
public readonly FloatCurveChannel HueCurve;
|
||||
public readonly ColorCurveChannel ColorFilterCurve;
|
||||
public readonly bool modifyExposure;
|
||||
public readonly FloatCurveChannel exposureCurve;
|
||||
|
||||
public readonly bool modifyContrast;
|
||||
public readonly FloatCurveChannel contrastCurve;
|
||||
|
||||
public readonly bool modifySaturation;
|
||||
public readonly FloatCurveChannel saturationCurve;
|
||||
|
||||
public readonly bool modifyHue;
|
||||
public readonly FloatCurveChannel hueCurve;
|
||||
|
||||
public readonly bool modifyColorFilter;
|
||||
public readonly ColorCurveChannel colorFilterCurve;
|
||||
|
||||
public AnimeACESShakeInstance(
|
||||
FeedbackContext feedbackContext,
|
||||
bool modifyExposure,
|
||||
FloatCurveChannel exposureCurve,
|
||||
bool modifyContrast,
|
||||
FloatCurveChannel contrastCurve,
|
||||
bool modifySaturation,
|
||||
FloatCurveChannel saturationCurve,
|
||||
bool modifyHue,
|
||||
FloatCurveChannel hueCurve,
|
||||
bool modifyColorFilter,
|
||||
ColorCurveChannel colorFilterCurve)
|
||||
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
|
||||
{
|
||||
ExposureCurve = exposureCurve;
|
||||
ContrastCurve = contrastCurve;
|
||||
SaturationCurve = saturationCurve;
|
||||
HueCurve = hueCurve;
|
||||
ColorFilterCurve = colorFilterCurve;
|
||||
this.modifyExposure = modifyExposure;
|
||||
this.modifyContrast = modifyContrast;
|
||||
this.modifySaturation = modifySaturation;
|
||||
this.modifyHue = modifyHue;
|
||||
this.modifyColorFilter = modifyColorFilter;
|
||||
this.exposureCurve = exposureCurve;
|
||||
this.contrastCurve = contrastCurve;
|
||||
this.saturationCurve = saturationCurve;
|
||||
this.hueCurve = hueCurve;
|
||||
this.colorFilterCurve = colorFilterCurve;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,38 +157,39 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
for (int i = _activeShakes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
AnimeACESShakeInstance shake = _activeShakes[i];
|
||||
shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings);
|
||||
shake.Tick();
|
||||
|
||||
float normalizedTime = shake.timer / shake.duration;
|
||||
|
||||
// Exposure
|
||||
if (shake.ExposureCurve.active)
|
||||
if (shake.modifyExposure)
|
||||
{
|
||||
additiveExposure += shake.ExposureCurve.Evaluate(normalizedTime);
|
||||
additiveExposure += shake.exposureCurve.Evaluate(normalizedTime);
|
||||
Debug.Log($"Exposure shake: {additiveExposure}");
|
||||
}
|
||||
|
||||
// Contrast
|
||||
if (shake.ContrastCurve.active)
|
||||
if (shake.modifyContrast)
|
||||
{
|
||||
additiveContrast += shake.ContrastCurve.Evaluate(normalizedTime);
|
||||
additiveContrast += shake.contrastCurve.Evaluate(normalizedTime);
|
||||
}
|
||||
|
||||
// Saturation
|
||||
if (shake.SaturationCurve.active)
|
||||
if (shake.modifySaturation)
|
||||
{
|
||||
additiveSaturation += shake.SaturationCurve.Evaluate(normalizedTime);
|
||||
additiveSaturation += shake.saturationCurve.Evaluate(normalizedTime);
|
||||
}
|
||||
|
||||
// Hue
|
||||
if (shake.HueCurve.active)
|
||||
if (shake.modifyHue)
|
||||
{
|
||||
additiveHue += shake.HueCurve.Evaluate(normalizedTime);
|
||||
additiveHue += shake.hueCurve.Evaluate(normalizedTime);
|
||||
}
|
||||
|
||||
// Color Filter
|
||||
if (shake.ColorFilterCurve.active)
|
||||
if (shake.modifyColorFilter)
|
||||
{
|
||||
colorFilterAccum = shake.ColorFilterCurve.Evaluate(normalizedTime);
|
||||
colorFilterAccum = shake.colorFilterCurve.Evaluate(normalizedTime);
|
||||
hasColorFilter = true;
|
||||
}
|
||||
|
||||
@@ -171,10 +214,15 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
private void OnShakeEvent(
|
||||
FeedbackContext feedbackContext,
|
||||
bool modifyExposure,
|
||||
FloatCurveChannel exposureCurve,
|
||||
bool modifyContrast,
|
||||
FloatCurveChannel contrastCurve,
|
||||
bool modifySaturation,
|
||||
FloatCurveChannel saturationCurve,
|
||||
bool modifyHue,
|
||||
FloatCurveChannel hueCurve,
|
||||
bool modifyColorFilter,
|
||||
ColorCurveChannel colorFilterCurve,
|
||||
bool stop)
|
||||
{
|
||||
@@ -184,12 +232,11 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
var instance = new AnimeACESShakeInstance(
|
||||
feedbackContext,
|
||||
exposureCurve,
|
||||
contrastCurve,
|
||||
saturationCurve,
|
||||
hueCurve,
|
||||
colorFilterCurve
|
||||
);
|
||||
modifyExposure, exposureCurve,
|
||||
modifyContrast, contrastCurve,
|
||||
modifySaturation, saturationCurve,
|
||||
modifyHue, hueCurve,
|
||||
modifyColorFilter, colorFilterCurve);
|
||||
_activeShakes.Add(instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,21 +118,18 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
float normalizedTime = shake.timer / shake.duration;
|
||||
|
||||
if (shake.intensityCurve.active)
|
||||
float curveValue = shake.intensityCurve.Evaluate(normalizedTime);
|
||||
if (shake.intensityCurve.relativeToInitial)
|
||||
{
|
||||
float curveValue = shake.intensityCurve.Evaluate(normalizedTime);
|
||||
if (shake.intensityCurve.relativeToInitial)
|
||||
{
|
||||
additiveIntensity += curveValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
absoluteIntensity = curveValue;
|
||||
hasAbsolute = true;
|
||||
}
|
||||
additiveIntensity += curveValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
absoluteIntensity = curveValue;
|
||||
hasAbsolute = true;
|
||||
}
|
||||
|
||||
if (shake.modifyJitter && shake.jitterCurve.active)
|
||||
if (shake.modifyJitter)
|
||||
{
|
||||
additiveJitter += shake.jitterCurve.Evaluate(normalizedTime);
|
||||
}
|
||||
|
||||
@@ -56,13 +56,13 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
public class CameraFovShaker : MonoBehaviour
|
||||
{
|
||||
private CinemachineCamera _camera;
|
||||
private float _initialFov;
|
||||
public float initialFov;
|
||||
private readonly List<CameraFovShakeInstance> _activeShakes = new List<CameraFovShakeInstance>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_camera = GetComponent<CinemachineCamera>();
|
||||
_initialFov = _camera.Lens.FieldOfView;
|
||||
initialFov = _camera.Lens.FieldOfView;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
@@ -82,7 +82,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
if (_activeShakes.Count == 0)
|
||||
{
|
||||
SetFov(_initialFov);
|
||||
SetFov(initialFov);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
}
|
||||
}
|
||||
|
||||
float finalFov = hasAbsolute ? absoluteFov : _initialFov + additiveFov;
|
||||
float finalFov = hasAbsolute ? absoluteFov : initialFov + additiveFov;
|
||||
SetFov(finalFov);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
_activeShakes.Clear();
|
||||
if (_camera != null)
|
||||
{
|
||||
SetFov(_initialFov);
|
||||
SetFov(initialFov);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,6 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
}
|
||||
|
||||
Vector3 totalOffset = Vector3.zero;
|
||||
|
||||
for (int i = _activeShakes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
CameraRotationShakeInstance shake = _activeShakes[i];
|
||||
@@ -121,7 +120,6 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
_activeShakes.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
_rotationOffset.rotationOffset = _initialRotation + totalOffset;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
using System.Collections.Generic;
|
||||
using SLSUtilities.Feedback;
|
||||
using SLSUtilities.Rendering.PostProcessing;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
/// <summary>
|
||||
/// RGB分离故障震动事件。
|
||||
/// </summary>
|
||||
public struct RGBSplitGlitchShakeEvent
|
||||
{
|
||||
private static event ShakeDelegate OnEvent;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void RuntimeInitialization() { OnEvent = null; }
|
||||
|
||||
public delegate void ShakeDelegate(
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
FloatCurveChannel speedCurve,
|
||||
bool stop
|
||||
);
|
||||
|
||||
public static void Register(ShakeDelegate callback) { OnEvent += callback; }
|
||||
public static void Unregister(ShakeDelegate callback) { OnEvent -= callback; }
|
||||
|
||||
public static void Trigger(
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
FloatCurveChannel speedCurve = default,
|
||||
bool stop = false)
|
||||
{
|
||||
OnEvent?.Invoke(feedbackContext, intensityCurve, speedCurve, stop);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB分离故障震动实例。
|
||||
/// </summary>
|
||||
public class RGBSplitGlitchShakeInstance : ShakeInstanceBase
|
||||
{
|
||||
public readonly FloatCurveChannel intensityCurve;
|
||||
public readonly FloatCurveChannel speedCurve;
|
||||
|
||||
public RGBSplitGlitchShakeInstance(
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
FloatCurveChannel speedCurve)
|
||||
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
|
||||
{
|
||||
this.intensityCurve = intensityCurve;
|
||||
this.speedCurve = speedCurve;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGBSplitGlitch 的震动聚合器。
|
||||
/// </summary>
|
||||
[AddComponentMenu("SLS Utilities/Feedback Shakers/RGB Split Glitch Shaker")]
|
||||
public class RGBSplitGlitchShaker : MonoBehaviour
|
||||
{
|
||||
private RGBSplitGlitch _component;
|
||||
private float _initialIntensity;
|
||||
private float _initialSpeed;
|
||||
private bool _resolved;
|
||||
|
||||
private readonly List<RGBSplitGlitchShakeInstance> _activeShakes = new List<RGBSplitGlitchShakeInstance>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_resolved = TryResolve();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RGBSplitGlitchShakeEvent.Register(OnShakeEvent);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
RGBSplitGlitchShakeEvent.Unregister(OnShakeEvent);
|
||||
StopAll();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!_resolved || _activeShakes.Count == 0) return;
|
||||
|
||||
float additiveIntensity = 0f;
|
||||
float absoluteIntensity = 0f;
|
||||
bool hasAbsolute = false;
|
||||
float additiveSpeed = 0f;
|
||||
|
||||
for (int i = _activeShakes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RGBSplitGlitchShakeInstance shake = _activeShakes[i];
|
||||
shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings);
|
||||
|
||||
float normalizedTime = shake.timer / shake.duration;
|
||||
|
||||
float intensityValue = shake.intensityCurve.Evaluate(normalizedTime);
|
||||
if (shake.intensityCurve.relativeToInitial)
|
||||
{
|
||||
additiveIntensity += intensityValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
absoluteIntensity = intensityValue;
|
||||
hasAbsolute = true;
|
||||
}
|
||||
|
||||
additiveSpeed += shake.speedCurve.Evaluate(normalizedTime);
|
||||
|
||||
if (shake.IsFinished)
|
||||
{
|
||||
_activeShakes.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
float finalIntensity = hasAbsolute ? absoluteIntensity : _initialIntensity + additiveIntensity;
|
||||
_component.intensity.value = finalIntensity;
|
||||
_component.speed.value = _initialSpeed + additiveSpeed;
|
||||
|
||||
if (_activeShakes.Count == 0)
|
||||
{
|
||||
Restore();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShakeEvent(
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
FloatCurveChannel speedCurve,
|
||||
bool stop)
|
||||
{
|
||||
if (stop) { StopAll(); return; }
|
||||
if (!_resolved) _resolved = TryResolve();
|
||||
if (!_resolved) return;
|
||||
|
||||
var instance = new RGBSplitGlitchShakeInstance(
|
||||
feedbackContext,
|
||||
intensityCurve,
|
||||
speedCurve
|
||||
);
|
||||
_activeShakes.Add(instance);
|
||||
}
|
||||
|
||||
private bool TryResolve()
|
||||
{
|
||||
if (_component != null) return true;
|
||||
if (PostProcessingManager.Instance == null) return false;
|
||||
if (!PostProcessingManager.Instance.GetVolumeComponent(out _component)) return false;
|
||||
|
||||
_initialIntensity = _component.intensity.value;
|
||||
_initialSpeed = _component.speed.value;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Restore()
|
||||
{
|
||||
if (!_resolved) return;
|
||||
_component.intensity.value = _initialIntensity;
|
||||
_component.speed.value = _initialSpeed;
|
||||
}
|
||||
|
||||
private void StopAll()
|
||||
{
|
||||
_activeShakes.Clear();
|
||||
Restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e720e1219abdd234b8c87ce75d5815cb
|
||||
@@ -19,13 +19,18 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
bool modifyCenter,
|
||||
Vector2CurveChannel centerCurve,
|
||||
Vector2 center,
|
||||
bool modifyColors,
|
||||
ColorCurveChannel colorOuter,
|
||||
ColorCurveChannel colorInner,
|
||||
Color outColor,
|
||||
Color innerColor,
|
||||
bool modifyShape,
|
||||
FloatCurveChannel smoothnessCurve,
|
||||
FloatCurveChannel roundnessCurve,
|
||||
float smoothness,
|
||||
float roundness,
|
||||
bool stop
|
||||
);
|
||||
|
||||
@@ -36,18 +41,23 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
bool modifyCenter = false,
|
||||
Vector2CurveChannel centerCurve = default,
|
||||
Vector2 center = default,
|
||||
bool modifyColors = false,
|
||||
ColorCurveChannel colorOuter = default,
|
||||
ColorCurveChannel colorInner = default,
|
||||
Color outColor = default,
|
||||
Color innerColor = default,
|
||||
bool modifyShape = false,
|
||||
FloatCurveChannel smoothnessCurve = default,
|
||||
FloatCurveChannel roundnessCurve = default,
|
||||
float smoothness = 0f,
|
||||
float roundness = 0f,
|
||||
bool stop = false)
|
||||
{
|
||||
OnEvent?.Invoke(feedbackContext, intensityCurve, modifyCenter, center,
|
||||
modifyColors, colorOuter, colorInner, modifyShape,
|
||||
smoothnessCurve, roundnessCurve, stop);
|
||||
OnEvent?.Invoke(feedbackContext, intensityCurve, modifyCenter, centerCurve, center,
|
||||
modifyColors, colorOuter, colorInner, outColor, innerColor, modifyShape,
|
||||
smoothnessCurve, roundnessCurve, smoothness, roundness, stop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,36 +68,51 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
{
|
||||
public readonly FloatCurveChannel intensityCurve;
|
||||
public readonly bool modifyCenter;
|
||||
public readonly Vector2CurveChannel centerCurve;
|
||||
public readonly Vector2 center;
|
||||
public readonly bool modifyColors;
|
||||
public readonly ColorCurveChannel colorOuter;
|
||||
public readonly ColorCurveChannel colorInner;
|
||||
public readonly Color outColor;
|
||||
public readonly Color innerColor;
|
||||
public readonly bool modifyShape;
|
||||
public readonly FloatCurveChannel smoothnessCurve;
|
||||
public readonly FloatCurveChannel roundnessCurve;
|
||||
public readonly float smoothness;
|
||||
public readonly float roundness;
|
||||
|
||||
public VignetteShakeInstance(
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
bool modifyCenter,
|
||||
Vector2CurveChannel centerCurve,
|
||||
Vector2 center,
|
||||
bool modifyColors,
|
||||
ColorCurveChannel colorOuter,
|
||||
ColorCurveChannel colorInner,
|
||||
Color outColor,
|
||||
Color innerColor,
|
||||
bool modifyShape,
|
||||
FloatCurveChannel smoothnessCurve,
|
||||
FloatCurveChannel roundnessCurve)
|
||||
FloatCurveChannel roundnessCurve,
|
||||
float smoothness,
|
||||
float roundness)
|
||||
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
|
||||
{
|
||||
this.intensityCurve = intensityCurve;
|
||||
this.modifyCenter = modifyCenter;
|
||||
this.centerCurve = centerCurve;
|
||||
this.center = center;
|
||||
this.modifyColors = modifyColors;
|
||||
this.colorOuter = colorOuter;
|
||||
this.colorInner = colorInner;
|
||||
this.outColor = outColor;
|
||||
this.innerColor = innerColor;
|
||||
this.modifyShape = modifyShape;
|
||||
this.smoothnessCurve = smoothnessCurve;
|
||||
this.roundnessCurve = roundnessCurve;
|
||||
this.smoothness = smoothness;
|
||||
this.roundness = roundness;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,37 +173,44 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
|
||||
float normalizedTime = shake.timer / shake.duration;
|
||||
|
||||
if (shake.intensityCurve.active)
|
||||
float curveValue = shake.intensityCurve.Evaluate(normalizedTime);
|
||||
if (shake.intensityCurve.relativeToInitial)
|
||||
{
|
||||
float curveValue = shake.intensityCurve.Evaluate(normalizedTime);
|
||||
if (shake.intensityCurve.relativeToInitial)
|
||||
{
|
||||
additiveIntensity += curveValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
absoluteIntensity = curveValue;
|
||||
hasAbsolute = true;
|
||||
}
|
||||
additiveIntensity += curveValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
absoluteIntensity = curveValue;
|
||||
hasAbsolute = true;
|
||||
}
|
||||
|
||||
if (shake.modifyCenter)
|
||||
{
|
||||
latestCenter = shake.center;
|
||||
latestCenter = shake.modifyCenter
|
||||
? shake.centerCurve.Evaluate(normalizedTime, _initialCenter)
|
||||
: shake.center;
|
||||
hasCenter = true;
|
||||
}
|
||||
|
||||
if (shake.modifyColors)
|
||||
{
|
||||
latestColorOuter = shake.colorOuter.Evaluate(normalizedTime);
|
||||
latestColorInner = shake.colorInner.Evaluate(normalizedTime);
|
||||
latestColorOuter = shake.modifyColors
|
||||
? shake.colorOuter.Evaluate(normalizedTime)
|
||||
: shake.outColor;
|
||||
latestColorInner = shake.modifyColors
|
||||
? shake.colorInner.Evaluate(normalizedTime)
|
||||
: shake.innerColor;
|
||||
hasColors = true;
|
||||
}
|
||||
|
||||
if (shake.modifyShape)
|
||||
{
|
||||
latestSmoothness = shake.smoothnessCurve.Evaluate(normalizedTime);
|
||||
latestRoundness = shake.roundnessCurve.Evaluate(normalizedTime);
|
||||
latestSmoothness = shake.modifyShape
|
||||
? shake.smoothnessCurve.Evaluate(normalizedTime)
|
||||
: shake.smoothness;
|
||||
latestRoundness = shake.modifyShape
|
||||
? shake.roundnessCurve.Evaluate(normalizedTime)
|
||||
: shake.roundness;
|
||||
hasShape = true;
|
||||
}
|
||||
|
||||
@@ -213,13 +245,18 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
FeedbackContext feedbackContext,
|
||||
FloatCurveChannel intensityCurve,
|
||||
bool modifyCenter,
|
||||
Vector2CurveChannel centerCurve,
|
||||
Vector2 center,
|
||||
bool modifyColors,
|
||||
ColorCurveChannel colorOuter,
|
||||
ColorCurveChannel colorInner,
|
||||
Color outColor,
|
||||
Color innerColor,
|
||||
bool modifyShape,
|
||||
FloatCurveChannel smoothnessCurve,
|
||||
FloatCurveChannel roundnessCurve,
|
||||
float smoothness,
|
||||
float roundness,
|
||||
bool stop)
|
||||
{
|
||||
if (stop) { StopAll(); return; }
|
||||
@@ -227,9 +264,21 @@ namespace Cielonos.MainGame.Effects.Feedback
|
||||
if (!_resolved) return;
|
||||
|
||||
var instance = new VignetteShakeInstance(
|
||||
feedbackContext, intensityCurve, modifyCenter, center,
|
||||
modifyColors, colorOuter, colorInner, modifyShape,
|
||||
smoothnessCurve, roundnessCurve
|
||||
feedbackContext,
|
||||
intensityCurve,
|
||||
modifyCenter,
|
||||
centerCurve,
|
||||
center,
|
||||
modifyColors,
|
||||
colorOuter,
|
||||
colorInner,
|
||||
outColor,
|
||||
innerColor,
|
||||
modifyShape,
|
||||
smoothnessCurve,
|
||||
roundnessCurve,
|
||||
smoothness,
|
||||
roundness
|
||||
);
|
||||
_activeShakes.Add(instance);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,49 @@ namespace Cielonos.MainGame
|
||||
|
||||
return enemiesInRadius;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有可见敌人
|
||||
/// </summary>
|
||||
public List<CharacterBase> GetVisibleEnemies(float radius = 50f)
|
||||
{
|
||||
List<CharacterBase> result = new List<CharacterBase>();
|
||||
List<CharacterBase> enemies = GetEnemiesInRadius(Player.transform.position, radius);
|
||||
|
||||
foreach (CharacterBase enemy in enemies)
|
||||
{
|
||||
if (enemy == null || enemy.statusSm.isDead) continue;
|
||||
|
||||
Vector3 screenPos = Player.viewSc.playerCamera.WorldToScreenPoint(enemy.centerPoint.position);
|
||||
bool isInScreen = screenPos.z > 0 &&
|
||||
screenPos.x > 0 && screenPos.x < Screen.width &&
|
||||
screenPos.y > 0 && screenPos.y < Screen.height;
|
||||
|
||||
if (isInScreen)
|
||||
{
|
||||
result.Add(enemy);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取按屏幕X坐标从左到右排序的可见敌人列表
|
||||
/// </summary>
|
||||
public List<CharacterBase> GetVisibleEnemiesSortedByScreenX(float radius = 50f)
|
||||
{
|
||||
List<CharacterBase> visibleEnemies = GetVisibleEnemies(radius);
|
||||
|
||||
visibleEnemies.Sort((a, b) =>
|
||||
{
|
||||
Vector3 screenA = Player.viewSc.playerCamera.WorldToScreenPoint(a.centerPoint.position);
|
||||
Vector3 screenB = Player.viewSc.playerCamera.WorldToScreenPoint(b.centerPoint.position);
|
||||
return screenA.x.CompareTo(screenB.x);
|
||||
});
|
||||
|
||||
return visibleEnemies;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 383b31d5ddcc89e4692157c4cc81b9aa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SLSUtilities.Feedback
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用的"按曲线震动数值"基类,提供曲线采样、初始值记录/复位等通用逻辑。
|
||||
/// RadialBlur、ChromaticAberration、Vignette 等后处理效果均继承此类。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class CurveShakeAction : FeedbackActionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 震动曲线,X 轴为归一化时间 [0,1],Y 轴为震动强度 [0,1]。
|
||||
/// </summary>
|
||||
[Title("Curve Shake")]
|
||||
[LabelText("Shake Curve")]
|
||||
[ShakeCurvePreset]
|
||||
public AnimationCurve shakeCurve = new AnimationCurve(
|
||||
new Keyframe(0f, 0f),
|
||||
new Keyframe(0.5f, 1f),
|
||||
new Keyframe(1f, 0f)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// 曲线值 0 对应的实际数值。
|
||||
/// </summary>
|
||||
[LabelText("Remap Min")]
|
||||
public float remapMin;
|
||||
|
||||
/// <summary>
|
||||
/// 曲线值 1 对应的实际数值。
|
||||
/// </summary>
|
||||
[LabelText("Remap Max")]
|
||||
public float remapMax = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在初始值上叠加(而非替换)。
|
||||
/// </summary>
|
||||
[LabelText("Relative to Initial")]
|
||||
public bool relativeToInitial;
|
||||
|
||||
|
||||
protected virtual float EvaluateShake(float normalizedTime, float initialValue)
|
||||
{
|
||||
return base.EvaluateShake(shakeCurve, remapMin, remapMax, relativeToInitial, normalizedTime, initialValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26b145321a43fe44d899db3f2178cb0e
|
||||
Reference in New Issue
Block a user