1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-28 00:47:20 +08:00

Fix hit error meters not updating visual state when hidden

It is an expectation of users that when the HUD is shown after a period
of being hidden, it will visually reflect the state based on recent
judgements.

To achieve this, I've added `AlwaysPresent` and moved the transform
application to the meter level, rather than at a child level. If this is
seen as a bad direction, `AlwaysPresent` can be applied to the drawable
children and the transforms can be moved back.

Also of note, `ColourHitErrorMeter` is pretty weird. The flow class
could potentially be removed and reduce `AlwaysPresent` usage by one.
Can do that refactor as part of this PR if preferred.

Closes #18624.
This commit is contained in:
Dean Herbert 2022-06-13 16:37:26 +09:00
parent 17eaf7bb5c
commit 86163d2225
3 changed files with 33 additions and 38 deletions

View File

@ -400,6 +400,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
{ {
const int arrow_move_duration = 800; const int arrow_move_duration = 800;
const int judgement_fade_in_duration = 100;
const int judgement_fade_out_duration = 5000;
if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0) if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0)
return; return;
@ -420,12 +423,26 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
} }
} }
judgementsContainer.Add(new JudgementLine var judgementLine = new JudgementLine
{ {
JudgementLineThickness = { BindTarget = JudgementLineThickness }, JudgementLineThickness = { BindTarget = JudgementLineThickness },
Y = getRelativeJudgementPosition(judgement.TimeOffset), Y = getRelativeJudgementPosition(judgement.TimeOffset),
Colour = GetColourForHitResult(judgement.Type), Colour = GetColourForHitResult(judgement.Type),
}); Alpha = 0,
Width = 0,
};
judgementsContainer.Add(judgementLine);
// Importantly, transforms should be applied in this method rather than constructed drawables
// to ensure that they are applied even when the `HitErrorMeter` is hidden (see `AlwaysPresent` usage).
judgementLine
.FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint)
.ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint)
.Then()
.FadeOut(judgement_fade_out_duration)
.ResizeWidthTo(0, judgement_fade_out_duration, Easing.InQuint)
.Expire();
arrow.MoveToY( arrow.MoveToY(
getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1) getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1)
@ -456,23 +473,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
protected override void LoadComplete() protected override void LoadComplete()
{ {
const int judgement_fade_in_duration = 100;
const int judgement_fade_out_duration = 5000;
base.LoadComplete(); base.LoadComplete();
Alpha = 0;
Width = 0;
JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true);
this
.FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint)
.ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint)
.Then()
.FadeOut(judgement_fade_out_duration)
.ResizeWidthTo(0, judgement_fade_out_duration, Easing.InQuint)
.Expire();
} }
} }

View File

@ -51,47 +51,37 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
Direction = FillDirection.Vertical; Direction = FillDirection.Vertical;
LayoutDuration = animation_duration; LayoutDuration = animation_duration;
LayoutEasing = Easing.OutQuint; LayoutEasing = Easing.OutQuint;
AlwaysPresent = true;
} }
public void Push(Color4 colour) public void Push(Color4 colour)
{ {
Add(new HitErrorCircle(colour, drawable_judgement_size)); var hitErrorCircle = new HitErrorCircle(colour);
Add(hitErrorCircle);
hitErrorCircle.FadeInFromZero(animation_duration, Easing.OutQuint);
hitErrorCircle.MoveToY(-drawable_judgement_size);
hitErrorCircle.MoveToY(0, animation_duration, Easing.OutQuint);
if (Children.Count > MAX_DISPLAYED_JUDGEMENTS) if (Children.Count > MAX_DISPLAYED_JUDGEMENTS)
Children.FirstOrDefault(c => !c.IsRemoved)?.Remove(); Children.FirstOrDefault(c => !c.IsRemoved)?.Remove();
} }
} }
internal class HitErrorCircle : Container internal class HitErrorCircle : Circle
{ {
public bool IsRemoved { get; private set; } public bool IsRemoved { get; private set; }
private readonly Circle circle; public HitErrorCircle(Color4 colour)
public HitErrorCircle(Color4 colour, int size)
{ {
Size = new Vector2(size); Colour = colour;
Child = circle = new Circle Size = new Vector2(drawable_judgement_size);
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
Colour = colour
};
}
protected override void LoadComplete()
{
base.LoadComplete();
circle.FadeInFromZero(animation_duration, Easing.OutQuint);
circle.MoveToY(-DrawSize.Y);
circle.MoveToY(0, animation_duration, Easing.OutQuint);
} }
public void Remove() public void Remove()
{ {
IsRemoved = true; IsRemoved = true;
this.FadeOut(animation_duration, Easing.OutQuint).Expire(); this.FadeOut(animation_duration, Easing.OutQuint).Expire();
} }
} }

View File

@ -37,6 +37,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
{ {
base.LoadComplete(); base.LoadComplete();
AlwaysPresent = true;
if (gameplayClockContainer != null) if (gameplayClockContainer != null)
gameplayClockContainer.OnSeek += Clear; gameplayClockContainer.OnSeek += Clear;