1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 19:27:24 +08:00

Only hit passed-through ticks if none were missed

This commit is contained in:
Dan Balasescu 2023-12-17 19:57:48 +09:00
parent c0e96927aa
commit f77884b62f
No known key found for this signature in database
2 changed files with 25 additions and 27 deletions

View File

@ -220,7 +220,7 @@ namespace osu.Game.Rulesets.Osu.Tests
/// If any hitobject does not meet this criteria, ALL hitobjects after that one should be missed.
/// </summary>
[Test]
public void TestHitLateInRangeDoesNotHitAfterAnyOutOfRange()
public void TestHitLateDoesNotHitTicksIfAnyOutOfRange()
{
performTest(new List<ReplayFrame>
{
@ -241,25 +241,8 @@ namespace osu.Game.Rulesets.Osu.Tests
assertHeadJudgement(HitResult.Meh);
// The first few ticks that are in the follow range of the head should be hit.
assertTickJudgement(0, HitResult.LargeTickHit); // This tick is hidden under the slider head :(
assertTickJudgement(1, HitResult.LargeTickHit);
assertTickJudgement(2, HitResult.LargeTickHit);
// Every other tick should be missed
assertTickJudgement(3, HitResult.LargeTickMiss);
assertTickJudgement(4, HitResult.LargeTickMiss);
assertTickJudgement(5, HitResult.LargeTickMiss);
assertTickJudgement(6, HitResult.LargeTickMiss);
assertTickJudgement(7, HitResult.LargeTickMiss);
assertTickJudgement(8, HitResult.LargeTickMiss);
assertTickJudgement(9, HitResult.LargeTickMiss);
assertTickJudgement(10, HitResult.LargeTickMiss);
// In particular, these three are in the follow range of the head, but should not be hit
// because the slider was at some point outside the follow range of the head.
assertTickJudgement(11, HitResult.LargeTickMiss);
assertTickJudgement(12, HitResult.LargeTickMiss);
// At least one tick was out of range, so they all should be missed.
assertAllTickJudgements(HitResult.LargeTickMiss);
// This particular test actually starts tracking the slider just before the end, so the tail should be hit because of its leniency.
assertTailJudgement(HitResult.LargeTickHit);

View File

@ -80,10 +80,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Vector2 mousePositionInSlider = slider.ToLocalSpace(screenSpaceMousePosition.Value) - slider.OriginPosition;
// When the head is hit and the mouse is in the expanded follow area, force a hit on every nested hitobject
// from the start of the slider that is within the follow area.
// When the head is hit late:
// - If the cursor has at all times been within range of the expanded follow area, hit all nested objects that have been passed through.
// - If the cursor has at some point left the expanded follow area, miss those nested objects instead.
bool forceMiss = false;
bool allTicksInRange = true;
foreach (var nested in slider.NestedHitObjects.OfType<DrawableOsuHitObject>())
{
@ -102,13 +103,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
// When the first nested object that is further outside the follow area is reached,
// forcefully miss all other nested objects that would otherwise be valid to be hit.
// This covers a case of a slider overlapping itself that requires tracking to a tick on an outer edge.
if (forceMiss || (objectPosition - mousePositionInSlider).LengthSquared > radius * radius)
if ((objectPosition - mousePositionInSlider).LengthSquared > radius * radius)
{
nested.MissForcefully();
forceMiss = true;
allTicksInRange = false;
break;
}
else
}
foreach (var nested in slider.NestedHitObjects.OfType<DrawableOsuHitObject>())
{
// Skip nested objects that are already judged.
if (nested.Judged)
continue;
// Stop the process when a nested object is reached that can't be hit before the current time.
if (nested.HitObject.StartTime > Time.Current)
break;
if (allTicksInRange)
nested.HitForcefully();
else
nested.MissForcefully();
}
// Enable tracking, since the mouse is within the follow area (if it were expanded).