Skip to content

Commit

Permalink
Merge pull request #2514 from peppy/exit-hold-confirmation
Browse files Browse the repository at this point in the history
Implement a hold-to-confirm screen when exiting game using escape key
  • Loading branch information
smoogipoo committed May 14, 2018
2 parents f0b7ed2 + 9536c32 commit 21ed275
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 45 deletions.
62 changes: 62 additions & 0 deletions osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Menu;

namespace osu.Game.Tests.Visual
{
public class TestCaseHoldToConfirmOverlay : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ExitConfirmOverlay) };

public TestCaseHoldToConfirmOverlay()
{
bool fired = false;

var firedText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "Fired!",
TextSize = 50,
Alpha = 0,
};

var overlay = new TestHoldToConfirmOverlay
{
Action = () =>
{
fired = true;
firedText.FadeTo(1).Then().FadeOut(1000);
}
};

Children = new Drawable[]
{
overlay,
firedText
};

AddStep("start confirming", () => overlay.Begin());
AddStep("abort confirming", () => overlay.Abort());

AddAssert("ensure aborted", () => !fired);

AddStep("start confirming", () => overlay.Begin());

AddUntilStep(() => fired, "wait until confirmed");
}

private class TestHoldToConfirmOverlay : ExitConfirmOverlay
{
protected override bool AllowMultipleFires => true;

public void Begin() => BeginConfirm();
public void Abort() => AbortConfirm();
}
}
}
66 changes: 66 additions & 0 deletions osu.Game/Overlays/HoldToConfirmOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using OpenTK.Graphics;

namespace osu.Game.Overlays
{
/// <summary>
/// An overlay which will display a black screen that dims over a period before confirming an exit action.
/// Action is BYO (derived class will need to call <see cref="BeginConfirm"/> and <see cref="AbortConfirm"/> from a user event).
/// </summary>
public abstract class HoldToConfirmOverlay : Container
{
public Action Action;

private Box overlay;

private const int activate_delay = 400;
private const int fadeout_delay = 200;

private bool fired;

/// <summary>
/// Whether the overlay should be allowed to return from a fired state.
/// </summary>
protected virtual bool AllowMultipleFires => false;

[BackgroundDependencyLoader]
private void load()
{
RelativeSizeAxes = Axes.Both;
AlwaysPresent = true;

Children = new Drawable[]
{
overlay = new Box
{
Alpha = 0,
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
}
};
}

protected void BeginConfirm()
{
if (!AllowMultipleFires && fired) return;
overlay.FadeIn(activate_delay * (1 - overlay.Alpha), Easing.Out).OnComplete(_ =>
{
Action?.Invoke();
fired = true;
});
}

protected void AbortConfirm()
{
if (!AllowMultipleFires && fired) return;
overlay.FadeOut(fadeout_delay, Easing.Out);
}
}
}
34 changes: 34 additions & 0 deletions osu.Game/Screens/Menu/ExitConfirmOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using osu.Framework.Input;
using osu.Game.Overlays;
using OpenTK.Input;

namespace osu.Game.Screens.Menu
{
public class ExitConfirmOverlay : HoldToConfirmOverlay
{
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.Escape && !args.Repeat)
{
BeginConfirm();
return true;
}

return base.OnKeyDown(state, args);
}

protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
{
if (args.Key == Key.Escape)
{
AbortConfirm();
return true;
}

return base.OnKeyUp(state, args);
}
}
}
4 changes: 4 additions & 0 deletions osu.Game/Screens/Menu/MainMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public MainMenu()

Children = new Drawable[]
{
new ExitConfirmOverlay
{
Action = Exit,
},
new ParallaxContainer
{
ParallaxAmount = 0.01f,
Expand Down
49 changes: 4 additions & 45 deletions osu.Game/Screens/Play/HotkeyRetryOverlay.cs
Original file line number Diff line number Diff line change
@@ -1,69 +1,28 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using osu.Framework.Allocation;
using System;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
using OpenTK.Graphics;
using osu.Game.Overlays;

namespace osu.Game.Screens.Play
{
public class HotkeyRetryOverlay : Container, IKeyBindingHandler<GlobalAction>
public class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler<GlobalAction>
{
public Action Action;

private Box overlay;

private const int activate_delay = 400;
private const int fadeout_delay = 200;

private bool fired;

[BackgroundDependencyLoader]
private void load()
{
RelativeSizeAxes = Axes.Both;
AlwaysPresent = true;

Children = new Drawable[]
{
overlay = new Box
{
Alpha = 0,
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
}
};
}

public bool OnPressed(GlobalAction action)
{
if (action != GlobalAction.QuickRetry) return false;

overlay.FadeIn(activate_delay, Easing.Out);
BeginConfirm();
return true;
}

public bool OnReleased(GlobalAction action)
{
if (action != GlobalAction.QuickRetry) return false;

overlay.FadeOut(fadeout_delay, Easing.Out);
AbortConfirm();
return true;
}

protected override void Update()
{
base.Update();
if (!fired && overlay.Alpha == 1)
{
fired = true;
Action?.Invoke();
}
}
}
}

0 comments on commit 21ed275

Please sign in to comment.