1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 09:32:55 +08:00

Merge pull request #7168 from peppy/improve-hud-hiding

Improve HUD hiding
This commit is contained in:
Dan Balasescu 2019-12-16 19:09:46 +09:00 committed by GitHub
commit 267d832ecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 145 additions and 34 deletions

View File

@ -0,0 +1,81 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneHUDOverlay : ManualInputManagerTestScene
{
private HUDOverlay hudOverlay;
private Drawable hideTarget => hudOverlay.KeyCounter; // best way of checking hideTargets without exposing.
[Resolved]
private OsuConfigManager config { get; set; }
[Test]
public void TestShownByDefault()
{
createNew();
AddAssert("showhud is set", () => hudOverlay.ShowHud.Value);
AddAssert("hidetarget is visible", () => hideTarget.IsPresent);
AddAssert("pause button is visible", () => hudOverlay.HoldToQuit.IsPresent);
}
[Test]
public void TestFadesInOnLoadComplete()
{
float? initialAlpha = null;
createNew(h => h.OnLoadComplete += _ => initialAlpha = hideTarget.Alpha);
AddUntilStep("wait for load", () => hudOverlay.IsAlive);
AddAssert("initial alpha was less than 1", () => initialAlpha != null && initialAlpha < 1);
}
[Test]
public void TestHideExternally()
{
createNew();
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent);
}
[Test]
public void TestExternalHideDoesntAffectConfig()
{
bool originalConfigValue = false;
createNew();
AddStep("get original config value", () => originalConfigValue = config.Get<bool>(OsuSetting.ShowInterface));
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
}
private void createNew(Action<HUDOverlay> action = null)
{
AddStep("create overlay", () =>
{
Child = hudOverlay = new HUDOverlay(null, null, Array.Empty<Mod>());
action?.Invoke(hudOverlay);
});
}
}
}

View File

@ -31,7 +31,8 @@ namespace osu.Game.Screens.Play.HUD
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
processor.NewJudgement += onNewJudgement; if (processor != null)
processor.NewJudgement += onNewJudgement;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -96,7 +97,9 @@ namespace osu.Game.Screens.Play.HUD
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
processor.NewJudgement -= onNewJudgement;
if (processor != null)
processor.NewJudgement -= onNewJudgement;
} }
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -23,8 +24,8 @@ namespace osu.Game.Screens.Play
{ {
public class HUDOverlay : Container public class HUDOverlay : Container
{ {
private const int duration = 250; private const float fade_duration = 400;
private const Easing easing = Easing.OutQuint; private const Easing fade_easing = Easing.Out;
public readonly KeyCounterDisplay KeyCounter; public readonly KeyCounterDisplay KeyCounter;
public readonly RollingCounter<int> ComboCounter; public readonly RollingCounter<int> ComboCounter;
@ -43,8 +44,15 @@ namespace osu.Game.Screens.Play
private readonly DrawableRuleset drawableRuleset; private readonly DrawableRuleset drawableRuleset;
private readonly IReadOnlyList<Mod> mods; private readonly IReadOnlyList<Mod> mods;
private Bindable<bool> showHud; /// <summary>
/// Whether the elements that can optionally be hidden should be visible.
/// </summary>
public Bindable<bool> ShowHud { get; } = new BindableBool();
private Bindable<bool> configShowHud;
private readonly Container visibilityContainer; private readonly Container visibilityContainer;
private readonly BindableBool replayLoaded = new BindableBool(); private readonly BindableBool replayLoaded = new BindableBool();
private static bool hasShownNotificationOnce; private static bool hasShownNotificationOnce;
@ -53,6 +61,8 @@ namespace osu.Game.Screens.Play
private readonly Container topScoreContainer; private readonly Container topScoreContainer;
private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter };
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods) public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
{ {
this.scoreProcessor = scoreProcessor; this.scoreProcessor = scoreProcessor;
@ -68,13 +78,12 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
HealthDisplay = CreateHealthDisplay(),
topScoreContainer = new Container topScoreContainer = new Container
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
AutoSizeDuration = 200,
AutoSizeEasing = Easing.Out,
Children = new Drawable[] Children = new Drawable[]
{ {
AccuracyCounter = CreateAccuracyCounter(), AccuracyCounter = CreateAccuracyCounter(),
@ -82,19 +91,20 @@ namespace osu.Game.Screens.Play
ComboCounter = CreateComboCounter(), ComboCounter = CreateComboCounter(),
}, },
}, },
HealthDisplay = CreateHealthDisplay(),
Progress = CreateProgress(), Progress = CreateProgress(),
ModDisplay = CreateModsContainer(), ModDisplay = CreateModsContainer(),
HitErrorDisplay = CreateHitErrorDisplayOverlay(), HitErrorDisplay = CreateHitErrorDisplayOverlay(),
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
} }
}, },
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
new FillFlowContainer new FillFlowContainer
{ {
Anchor = Anchor.BottomRight, Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight, Origin = Anchor.BottomRight,
Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y), Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
LayoutDuration = fade_duration / 2,
LayoutEasing = fade_easing,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
@ -108,34 +118,24 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay) private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
{ {
BindProcessor(scoreProcessor); if (scoreProcessor != null)
BindDrawableRuleset(drawableRuleset); BindProcessor(scoreProcessor);
Progress.Objects = drawableRuleset.Objects; if (drawableRuleset != null)
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value; {
Progress.RequestSeek = time => RequestSeek(time); BindDrawableRuleset(drawableRuleset);
Progress.ReferenceClock = drawableRuleset.FrameStableClock;
Progress.Objects = drawableRuleset.Objects;
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value;
Progress.RequestSeek = time => RequestSeek(time);
Progress.ReferenceClock = drawableRuleset.FrameStableClock;
}
ModDisplay.Current.Value = mods; ModDisplay.Current.Value = mods;
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface); configShowHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
showHud.BindValueChanged(visible => visibilityContainer.FadeTo(visible.NewValue ? 1 : 0, duration, easing), true);
ShowHealthbar.BindValueChanged(healthBar => if (!configShowHud.Value && !hasShownNotificationOnce)
{
if (healthBar.NewValue)
{
HealthDisplay.FadeIn(duration, easing);
topScoreContainer.MoveToY(30, duration, easing);
}
else
{
HealthDisplay.FadeOut(duration, easing);
topScoreContainer.MoveToY(0, duration, easing);
}
}, true);
if (!showHud.Value && !hasShownNotificationOnce)
{ {
hasShownNotificationOnce = true; hasShownNotificationOnce = true;
@ -144,12 +144,39 @@ namespace osu.Game.Screens.Play
Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab." Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
}); });
} }
// start all elements hidden
hideTargets.ForEach(d => d.Hide());
} }
public override void Hide() => throw new InvalidOperationException($"{nameof(HUDOverlay)} should not be hidden as it will remove the ability of a user to quit. Use {nameof(ShowHud)} instead.");
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
ShowHud.BindValueChanged(visible => hideTargets.ForEach(d => d.FadeTo(visible.NewValue ? 1 : 0, fade_duration, fade_easing)));
ShowHealthbar.BindValueChanged(healthBar =>
{
if (healthBar.NewValue)
{
HealthDisplay.FadeIn(fade_duration, fade_easing);
topScoreContainer.MoveToY(30, fade_duration, fade_easing);
}
else
{
HealthDisplay.FadeOut(fade_duration, fade_easing);
topScoreContainer.MoveToY(0, fade_duration, fade_easing);
}
}, true);
configShowHud.BindValueChanged(visible =>
{
if (!ShowHud.Disabled)
ShowHud.Value = visible.NewValue;
}, true);
replayLoaded.BindValueChanged(replayLoadedValueChanged, true); replayLoaded.BindValueChanged(replayLoadedValueChanged, true);
} }
@ -189,7 +216,7 @@ namespace osu.Game.Screens.Play
switch (e.Key) switch (e.Key)
{ {
case Key.Tab: case Key.Tab:
showHud.Value = !showHud.Value; configShowHud.Value = !configShowHud.Value;
return true; return true;
} }
} }
@ -257,7 +284,7 @@ namespace osu.Game.Screens.Play
Margin = new MarginPadding { Top = 20, Right = 10 }, Margin = new MarginPadding { Top = 20, Right = 10 },
}; };
protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.FirstAvailableHitWindows); protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset?.FirstAvailableHitWindows);
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();