diff --git a/src/GameUtils/Math/CatmullRom.cs b/src/GameUtils/Math/CatmullRom.cs index 2488101..ed59730 100644 --- a/src/GameUtils/Math/CatmullRom.cs +++ b/src/GameUtils/Math/CatmullRom.cs @@ -111,15 +111,16 @@ private void GetSegmentAndLocalT(float t, out int segmentIndex, out float localT var segmentCount = _loop ? _points.Count : _points.Count - 1; var scaled = t * segmentCount; segmentIndex = (int)MathF.Floor(scaled); - localT = scaled - segmentIndex; if (_loop) { - segmentIndex = segmentIndex % segmentCount; + segmentIndex = ((segmentIndex % segmentCount) + segmentCount) % segmentCount; + localT = scaled - MathF.Floor(scaled); } else { segmentIndex = System.Math.Clamp(segmentIndex, 0, segmentCount - 1); + localT = scaled - segmentIndex; } } diff --git a/tests/GameUtils.Tests/Math/CatmullRomPathTests.cs b/tests/GameUtils.Tests/Math/CatmullRomPathTests.cs index 7ecfbfe..ac13c58 100644 --- a/tests/GameUtils.Tests/Math/CatmullRomPathTests.cs +++ b/tests/GameUtils.Tests/Math/CatmullRomPathTests.cs @@ -134,4 +134,42 @@ public void GetTangent_Looping_EvaluatesTangentCorrectly() var tangentStart = path.GetTangent(0f); Assert.AreNotEqual(Vector2.Zero, tangentStart); } + + [TestMethod] + public void SetLooping_True_AlignsPositionAndTangentAtEndpoints() + { + var path = new CatmullRomPath() + .SetLooping(true) + .AddPoint(new Vector2(0, 0)) + .AddPoint(new Vector2(10, 0)) + .AddPoint(new Vector2(10, 10)) + .AddPoint(new Vector2(0, 10)); + + var pStart = path.GetPoint(0f); + var pEnd = path.GetPoint(1f); + Assert.AreEqual(pStart, pEnd); + + var tangentStart = path.GetTangent(0f); + var tangentEnd = path.GetTangent(1f); + Assert.AreEqual(tangentStart.X, tangentEnd.X, 1e-4f); + Assert.AreEqual(tangentStart.Y, tangentEnd.Y, 1e-4f); + } + + [TestMethod] + public void SetLooping_CanToggleLoopingState() + { + var path = new CatmullRomPath() + .AddPoint(new Vector2(0, 0)) + .AddPoint(new Vector2(10, 0)) + .AddPoint(new Vector2(10, 10)) + .AddPoint(new Vector2(0, 10)); + + path.SetLooping(true); + var pEndLoop = path.GetPoint(1f); + Assert.AreEqual(new Vector2(0, 0), pEndLoop); + + path.SetLooping(false); + var pEndNonLoop = path.GetPoint(1f); + Assert.AreEqual(new Vector2(0, 10), pEndNonLoop); + } }