diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 956d0e0c14..182cc51572 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -106,20 +106,37 @@ namespace osu.Game.Rulesets.Catch.Tests public void TestCatcherCatchWidth() { float halfWidth = Catcher.CalculateCatchWidth(new BeatmapDifficulty { CircleSize = 0 }) / 2; + + AddStep("move catcher to center", () => catcher.X = CatchPlayfield.CENTER_X); + + float leftPlateBounds = CatchPlayfield.CENTER_X - halfWidth; + float rightPlateBounds = CatchPlayfield.CENTER_X + halfWidth; + AddStep("catch fruit", () => { - attemptCatch(new Fruit { X = -halfWidth + 1 }); - attemptCatch(new Fruit { X = halfWidth - 1 }); + attemptCatch(new Fruit { X = leftPlateBounds + 1 }); + attemptCatch(new Fruit { X = rightPlateBounds - 1 }); }); checkPlate(2); + AddStep("miss fruit", () => { - attemptCatch(new Fruit { X = -halfWidth - 1 }); - attemptCatch(new Fruit { X = halfWidth + 1 }); + attemptCatch(new Fruit { X = leftPlateBounds - 1 }); + attemptCatch(new Fruit { X = rightPlateBounds + 1 }); }); checkPlate(2); } + [Test] + public void TestFruitClampedToCatchableRegion() + { + AddStep("catch fruit left", () => attemptCatch(new Fruit { X = -CatchPlayfield.WIDTH })); + checkPlate(1); + AddStep("move catcher to right", () => catcher.X = CatchPlayfield.WIDTH); + AddStep("catch fruit right", () => attemptCatch(new Fruit { X = CatchPlayfield.WIDTH * 2 })); + checkPlate(2); + } + [Test] public void TestFruitChangesCatcherState() { diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 6e01c44e1f..cd2b8348e2 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -69,7 +70,7 @@ namespace osu.Game.Rulesets.Catch.Objects /// This value is the original value plus the offset applied by the beatmap processing. /// Use if a value not affected by the offset is desired. /// - public float EffectiveX => OriginalX + XOffset; + public float EffectiveX => Math.Clamp(OriginalX + XOffset, 0, CatchPlayfield.WIDTH); public double TimePreempt { get; set; } = 1000; diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 311e15116e..015457e84f 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -11,6 +11,7 @@ using Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -84,8 +85,8 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t + lastEvent.Value.Time, - X = OriginalX + Path.PositionAt( - lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X, + X = ClampToPlayfield(EffectiveX + Path.PositionAt( + lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X), }); } } @@ -102,7 +103,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = dropletSamples, StartTime = e.Time, - X = OriginalX + Path.PositionAt(e.PathProgress).X, + X = ClampToPlayfield(EffectiveX + Path.PositionAt(e.PathProgress).X), }); break; @@ -113,14 +114,16 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = this.GetNodeSamples(nodeIndex++), StartTime = e.Time, - X = OriginalX + Path.PositionAt(e.PathProgress).X, + X = ClampToPlayfield(EffectiveX + Path.PositionAt(e.PathProgress).X), }); break; } } } - public float EndX => OriginalX + this.CurvePositionAt(1).X; + public float EndX => ClampToPlayfield(EffectiveX + this.CurvePositionAt(1).X); + + public float ClampToPlayfield(float value) => Math.Clamp(value, 0, CatchPlayfield.WIDTH); [JsonIgnore] public double Duration