using Unity.Mathematics; namespace ProjectM.Simulation { /// /// Pure, deterministic Husk AI math — no RNG, no wall-clock — so server simulation stays reproducible and /// the helpers are EditMode-unit-testable without an ECS world (mirrors / /// StatMath). /// public static class EnemyAIMath { /// /// Planar (XZ) seek velocity from toward at /// . Y is forced to 0 (top-down plane). Returns zero once within /// (so the Husk halts at strike range instead of jittering through the /// target) or when the two points coincide. /// public static float3 SeekVelocity(float3 from, float3 to, float speed, float stopDistance) { float3 d = to - from; d.y = 0f; float distSq = math.lengthsq(d); if (distSq <= stopDistance * stopDistance || distSq < 1e-8f) return float3.zero; return math.normalize(d) * speed; } /// /// True when is within of on the /// XZ plane. /// public static bool InAttackRange(float3 from, float3 to, float range) { float3 d = to - from; d.y = 0f; return math.lengthsq(d) <= range * range; } /// /// Deterministic planar ring position around for spawn /// : evenly spaced over angles at /// . Stable per index so a replayed spawn lands identically. /// public static float3 RingPosition(float3 center, int index, int slots, float radius) { if (slots < 1) slots = 1; int slot = ((index % slots) + slots) % slots; float angle = (2f * math.PI * slot) / slots; math.sincos(angle, out float s, out float c); return center + new float3(c * radius, 0f, s * radius); } } }