mirror of
https://github.com/osukey/osukey.git
synced 2025-05-18 20:17:23 +09:00
Merge pull request #13535 from peppy/fix-hitcircle-approach-circle-early-hit
Fix approach circle fade not running early on an early user hit
This commit is contained in:
commit
a72151d4e1
@ -21,20 +21,37 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
private int depthIndex;
|
private int depthIndex;
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVariousHitCircles()
|
public void TestHits()
|
||||||
|
{
|
||||||
|
AddStep("Hit Big Single", () => SetContents(_ => testSingle(2, true)));
|
||||||
|
AddStep("Hit Medium Single", () => SetContents(_ => testSingle(5, true)));
|
||||||
|
AddStep("Hit Small Single", () => SetContents(_ => testSingle(7, true)));
|
||||||
|
AddStep("Hit Big Stream", () => SetContents(_ => testStream(2, true)));
|
||||||
|
AddStep("Hit Medium Stream", () => SetContents(_ => testStream(5, true)));
|
||||||
|
AddStep("Hit Small Stream", () => SetContents(_ => testStream(7, true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHittingEarly()
|
||||||
|
{
|
||||||
|
AddStep("Hit stream early", () => SetContents(_ => testStream(5, true, -150)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMisses()
|
||||||
{
|
{
|
||||||
AddStep("Miss Big Single", () => SetContents(_ => testSingle(2)));
|
AddStep("Miss Big Single", () => SetContents(_ => testSingle(2)));
|
||||||
AddStep("Miss Medium Single", () => SetContents(_ => testSingle(5)));
|
AddStep("Miss Medium Single", () => SetContents(_ => testSingle(5)));
|
||||||
AddStep("Miss Small Single", () => SetContents(_ => testSingle(7)));
|
AddStep("Miss Small Single", () => SetContents(_ => testSingle(7)));
|
||||||
AddStep("Hit Big Single", () => SetContents(_ => testSingle(2, true)));
|
|
||||||
AddStep("Hit Medium Single", () => SetContents(_ => testSingle(5, true)));
|
|
||||||
AddStep("Hit Small Single", () => SetContents(_ => testSingle(7, true)));
|
|
||||||
AddStep("Miss Big Stream", () => SetContents(_ => testStream(2)));
|
AddStep("Miss Big Stream", () => SetContents(_ => testStream(2)));
|
||||||
AddStep("Miss Medium Stream", () => SetContents(_ => testStream(5)));
|
AddStep("Miss Medium Stream", () => SetContents(_ => testStream(5)));
|
||||||
AddStep("Miss Small Stream", () => SetContents(_ => testStream(7)));
|
AddStep("Miss Small Stream", () => SetContents(_ => testStream(7)));
|
||||||
AddStep("Hit Big Stream", () => SetContents(_ => testStream(2, true)));
|
}
|
||||||
AddStep("Hit Medium Stream", () => SetContents(_ => testStream(5, true)));
|
|
||||||
AddStep("Hit Small Stream", () => SetContents(_ => testStream(7, true)));
|
[Test]
|
||||||
|
public void TestHittingLate()
|
||||||
|
{
|
||||||
|
AddStep("Hit stream late", () => SetContents(_ => testStream(5, true, 150)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null)
|
private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null)
|
||||||
@ -46,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
return playfield;
|
return playfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable testStream(float circleSize, bool auto = false)
|
private Drawable testStream(float circleSize, bool auto = false, double hitOffset = 0)
|
||||||
{
|
{
|
||||||
var playfield = new TestOsuPlayfield();
|
var playfield = new TestOsuPlayfield();
|
||||||
|
|
||||||
@ -54,14 +71,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
for (int i = 0; i <= 1000; i += 100)
|
for (int i = 0; i <= 1000; i += 100)
|
||||||
{
|
{
|
||||||
playfield.Add(createSingle(circleSize, auto, i, pos));
|
playfield.Add(createSingle(circleSize, auto, i, pos, hitOffset));
|
||||||
pos.X += 50;
|
pos.X += 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
return playfield;
|
return playfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestDrawableHitCircle createSingle(float circleSize, bool auto, double timeOffset, Vector2? positionOffset)
|
private TestDrawableHitCircle createSingle(float circleSize, bool auto, double timeOffset, Vector2? positionOffset, double hitOffset = 0)
|
||||||
{
|
{
|
||||||
positionOffset ??= Vector2.Zero;
|
positionOffset ??= Vector2.Zero;
|
||||||
|
|
||||||
@ -73,14 +90,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize });
|
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize });
|
||||||
|
|
||||||
var drawable = CreateDrawableHitCircle(circle, auto);
|
var drawable = CreateDrawableHitCircle(circle, auto, hitOffset);
|
||||||
|
|
||||||
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto) => new TestDrawableHitCircle(circle, auto)
|
protected virtual TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto, double hitOffset = 0) => new TestDrawableHitCircle(circle, auto, hitOffset)
|
||||||
{
|
{
|
||||||
Depth = depthIndex++
|
Depth = depthIndex++
|
||||||
};
|
};
|
||||||
@ -88,18 +105,20 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
protected class TestDrawableHitCircle : DrawableHitCircle
|
protected class TestDrawableHitCircle : DrawableHitCircle
|
||||||
{
|
{
|
||||||
private readonly bool auto;
|
private readonly bool auto;
|
||||||
|
private readonly double hitOffset;
|
||||||
|
|
||||||
public TestDrawableHitCircle(HitCircle h, bool auto)
|
public TestDrawableHitCircle(HitCircle h, bool auto, double hitOffset)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
this.auto = auto;
|
this.auto = auto;
|
||||||
|
this.hitOffset = hitOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TriggerJudgement() => UpdateResult(true);
|
public void TriggerJudgement() => Schedule(() => UpdateResult(true));
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (auto && !userTriggered && timeOffset > 0)
|
if (auto && !userTriggered && timeOffset > hitOffset && CheckHittable?.Invoke(this, Time.Current) != false)
|
||||||
{
|
{
|
||||||
// force success
|
// force success
|
||||||
ApplyResult(r => r.Type = HitResult.Great);
|
ApplyResult(r => r.Type = HitResult.Great);
|
||||||
|
@ -16,11 +16,11 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Scheduler.AddDelayed(() => comboIndex.Value++, 250, true);
|
Scheduler.AddDelayed(() => comboIndex.Value++, 250, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto)
|
protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto, double hitOffset = 0)
|
||||||
{
|
{
|
||||||
circle.ComboIndexBindable.BindTo(comboIndex);
|
circle.ComboIndexBindable.BindTo(comboIndex);
|
||||||
circle.IndexInCurrentComboBindable.BindTo(comboIndex);
|
circle.IndexInCurrentComboBindable.BindTo(comboIndex);
|
||||||
return base.CreateDrawableHitCircle(circle, auto);
|
return base.CreateDrawableHitCircle(circle, auto, hitOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
return base.CreateBeatmapForSkinProvider();
|
return base.CreateBeatmapForSkinProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto)
|
protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto, double hitOffset = 0)
|
||||||
{
|
{
|
||||||
var drawableHitObject = base.CreateDrawableHitCircle(circle, auto);
|
var drawableHitObject = base.CreateDrawableHitCircle(circle, auto, hitOffset);
|
||||||
|
|
||||||
Debug.Assert(drawableHitObject.HitObject.HitWindows != null);
|
Debug.Assert(drawableHitObject.HitObject.HitWindows != null);
|
||||||
|
|
||||||
|
@ -172,6 +172,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
base.UpdateStartTimeStateTransforms();
|
base.UpdateStartTimeStateTransforms();
|
||||||
|
|
||||||
|
// always fade out at the circle's start time (to match user expectations).
|
||||||
ApproachCircle.FadeOut(50);
|
ApproachCircle.FadeOut(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +183,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
// todo: temporary / arbitrary, used for lifetime optimisation.
|
// todo: temporary / arbitrary, used for lifetime optimisation.
|
||||||
this.Delay(800).FadeOut();
|
this.Delay(800).FadeOut();
|
||||||
|
|
||||||
|
// in the case of an early state change, the fade should be expedited to the current point in time.
|
||||||
|
if (HitStateUpdateTime < HitObject.StartTime)
|
||||||
|
ApproachCircle.FadeOut(50);
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user