using System; using UnityEngine; namespace BumpCombat.Combat { // Authored ground geometry shared by the XY controller and XZ comparison. // Sprite frames and decoration consume elapsed time independently of damage ticks. public static class CycloneGeometry { public const float PixelsPerUnit = 32f; public const float ShadowLocalY = -7.5f / PixelsPerUnit; public const float CenterOffsetY = 5f / PixelsPerUnit; public const float FrameSeconds = .05f; public static float VisualScale(float range, bool charged) => range / (charged ? 1.25f : .85f); public static Vector2 Radii(float range, bool charged) => (charged ? new Vector2(46f, 18f) : new Vector2(38.0625f, 15.03125f)) / PixelsPerUnit * VisualScale(range, charged); public static Vector2 CenterOffset(float range, bool charged, float rootScaleY) => Vector2.up * (ShadowLocalY * rootScaleY + CenterOffsetY * VisualScale(range, charged)); public static int ScheduledHitCount(float duration, float interval) => duration <= 0f || interval <= 0f ? 1 : Mathf.Max(1, Mathf.FloorToInt((duration + .0001f) / interval) + 1); public static float NormalizedDistance(Vector2 offset, Vector2 radii) => offset.x * offset.x / (radii.x * radii.x) + offset.y * offset.y / (radii.y * radii.y); // Keep the original closest-point and 64 boundary samples, including tolerances. // The adapter supplies Collider2D.ClosestPoint or an XZ circular footprint. public static bool Overlaps(Vector2 center, Vector2 radii, Func closestPoint) { if (NormalizedDistance(closestPoint(center) - center, radii) <= 1.0001f) return true; const int samples = 64; for (int i = 0; i < samples; i++) { float angle = Mathf.PI * 2f * i / samples; Vector2 point = center + new Vector2(Mathf.Cos(angle) * radii.x, Mathf.Sin(angle) * radii.y); if ((closestPoint(point) - point).sqrMagnitude <= .000001f) return true; } return false; } } }