122 lines
4.7 KiB
C#
122 lines
4.7 KiB
C#
using Cielonos.MainGame.Characters;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame.Effects.Feedback
|
||
{
|
||
/// <summary>
|
||
/// 反馈用向量转换工具。
|
||
/// 统一处理“攻击方向”“摄像机本地方向”“反馈振幅”等常见转换,避免各个武器和角色重复实现。
|
||
/// </summary>
|
||
public static class FeedbackVectorUtility
|
||
{
|
||
private const float DirectionEpsilon = 0.0001f;
|
||
|
||
/// <summary>
|
||
/// 获取攻击打向目标的世界方向。
|
||
/// 对于 Projectile,优先使用真实移动速度方向;对于 NormalArea,使用攻击者指向目标的方向。
|
||
/// </summary>
|
||
public static Vector3 GetAttackDirection(AttackAreaBase attackArea, CharacterBase target)
|
||
{
|
||
if (attackArea == null)
|
||
{
|
||
return Vector3.forward;
|
||
}
|
||
|
||
if (attackArea is Projectile)
|
||
{
|
||
return GetProjectileDirection(attackArea);
|
||
}
|
||
|
||
if (attackArea is NormalArea && attackArea.creator != null && target != null)
|
||
{
|
||
return NormalizeOrFallback(
|
||
target.CenterPoint.position - attackArea.creator.CenterPoint.position,
|
||
attackArea.topParent.forward);
|
||
}
|
||
|
||
if (attackArea.creator != null && target != null)
|
||
{
|
||
return NormalizeOrFallback(
|
||
target.CenterPoint.position - attackArea.creator.CenterPoint.position,
|
||
attackArea.topParent.forward);
|
||
}
|
||
|
||
return NormalizeOrFallback(attackArea.topParent.forward, Vector3.forward);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将世界方向转换为摄像机本地方向。
|
||
/// 摄像机不存在时返回标准化世界方向,保证调用端仍能获得稳定结果。
|
||
/// </summary>
|
||
public static Vector3 WorldDirectionToCameraLocal(Vector3 worldDirection, Camera camera)
|
||
{
|
||
Vector3 normalizedDirection = NormalizeOrFallback(worldDirection, Vector3.forward);
|
||
return camera != null
|
||
? camera.transform.InverseTransformDirection(normalizedDirection).normalized
|
||
: normalizedDirection;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取攻击方向对应的摄像机本地方向。
|
||
/// 语义为“攻击从来源打向目标”,适合玩家受击、受击后处理、方向性摄像机反馈等场景。
|
||
/// </summary>
|
||
public static Vector3 GetCameraLocalAttackDirection(AttackAreaBase attackArea, CharacterBase target, Camera camera)
|
||
{
|
||
Vector3 attackDirection = GetAttackDirection(attackArea, target);
|
||
return WorldDirectionToCameraLocal(attackDirection, camera);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据方向和强度生成摄像机反馈振幅。
|
||
/// </summary>
|
||
public static Vector3 DirectionToAmplitude(Vector3 direction, float strength)
|
||
{
|
||
return NormalizeOrFallback(direction, Vector3.forward) * Mathf.Max(0f, strength);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据命中点在屏幕中的横向位置生成振幅。
|
||
/// 适合远程命中确认等“屏幕位置比物理飞行方向更重要”的反馈。
|
||
/// </summary>
|
||
public static Vector3 ScreenHitPositionToAmplitude(
|
||
Vector3 hitPosition,
|
||
Camera camera,
|
||
float horizontalStrength,
|
||
float verticalKick,
|
||
float depthKick)
|
||
{
|
||
if (camera == null)
|
||
{
|
||
return new Vector3(0f, verticalKick, depthKick);
|
||
}
|
||
|
||
Vector3 viewportPosition = camera.WorldToViewportPoint(hitPosition);
|
||
float screenX = viewportPosition.z >= 0f
|
||
? Mathf.Clamp((viewportPosition.x - 0.5f) * 2f, -1f, 1f)
|
||
: 0f;
|
||
|
||
return new Vector3(screenX * horizontalStrength, verticalKick, depthKick);
|
||
}
|
||
|
||
private static Vector3 GetProjectileDirection(AttackAreaBase attackArea)
|
||
{
|
||
if (attackArea.moveSm != null && attackArea.moveSm.unscaledVelocity.sqrMagnitude > DirectionEpsilon)
|
||
{
|
||
return attackArea.moveSm.unscaledVelocity.normalized;
|
||
}
|
||
|
||
return NormalizeOrFallback(attackArea.topParent.forward, Vector3.forward);
|
||
}
|
||
|
||
private static Vector3 NormalizeOrFallback(Vector3 direction, Vector3 fallback)
|
||
{
|
||
if (direction.sqrMagnitude > DirectionEpsilon)
|
||
{
|
||
return direction.normalized;
|
||
}
|
||
|
||
return fallback.sqrMagnitude > DirectionEpsilon ? fallback.normalized : Vector3.forward;
|
||
}
|
||
}
|
||
}
|