diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs similarity index 99% rename from osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs rename to osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs index 296b421a11..177a4f50a1 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneOutOfOrderHits : RateAdjustedBeatmapTestScene + public class TestSceneStartTimeOrderedHitPolicy : RateAdjustedBeatmapTestScene { private const double early_miss_window = 1000; // time after -1000 to -500 is considered a miss private const double late_miss_window = 500; // time after +500 is considered a miss @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Osu.Tests addJudgementAssert(hitObjects[0], HitResult.Great); addJudgementAssert(hitObjects[1], HitResult.Great); addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200 - addJudgementOffsetAssert(hitObjects[0], -200); // time_second_circle - first_circle_time - 100 + addJudgementOffsetAssert(hitObjects[1], -200); // time_second_circle - first_circle_time - 100 } /// diff --git a/osu.Game.Rulesets.Osu/UI/IHitPolicy.cs b/osu.Game.Rulesets.Osu/UI/IHitPolicy.cs new file mode 100644 index 0000000000..5d8ea035a7 --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/IHitPolicy.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Osu.UI +{ + public interface IHitPolicy + { + /// + /// The containing the s which this applies to. + /// + IHitObjectContainer HitObjectContainer { set; } + + /// + /// Determines whether a can be hit at a point in time. + /// + /// The to check. + /// The time to check. + /// Whether can be hit at the given . + bool IsHittable(DrawableHitObject hitObject, double time); + + /// + /// Handles a being hit. + /// + /// The that was hit. + void HandleHit(DrawableHitObject hitObject); + } +} diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 975b444699..e085714265 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.UI private readonly ProxyContainer spinnerProxies; private readonly JudgementContainer judgementLayer; private readonly FollowPointRenderer followPoints; - private readonly OrderedHitPolicy hitPolicy; + private readonly StartTimeOrderedHitPolicy hitPolicy; public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.UI approachCircles = new ProxyContainer { RelativeSizeAxes = Axes.Both }, }; - hitPolicy = new OrderedHitPolicy(HitObjectContainer); + hitPolicy = new StartTimeOrderedHitPolicy { HitObjectContainer = HitObjectContainer }; var hitWindows = new OsuHitWindows(); diff --git a/osu.Game.Rulesets.Osu/UI/OrderedHitPolicy.cs b/osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs similarity index 76% rename from osu.Game.Rulesets.Osu/UI/OrderedHitPolicy.cs rename to osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs index 8e4f81347d..0173156246 100644 --- a/osu.Game.Rulesets.Osu/UI/OrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu/UI/StartTimeOrderedHitPolicy.cs @@ -11,28 +11,17 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.UI { /// - /// Ensures that s are hit in-order. Affectionately known as "note lock". + /// Ensures that s are hit in-order of their start times. Affectionately known as "note lock". /// If a is hit out of order: /// /// The hit is blocked if it occurred earlier than the previous 's start time. /// The hit causes all previous s to missed otherwise. /// /// - public class OrderedHitPolicy + public class StartTimeOrderedHitPolicy : IHitPolicy { - private readonly HitObjectContainer hitObjectContainer; + public IHitObjectContainer HitObjectContainer { get; set; } - public OrderedHitPolicy(HitObjectContainer hitObjectContainer) - { - this.hitObjectContainer = hitObjectContainer; - } - - /// - /// Determines whether a can be hit at a point in time. - /// - /// The to check. - /// The time to check. - /// Whether can be hit at the given . public bool IsHittable(DrawableHitObject hitObject, double time) { DrawableHitObject blockingObject = null; @@ -54,10 +43,6 @@ namespace osu.Game.Rulesets.Osu.UI return blockingObject.Judged || time >= blockingObject.HitObject.StartTime; } - /// - /// Handles a being hit to potentially miss all earlier s. - /// - /// The that was hit. public void HandleHit(DrawableHitObject hitObject) { // Hitobjects which themselves don't block future hitobjects don't cause misses (e.g. slider ticks, spinners). @@ -67,6 +52,7 @@ namespace osu.Game.Rulesets.Osu.UI if (!IsHittable(hitObject, hitObject.HitObject.StartTime + hitObject.Result.TimeOffset)) throw new InvalidOperationException($"A {hitObject} was hit before it became hittable!"); + // Miss all hitobjects prior to the hit one. foreach (var obj in enumerateHitObjectsUpTo(hitObject.HitObject.StartTime)) { if (obj.Judged) @@ -86,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.UI private IEnumerable enumerateHitObjectsUpTo(double targetTime) { - foreach (var obj in hitObjectContainer.AliveObjects) + foreach (var obj in HitObjectContainer.AliveObjects) { if (obj.HitObject.StartTime >= targetTime) yield break; diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 1972043ccb..11312a46df 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -17,19 +17,10 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.UI { - public class HitObjectContainer : LifetimeManagementContainer + public class HitObjectContainer : LifetimeManagementContainer, IHitObjectContainer { - /// - /// All currently in-use s. - /// public IEnumerable Objects => InternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); - /// - /// All currently in-use s that are alive. - /// - /// - /// If this uses pooled objects, this is equivalent to . - /// public IEnumerable AliveObjects => AliveInternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); /// diff --git a/osu.Game/Rulesets/UI/IHitObjectContainer.cs b/osu.Game/Rulesets/UI/IHitObjectContainer.cs new file mode 100644 index 0000000000..4c784132e8 --- /dev/null +++ b/osu.Game/Rulesets/UI/IHitObjectContainer.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Game.Rulesets.Objects.Drawables; + +namespace osu.Game.Rulesets.UI +{ + public interface IHitObjectContainer + { + /// + /// All currently in-use s. + /// + IEnumerable Objects { get; } + + /// + /// All currently in-use s that are alive. + /// + /// + /// If this uses pooled objects, this is equivalent to . + /// + IEnumerable AliveObjects { get; } + } +}