diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs index d42338f20e..3dad5b508c 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps continue; double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime; - float stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; + double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; if (objectN.StartTime - endTime > stackThreshold) //We are no longer within stacking range of the next object. @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps OsuHitObject objectI = beatmap.HitObjects[i]; if (objectI.StackHeight != 0 || objectI is Spinner) continue; - float stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; + double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; /* If this object is a hitcircle, then we enter this "special" case. * It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider. diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 3a486e7763..b4dd08eadb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => @"Play with no approach circles and fading notes for a slight score advantage."; public override double ScoreMultiplier => 1.06; - private const float fade_in_duration_multiplier = 0.4f; + private const double fade_in_duration_multiplier = 0.4; private const double fade_out_duration_multiplier = 0.3; public void ApplyToDrawableHitObjects(IEnumerable drawables) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index 6cf353eaf2..6d556d0304 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -16,8 +16,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly RepeatPoint repeatPoint; private readonly DrawableSlider drawableSlider; - public double FadeInTime; - public double FadeOutTime; + private double animDuration; public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider) : base(repeatPoint) @@ -48,11 +47,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void UpdatePreemptState() { - var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime); + animDuration = Math.Min(150, repeatPoint.SpanDuration / 2); - this.FadeIn(animIn).ScaleTo(1.2f, animIn) + this.FadeIn(animDuration).ScaleTo(1.2f, animDuration / 2) .Then() - .ScaleTo(1, 150, Easing.Out); + .ScaleTo(1, animDuration / 2, Easing.Out); } protected override void UpdateCurrentState(ArmedState state) @@ -60,14 +59,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables switch (state) { case ArmedState.Idle: - this.Delay(FadeOutTime - repeatPoint.StartTime).FadeOut(); + this.Delay(HitObject.TimePreempt).FadeOut(); break; case ArmedState.Miss: - this.FadeOut(160); + this.FadeOut(animDuration); break; case ArmedState.Hit: - this.FadeOut(120, Easing.OutQuint) - .ScaleTo(Scale * 1.5f, 120, Easing.OutQuint); + this.FadeOut(animDuration, Easing.OutQuint) + .ScaleTo(Scale * 1.5f, animDuration, Easing.OutQuint); break; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 6f3bb34a89..af947817c0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -73,12 +73,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddNested(InitialCircle); - var spanDuration = s.Curve.Distance / s.Velocity; foreach (var tick in s.NestedHitObjects.OfType()) { - var spanStartTime = s.StartTime + tick.SpanIndex * spanDuration; + var spanStartTime = s.StartTime + tick.SpanIndex * s.SpanDuration; var fadeInTime = spanStartTime + (tick.StartTime - spanStartTime) / 2 - (tick.SpanIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2); - var fadeOutTime = spanStartTime + spanDuration; + var fadeOutTime = spanStartTime + s.SpanDuration; var drawableTick = new DrawableSliderTick(tick) { @@ -93,15 +92,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables foreach (var repeatPoint in s.NestedHitObjects.OfType()) { - var repeatStartTime = s.StartTime + (repeatPoint.RepeatIndex + 1) * spanDuration; - var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2); - var fadeOutTime = repeatStartTime + spanDuration; - var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this) { - FadeInTime = fadeInTime, - FadeOutTime = fadeOutTime, - Position = repeatPoint.Position, + Position = repeatPoint.Position }; repeatPoints.Add(drawableRepeatPoint); diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 0e7c2f3d4d..f217ae89e9 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects public double HitWindow100 = 80; public double HitWindow300 = 30; - public float TimePreempt = 600; - public float TimeFadein = 400; + public double TimePreempt = 600; + public double TimeFadein = 400; public Vector2 Position { get; set; } public float X => Position.X; diff --git a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs index abdbb97072..eaaa8d7a7e 100644 --- a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs @@ -1,10 +1,25 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; + namespace osu.Game.Rulesets.Osu.Objects { public class RepeatPoint : OsuHitObject { public int RepeatIndex { get; set; } + public double SpanDuration { get; set; } + + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); + + // We want to show the first RepeatPoint as the TimePreempt dictates but on short (and possibly fast) sliders + // we may need to cut down this time on following RepeatPoints to only show up to two RepeatPoints at any given time. + if (RepeatIndex > 0) + TimePreempt = Math.Min(SpanDuration * 2, TimePreempt); + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 35635788f2..79bb14a475 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -60,6 +60,11 @@ namespace osu.Game.Rulesets.Osu.Objects public List> RepeatSamples { get; set; } = new List>(); public int RepeatCount { get; set; } + /// + /// The length of one span of this . + /// + public double SpanDuration => Duration / this.SpanCount(); + private int stackHeight; public override int StackHeight @@ -102,13 +107,12 @@ namespace osu.Game.Rulesets.Osu.Objects var length = Curve.Distance; var tickDistance = Math.Min(TickDistance, length); - var spanDuration = length / Velocity; var minDistanceFromEnd = Velocity * 0.01; for (var span = 0; span < this.SpanCount(); span++) { - var spanStartTime = StartTime + span * spanDuration; + var spanStartTime = StartTime + span * SpanDuration; var reversed = span % 2 == 1; for (var d = tickDistance; d <= length; d += tickDistance) @@ -133,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Objects AddNested(new SliderTick { SpanIndex = span, - StartTime = spanStartTime + timeProgress * spanDuration, + StartTime = spanStartTime + timeProgress * SpanDuration, Position = Curve.PositionAt(distanceProgress), StackHeight = StackHeight, Scale = Scale, @@ -146,16 +150,13 @@ namespace osu.Game.Rulesets.Osu.Objects private void createRepeatPoints() { - var repeatDuration = Distance / Velocity; - for (int repeatIndex = 0, repeat = 1; repeatIndex < RepeatCount; repeatIndex++, repeat++) { - var repeatStartTime = StartTime + repeat * repeatDuration; - AddNested(new RepeatPoint { RepeatIndex = repeatIndex, - StartTime = repeatStartTime, + SpanDuration = SpanDuration, + StartTime = StartTime + repeat * SpanDuration, Position = Curve.PositionAt(repeat % 2), StackHeight = StackHeight, Scale = Scale, diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs index ddf24cc405..5060137ec6 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs @@ -63,6 +63,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("Fast Short Slider", () => testShortHighSpeed()); AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1)); AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2)); + AddStep("Fast Short Slider 6 Repeats", () => testShortHighSpeed(6)); AddStep("Perfect Curve", testCurve); // TODO more curve types?