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