using NUnit.Framework; using ProjectM.Simulation; using Unity.Mathematics; namespace ProjectM.Tests { /// /// MC-4 — pure cone hit-test (): the planar XZ range gate + the /// dot(bearing, facing) >= cos(halfAngle) cone gate, plus the coincident / zero-facing / non-positive-range /// guards. Shares the exact predicate AutoTarget uses, but as a per-candidate boolean for the collect-all cleave. /// public class MeleeConeMathTests { const float Cos60 = 0.5f; // cos(60deg): half-angle 60 -> 120deg full cone [Test] public void In_Range_And_Straight_Ahead_Hits() { Assert.IsTrue(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 3f, Cos60, new float3(0, 0, 2))); } [Test] public void Out_Of_Range_Misses() { Assert.IsFalse(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 3f, Cos60, new float3(0, 0, 4))); } [Test] public void At_90_Degrees_Outside_Cone_Misses() { // bearing +X vs facing +Z: dot = 0 < cos60 (0.5) -> outside the cone. Assert.IsFalse(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 3f, Cos60, new float3(2, 0, 0))); } [Test] public void At_45_Degrees_Inside_Cone_Hits() { // bearing ~45deg: dot ~0.707 > 0.5 -> inside. Assert.IsTrue(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 5f, Cos60, new float3(2, 0, 2))); } [Test] public void Behind_The_Player_Misses() { Assert.IsFalse(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 5f, Cos60, new float3(0, 0, -2))); } [Test] public void Coincident_Target_Excluded() { Assert.IsFalse(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 3f, Cos60, float3.zero)); } [Test] public void Zero_Facing_Or_NonPositive_Range_Misses() { Assert.IsFalse(MeleeConeMath.InCone(float3.zero, float2.zero, 3f, Cos60, new float3(0, 0, 2)), "zero facing -> miss"); Assert.IsFalse(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 0f, Cos60, new float3(0, 0, 1)), "range 0 -> miss"); } [Test] public void Uses_Planar_XZ_And_Ignores_Y() { // straight ahead in XZ but far in Y: still a hit (Y ignored, top-down). Assert.IsTrue(MeleeConeMath.InCone(float3.zero, new float2(0, 1), 3f, Cos60, new float3(0, 5, 2))); } } }