From 4ab4f65c83e04942f4865acabe7ce0c266d6152b Mon Sep 17 00:00:00 2001 From: Andrey Zavadskiy Date: Sun, 9 Apr 2017 16:26:31 +0300 Subject: [PATCH 01/18] Retry on Tilde key --- osu.Game/Screens/Play/Player.cs | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 36ab1ab946..0af3dcecba 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -22,6 +22,10 @@ using System; using System.Linq; using osu.Framework.Threading; using osu.Game.Modes.Scoring; +using OpenTK.Input; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics.Sprites; +using OpenTK.Graphics; namespace osu.Game.Screens.Play { @@ -59,10 +63,16 @@ namespace osu.Game.Screens.Play private HudOverlay hudOverlay; private PauseOverlay pauseOverlay; private FailOverlay failOverlay; + private Box retryOverlay; + + private SampleChannel SampleClick; [BackgroundDependencyLoader] private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config) { + AlwaysPresent = true; + SampleClick = audio.Sample.Get(@"Menu/menuback"); + var beatmap = Beatmap.Beatmap; if (beatmap.BeatmapInfo?.Mode > PlayMode.Taiko) @@ -157,6 +167,13 @@ namespace osu.Game.Screens.Play { OnRetry = Restart, OnQuit = Exit, + }, + retryOverlay = new Box + { + Alpha = 0, + AlwaysPresent = true, + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, } }; } @@ -331,5 +348,41 @@ namespace osu.Game.Screens.Play private Bindable mouseWheelDisabled; protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value && !IsPaused; + + private bool isHolded; + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Repeat) return false; + + if (args.Key == Key.Tilde) + { + isHolded = true; + + retryOverlay.FadeIn(500); + + Delay(500).Schedule(() =>{ + if (isHolded) + { + SampleClick.Play(); + Restart(); + } + }); + return true; + } + + return base.OnKeyDown(state, args); + } + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + { + if (args.Key == Key.Tilde) + { + isHolded = false; + retryOverlay.FadeOut(200); + return true; + } + + return base.OnKeyUp(state, args); + } } } \ No newline at end of file From 425e96c45cacbdbb07f6d60f4997f9a25014321c Mon Sep 17 00:00:00 2001 From: Andrey Zavadskiy Date: Sun, 9 Apr 2017 17:44:19 +0300 Subject: [PATCH 02/18] Moved logic to it's own class --- osu.Game/Screens/Play/Player.cs | 55 +++-------------------- osu.Game/Screens/Play/RetryOverlay.cs | 65 +++++++++++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 3 files changed, 71 insertions(+), 50 deletions(-) create mode 100644 osu.Game/Screens/Play/RetryOverlay.cs diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0af3dcecba..3b67f8d6e6 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -22,9 +22,6 @@ using System; using System.Linq; using osu.Framework.Threading; using osu.Game.Modes.Scoring; -using OpenTK.Input; -using osu.Framework.Audio.Sample; -using osu.Framework.Graphics.Sprites; using OpenTK.Graphics; namespace osu.Game.Screens.Play @@ -63,16 +60,11 @@ namespace osu.Game.Screens.Play private HudOverlay hudOverlay; private PauseOverlay pauseOverlay; private FailOverlay failOverlay; - private Box retryOverlay; - - private SampleChannel SampleClick; + private RetryOverlay retryOverlay; [BackgroundDependencyLoader] private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config) { - AlwaysPresent = true; - SampleClick = audio.Sample.Get(@"Menu/menuback"); - var beatmap = Beatmap.Beatmap; if (beatmap.BeatmapInfo?.Mode > PlayMode.Taiko) @@ -168,12 +160,11 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = Exit, }, - retryOverlay = new Box + retryOverlay = new RetryOverlay { - Alpha = 0, - AlwaysPresent = true, - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, + Action = Restart, + OnKeyPressed = () => Content.FadeColour(Color4.Black, 500), + OnKeyReleased = () => Content.FadeColour(Color4.White, 200), } }; } @@ -348,41 +339,5 @@ namespace osu.Game.Screens.Play private Bindable mouseWheelDisabled; protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value && !IsPaused; - - private bool isHolded; - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) - { - if (args.Repeat) return false; - - if (args.Key == Key.Tilde) - { - isHolded = true; - - retryOverlay.FadeIn(500); - - Delay(500).Schedule(() =>{ - if (isHolded) - { - SampleClick.Play(); - Restart(); - } - }); - return true; - } - - return base.OnKeyDown(state, args); - } - - protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) - { - if (args.Key == Key.Tilde) - { - isHolded = false; - retryOverlay.FadeOut(200); - return true; - } - - return base.OnKeyUp(state, args); - } } } \ No newline at end of file diff --git a/osu.Game/Screens/Play/RetryOverlay.cs b/osu.Game/Screens/Play/RetryOverlay.cs new file mode 100644 index 0000000000..e44f7d8914 --- /dev/null +++ b/osu.Game/Screens/Play/RetryOverlay.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input; +using OpenTK.Input; +using osu.Framework.Allocation; +using osu.Framework.Audio.Sample; +using osu.Framework.Audio; +using System; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Screens.Play +{ + public class RetryOverlay : Container + { + public Action Action; + public Action OnKeyPressed; + public Action OnKeyReleased; + + private SampleChannel retrySample; + private bool keyIsHeld; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + retrySample = audio.Sample.Get(@"Menu/menuback"); + AlwaysPresent = true; + } + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Repeat) return false; + + if (args.Key == Key.Tilde) + { + keyIsHeld = true; + OnKeyPressed(); + + Delay(500).Schedule(() => + { + if (keyIsHeld) + { + retrySample.Play(); + Action(); + } + }); + return true; + } + + return base.OnKeyDown(state, args); + } + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + { + if (args.Key == Key.Tilde) + { + keyIsHeld = false; + OnKeyReleased(); + return true; + } + + return base.OnKeyUp(state, args); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6dd5ec3088..1777bf6dc2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -180,6 +180,7 @@ + From a7264aa84cd86188379fd72e403172175e5094dc Mon Sep 17 00:00:00 2001 From: Andrey Zavadskiy Date: Sun, 9 Apr 2017 17:53:16 +0300 Subject: [PATCH 03/18] Warning fix --- osu.Game/Screens/Play/Player.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 3b67f8d6e6..af3da23231 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -60,7 +60,6 @@ namespace osu.Game.Screens.Play private HudOverlay hudOverlay; private PauseOverlay pauseOverlay; private FailOverlay failOverlay; - private RetryOverlay retryOverlay; [BackgroundDependencyLoader] private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config) @@ -160,7 +159,7 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = Exit, }, - retryOverlay = new RetryOverlay + new RetryOverlay { Action = Restart, OnKeyPressed = () => Content.FadeColour(Color4.Black, 500), From c882b9bafd96f752433d0e596350cd58e6632559 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 05:08:05 +0900 Subject: [PATCH 04/18] Make taiko playfield scale by height. --- .../Tests/TestCaseTaikoPlayfield.cs | 15 +++++++++++---- .../Objects/Drawables/DrawableDrumRoll.cs | 2 +- .../Drawables/DrawableTaikoHitObject.cs | 4 +++- osu.Game.Modes.Taiko/UI/HitTarget.cs | 6 +++--- osu.Game.Modes.Taiko/UI/InputDrum.cs | 2 +- osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs | 18 +++++++++++++----- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs index 88a037afee..a942535d06 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs @@ -61,17 +61,24 @@ namespace osu.Desktop.VisualTests.Tests { TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great; - playfield.OnJudgement(new DrawableTestHit(new Hit()) + var h = new DrawableTestHit(new Hit()) { X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f), Judgement = new TaikoJudgement { Result = HitResult.Hit, TaikoResult = hitResult, - TimeOffset = 0, - SecondHit = RNG.Next(10) == 0 + TimeOffset = 0 } - }); + }; + + playfield.OnJudgement(h); + + if (RNG.Next(10) == 0) + { + h.Judgement.SecondHit = true; + playfield.OnJudgement(h); + } } private void addMissJudgement() diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 0a0098dd34..695717ce9e 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -49,7 +49,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(HitObject.IsStrong) { Length = (float)(HitObject.Duration / HitObject.ScrollTime), - PlayfieldLengthReference = () => Parent.DrawSize.X + PlayfieldLengthReference = () => Parent.DrawSize.X / DrawScale.X }; [BackgroundDependencyLoader] diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index f15f2bd152..7cd9f9baa5 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -22,7 +22,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables /// private readonly List validKeys = new List(new[] { Key.D, Key.F, Key.J, Key.K }); - public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); + public override Vector2 OriginPosition => new Vector2(bodyContainer.DrawHeight / 2f, DrawHeight / 2f); protected override Container Content => bodyContainer; @@ -46,6 +46,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables AddInternal(bodyContainer = new Container { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, Children = new[] { diff --git a/osu.Game.Modes.Taiko/UI/HitTarget.cs b/osu.Game.Modes.Taiko/UI/HitTarget.cs index a17480628d..f5d6a3b797 100644 --- a/osu.Game.Modes.Taiko/UI/HitTarget.cs +++ b/osu.Game.Modes.Taiko/UI/HitTarget.cs @@ -37,7 +37,7 @@ namespace osu.Game.Modes.Taiko.UI public HitTarget() { - RelativeSizeAxes = Axes.Y; + Size = new Vector2(TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT); Children = new Drawable[] { @@ -47,7 +47,7 @@ namespace osu.Game.Modes.Taiko.UI Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Y = border_offset, - Size = new Vector2(border_thickness, (TaikoPlayfield.PLAYFIELD_HEIGHT - strong_hit_diameter) / 2f - border_offset), + Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - strong_hit_diameter) / 2f - border_offset), Alpha = 0.1f }, new CircularContainer @@ -96,7 +96,7 @@ namespace osu.Game.Modes.Taiko.UI Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Y = -border_offset, - Size = new Vector2(border_thickness, (TaikoPlayfield.PLAYFIELD_HEIGHT - strong_hit_diameter) / 2f - border_offset), + Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - strong_hit_diameter) / 2f - border_offset), Alpha = 0.1f }, }; diff --git a/osu.Game.Modes.Taiko/UI/InputDrum.cs b/osu.Game.Modes.Taiko/UI/InputDrum.cs index 0c1e1105cb..d238c38e74 100644 --- a/osu.Game.Modes.Taiko/UI/InputDrum.cs +++ b/osu.Game.Modes.Taiko/UI/InputDrum.cs @@ -21,7 +21,7 @@ namespace osu.Game.Modes.Taiko.UI { public InputDrum() { - Size = new Vector2(TaikoPlayfield.PLAYFIELD_HEIGHT); + Size = new Vector2(TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT); const float middle_split = 10; diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs index 9e7eb571a1..0407cbc5fd 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs @@ -25,7 +25,7 @@ namespace osu.Game.Modes.Taiko.UI /// The play field height. This is relative to the size of hit objects /// such that the playfield is just a bit larger than strong hits. /// - public const float PLAYFIELD_HEIGHT = TaikoHitObject.CIRCLE_RADIUS * 2 * 2; + public const float DEFAULT_PLAYFIELD_HEIGHT = TaikoHitObject.CIRCLE_RADIUS * 2 * 2; /// /// The offset from which the center of the hit target lies at. @@ -53,7 +53,7 @@ namespace osu.Game.Modes.Taiko.UI public TaikoPlayfield() { RelativeSizeAxes = Axes.X; - Height = PLAYFIELD_HEIGHT; + Height = DEFAULT_PLAYFIELD_HEIGHT; AddInternal(new Drawable[] { @@ -93,7 +93,8 @@ namespace osu.Game.Modes.Taiko.UI { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, - Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2), + Size = new Vector2(DEFAULT_PLAYFIELD_HEIGHT), + FillMode = FillMode.Fit, BlendingMode = BlendingMode.Additive }, barLineContainer = new Container @@ -104,6 +105,7 @@ namespace osu.Game.Modes.Taiko.UI { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, + FillMode = FillMode.Fit }, hitObjectContainer = new Container { @@ -111,7 +113,8 @@ namespace osu.Game.Modes.Taiko.UI }, judgementContainer = new Container { - RelativeSizeAxes = Axes.Both, + Size = new Vector2(DEFAULT_PLAYFIELD_HEIGHT), + FillMode = FillMode.Fit, BlendingMode = BlendingMode.Additive }, }, @@ -120,7 +123,8 @@ namespace osu.Game.Modes.Taiko.UI }, leftBackgroundContainer = new Container { - Size = new Vector2(left_area_size, PLAYFIELD_HEIGHT), + RelativeSizeAxes = Axes.Y, + Width = left_area_size, BorderThickness = 1, Children = new Drawable[] { @@ -134,6 +138,7 @@ namespace osu.Game.Modes.Taiko.UI Origin = Anchor.Centre, RelativePositionAxes = Axes.X, Position = new Vector2(0.10f, 0), + FillMode = FillMode.Fit, Scale = new Vector2(0.9f) }, new Box @@ -164,6 +169,9 @@ namespace osu.Game.Modes.Taiko.UI public override void Add(DrawableHitObject h) { + h.AutoSizeAxes = h.AutoSizeAxes & ~Axes.Y; + h.Height = DEFAULT_PLAYFIELD_HEIGHT; + h.FillMode = FillMode.Fit; h.Depth = (float)h.HitObject.StartTime; base.Add(h); From 88666c865f3e673500c19f6e11cb61918f9a7997 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 09:23:00 +0900 Subject: [PATCH 05/18] Make hit objects default size relative to play field size, not the other way around. --- .../Objects/Drawables/DrawableSwell.cs | 4 ++-- .../Objects/Drawables/Pieces/CirclePiece.cs | 11 +++------- .../Objects/Drawables/Pieces/TaikoPiece.cs | 2 +- .../Objects/Drawables/Pieces/TickPiece.cs | 4 ++-- .../Objects/TaikoHitObject.cs | 20 +++++++++++++++++-- osu.Game.Modes.Taiko/UI/HitExplosion.cs | 9 ++------- osu.Game.Modes.Taiko/UI/HitTarget.cs | 18 ++++------------- osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs | 4 ++-- 8 files changed, 34 insertions(+), 38 deletions(-) diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs index e1a590a025..1e440df69a 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs @@ -65,7 +65,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre, Alpha = 0, - Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2), + Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER), BlendingMode = BlendingMode.Additive, Masking = true, Children = new [] @@ -82,7 +82,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables Name = "Target ring (thick border)", Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2), + Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER), Masking = true, BorderThickness = target_ring_thick_border, BlendingMode = BlendingMode.Additive, diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs index f921511e22..216e05ebc4 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs @@ -19,15 +19,10 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces /// public class CirclePiece : TaikoPiece { - public const float SYMBOL_SIZE = TaikoHitObject.CIRCLE_RADIUS * 2f * 0.45f; + public const float SYMBOL_SIZE = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER * 0.45f; public const float SYMBOL_BORDER = 8; public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER; - /// - /// The amount to scale up the base circle to show it as a "strong" piece. - /// - private const float strong_scale = 1.5f; - /// /// The colour of the inner circle and outer glows. /// @@ -129,10 +124,10 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces if (isStrong) { - Size *= strong_scale; + Size *= TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE; //default for symbols etc. - Content.Scale *= strong_scale; + Content.Scale *= TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE; } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs index a0c8865c59..2220438a4a 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs @@ -39,7 +39,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces public TaikoPiece() { //just a default - Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2); + Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER); } } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs index 697102eb22..53e795e2e2 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs @@ -15,12 +15,12 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces /// Any tick that is not the first for a drumroll is not filled, but is instead displayed /// as a hollow circle. This is what controls the border width of that circle. /// - private const float tick_border_width = TaikoHitObject.CIRCLE_RADIUS / 2 / 4; + private const float tick_border_width = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 16; /// /// The size of a tick. /// - private const float tick_size = TaikoHitObject.CIRCLE_RADIUS / 2; + private const float tick_size = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 4; private bool filled; public bool Filled diff --git a/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs index 54ab8c5300..ebc9b19d3a 100644 --- a/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs @@ -4,15 +4,31 @@ using osu.Game.Beatmaps.Timing; using osu.Game.Database; using osu.Game.Modes.Objects; +using osu.Game.Modes.Taiko.UI; namespace osu.Game.Modes.Taiko.Objects { public abstract class TaikoHitObject : HitObject { /// - /// HitCircle radius. + /// Diameter of a circle relative to the size of the . /// - public const float CIRCLE_RADIUS = 42f; + public const float PLAYFIELD_RELATIVE_DIAMETER = 0.5f; + + /// + /// Scale multiplier for a strong circle. + /// + public const float STRONG_CIRCLE_DIAMETER_SCALE = 1.5f; + + /// + /// Default circle diameter. + /// + public const float DEFAULT_CIRCLE_DIAMETER = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT * PLAYFIELD_RELATIVE_DIAMETER; + + /// + /// Default strong circle diameter. + /// + public const float DEFAULT_STRONG_CIRCLE_DIAMETER = DEFAULT_CIRCLE_DIAMETER * STRONG_CIRCLE_DIAMETER_SCALE; /// /// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a of 1000ms. diff --git a/osu.Game.Modes.Taiko/UI/HitExplosion.cs b/osu.Game.Modes.Taiko/UI/HitExplosion.cs index eb43c1a5d0..e4e329523f 100644 --- a/osu.Game.Modes.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Modes.Taiko/UI/HitExplosion.cs @@ -18,11 +18,6 @@ namespace osu.Game.Modes.Taiko.UI /// internal class HitExplosion : CircularContainer { - /// - /// The size multiplier of a hit explosion if a hit object has been hit with the second key. - /// - private const float secondhit_size_multiplier = 1.5f; - /// /// The judgement this hit explosion visualises. /// @@ -34,7 +29,7 @@ namespace osu.Game.Modes.Taiko.UI { Judgement = judgement; - Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2); + Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER); Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -85,7 +80,7 @@ namespace osu.Game.Modes.Taiko.UI /// public void VisualiseSecondHit() { - ResizeTo(Size * secondhit_size_multiplier, 50); + ResizeTo(Size * TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE, 50); } } } diff --git a/osu.Game.Modes.Taiko/UI/HitTarget.cs b/osu.Game.Modes.Taiko/UI/HitTarget.cs index f5d6a3b797..b22dc1d647 100644 --- a/osu.Game.Modes.Taiko/UI/HitTarget.cs +++ b/osu.Game.Modes.Taiko/UI/HitTarget.cs @@ -15,16 +15,6 @@ namespace osu.Game.Modes.Taiko.UI /// internal class HitTarget : Container { - /// - /// Diameter of normal hit object circles. - /// - private const float normal_diameter = TaikoHitObject.CIRCLE_RADIUS * 2; - - /// - /// Diameter of strong hit object circles. - /// - private const float strong_hit_diameter = normal_diameter * 1.5f; - /// /// The 1px inner border of the taiko playfield. /// @@ -47,7 +37,7 @@ namespace osu.Game.Modes.Taiko.UI Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Y = border_offset, - Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - strong_hit_diameter) / 2f - border_offset), + Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER) / 2f - border_offset), Alpha = 0.1f }, new CircularContainer @@ -55,7 +45,7 @@ namespace osu.Game.Modes.Taiko.UI Name = "Strong Hit Ring", Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(strong_hit_diameter), + Size = new Vector2(TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER), Masking = true, BorderColour = Color4.White, BorderThickness = border_thickness, @@ -75,7 +65,7 @@ namespace osu.Game.Modes.Taiko.UI Name = "Normal Hit Ring", Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(normal_diameter), + Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER), Masking = true, BorderColour = Color4.White, BorderThickness = border_thickness, @@ -96,7 +86,7 @@ namespace osu.Game.Modes.Taiko.UI Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Y = -border_offset, - Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - strong_hit_diameter) / 2f - border_offset), + Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER) / 2f - border_offset), Alpha = 0.1f }, }; diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs index 0407cbc5fd..ad21f22d1e 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs @@ -25,12 +25,12 @@ namespace osu.Game.Modes.Taiko.UI /// The play field height. This is relative to the size of hit objects /// such that the playfield is just a bit larger than strong hits. /// - public const float DEFAULT_PLAYFIELD_HEIGHT = TaikoHitObject.CIRCLE_RADIUS * 2 * 2; + public const float DEFAULT_PLAYFIELD_HEIGHT = 168f; /// /// The offset from which the center of the hit target lies at. /// - private const float hit_target_offset = TaikoHitObject.CIRCLE_RADIUS * 1.5f + 40; + private const float hit_target_offset = TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER / 2f + 40; /// /// The size of the left area of the playfield. This area contains the input drum. From e95c7dfa3731ccab60a4fd9b9ec312a4dd72f4a2 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 09:33:46 +0900 Subject: [PATCH 06/18] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 45e75163b2..3d74f40e52 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 45e75163b272b7aa023afec7801ea079aba4ee69 +Subproject commit 3d74f40e524adac263ead7437894a7b11fbf5a20 From 05ac73edcb18241c7822a941deba83388d875aae Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 10:33:52 +0900 Subject: [PATCH 07/18] Apply width modification to hit object container instead of hit objects, to preserve original size. --- osu-framework | 2 +- .../Drawables/DrawableTaikoHitObject.cs | 4 +--- osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs | 23 +++++++++++++++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/osu-framework b/osu-framework index 3d74f40e52..49775b9d5e 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 3d74f40e524adac263ead7437894a7b11fbf5a20 +Subproject commit 49775b9d5e7a383d78ef1018532040823fe18e76 diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 7cd9f9baa5..13ea09aab0 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -22,7 +22,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables /// private readonly List validKeys = new List(new[] { Key.D, Key.F, Key.J, Key.K }); - public override Vector2 OriginPosition => new Vector2(bodyContainer.DrawHeight / 2f, DrawHeight / 2f); + public override Vector2 OriginPosition => new Vector2(DrawHeight / 2f); protected override Container Content => bodyContainer; @@ -46,8 +46,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables AddInternal(bodyContainer = new Container { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, Children = new[] { diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs index ad21f22d1e..0056592447 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs @@ -107,9 +107,10 @@ namespace osu.Game.Modes.Taiko.UI Origin = Anchor.Centre, FillMode = FillMode.Fit }, - hitObjectContainer = new Container + hitObjectContainer = new HitObjectContainer { - RelativeSizeAxes = Axes.Both, + Height = DEFAULT_PLAYFIELD_HEIGHT, + FillMode = FillMode.Fit }, judgementContainer = new Container { @@ -169,9 +170,6 @@ namespace osu.Game.Modes.Taiko.UI public override void Add(DrawableHitObject h) { - h.AutoSizeAxes = h.AutoSizeAxes & ~Axes.Y; - h.Height = DEFAULT_PLAYFIELD_HEIGHT; - h.FillMode = FillMode.Fit; h.Depth = (float)h.HitObject.StartTime; base.Add(h); @@ -216,5 +214,20 @@ namespace osu.Game.Modes.Taiko.UI else hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit(); } + + private class HitObjectContainer : Container + { + public HitObjectContainer() + { + RelativeSizeAxes = Axes.X; + } + + protected override void Update() + { + base.Update(); + + Width = 1 / DrawScale.X; + } + } } } \ No newline at end of file From 30b5b6f7e2bcb0d018ea744b555df9178dfd3045 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 11:54:01 +0900 Subject: [PATCH 08/18] General cleanup. --- osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs | 2 +- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 +- osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 695717ce9e..0a0098dd34 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -49,7 +49,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(HitObject.IsStrong) { Length = (float)(HitObject.Duration / HitObject.ScrollTime), - PlayfieldLengthReference = () => Parent.DrawSize.X / DrawScale.X + PlayfieldLengthReference = () => Parent.DrawSize.X }; [BackgroundDependencyLoader] diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 13ea09aab0..f15f2bd152 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -22,7 +22,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables /// private readonly List validKeys = new List(new[] { Key.D, Key.F, Key.J, Key.K }); - public override Vector2 OriginPosition => new Vector2(DrawHeight / 2f); + public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); protected override Container Content => bodyContainer; diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs index 0056592447..4cbae2c3aa 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs @@ -215,6 +215,9 @@ namespace osu.Game.Modes.Taiko.UI hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit(); } + /// + /// Container for hit objects. Locks width to parent width even through scale. + /// private class HitObjectContainer : Container { public HitObjectContainer() From e73f543c4f02a140418da3b1e5bb517aafca2190 Mon Sep 17 00:00:00 2001 From: Andrey Zavadskiy Date: Mon, 10 Apr 2017 06:06:10 +0300 Subject: [PATCH 09/18] Applied suggestions --- ...{RetryOverlay.cs => HotkeyRetryOverlay.cs} | 45 ++++++++++++------- osu.Game/Screens/Play/Player.cs | 4 +- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 32 insertions(+), 19 deletions(-) rename osu.Game/Screens/Play/{RetryOverlay.cs => HotkeyRetryOverlay.cs} (53%) diff --git a/osu.Game/Screens/Play/RetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs similarity index 53% rename from osu.Game/Screens/Play/RetryOverlay.cs rename to osu.Game/Screens/Play/HotkeyRetryOverlay.cs index e44f7d8914..4e383510fc 100644 --- a/osu.Game/Screens/Play/RetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -8,23 +8,41 @@ using osu.Framework.Audio.Sample; using osu.Framework.Audio; using System; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using OpenTK.Graphics; +using osu.Framework.Threading; namespace osu.Game.Screens.Play { - public class RetryOverlay : Container + public class HotkeyRetryOverlay : Container { public Action Action; - public Action OnKeyPressed; - public Action OnKeyReleased; private SampleChannel retrySample; - private bool keyIsHeld; + private ScheduledDelegate task; + private Box overlay; + + private const int activate_delay = 500; + private const int fadeout_delay = 200; [BackgroundDependencyLoader] private void load(AudioManager audio) { retrySample = audio.Sample.Get(@"Menu/menuback"); + RelativeSizeAxes = Axes.Both; AlwaysPresent = true; + + Children = new Drawable[] + { + overlay = new Box + { + Alpha = 0, + AlwaysPresent = true, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + } + }; } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) @@ -33,17 +51,14 @@ namespace osu.Game.Screens.Play if (args.Key == Key.Tilde) { - keyIsHeld = true; - OnKeyPressed(); + overlay.FadeIn(activate_delay); - Delay(500).Schedule(() => + task = Scheduler.AddDelayed(() => { - if (keyIsHeld) - { - retrySample.Play(); - Action(); - } - }); + retrySample.Play(); + Action(); + }, activate_delay); + return true; } @@ -54,8 +69,8 @@ namespace osu.Game.Screens.Play { if (args.Key == Key.Tilde) { - keyIsHeld = false; - OnKeyReleased(); + task?.Cancel(); + overlay.FadeOut(fadeout_delay); return true; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index af3da23231..939895654b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -159,11 +159,9 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = Exit, }, - new RetryOverlay + new HotkeyRetryOverlay { Action = Restart, - OnKeyPressed = () => Content.FadeColour(Color4.Black, 500), - OnKeyReleased = () => Content.FadeColour(Color4.White, 200), } }; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1777bf6dc2..d90fdda41a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -180,7 +180,7 @@ - + From 1879a05c7beb31f1a3b69bb0234c47fa0235624e Mon Sep 17 00:00:00 2001 From: Andrey Zavadskiy Date: Mon, 10 Apr 2017 06:10:12 +0300 Subject: [PATCH 10/18] Removed using --- osu.Game/Screens/Play/Player.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 939895654b..a7108eda1b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -22,7 +22,6 @@ using System; using System.Linq; using osu.Framework.Threading; using osu.Game.Modes.Scoring; -using OpenTK.Graphics; namespace osu.Game.Screens.Play { From d6f388f8fde4e18a2137d3b0426061a29652593b Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 14:28:01 +0900 Subject: [PATCH 11/18] Add better scale adjustements to TaikoPlayfield. It will now keep the original width while scaling everything inside to match the playfield height. --- osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs | 168 ++++++++++++++-------- 1 file changed, 105 insertions(+), 63 deletions(-) diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs index 4cbae2c3aa..6fe2282d88 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs @@ -16,14 +16,14 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics.Primitives; using System.Linq; using osu.Game.Modes.Taiko.Objects.Drawables; +using System; namespace osu.Game.Modes.Taiko.UI { public class TaikoPlayfield : Playfield { /// - /// The play field height. This is relative to the size of hit objects - /// such that the playfield is just a bit larger than strong hits. + /// The default play field height. /// public const float DEFAULT_PLAYFIELD_HEIGHT = 168f; @@ -53,12 +53,15 @@ namespace osu.Game.Modes.Taiko.UI public TaikoPlayfield() { RelativeSizeAxes = Axes.X; + + // Default height Height = DEFAULT_PLAYFIELD_HEIGHT; AddInternal(new Drawable[] { rightBackgroundContainer = new Container { + Name = "Transparent playfield background", RelativeSizeAxes = Axes.Both, BorderThickness = 2, Masking = true, @@ -77,82 +80,88 @@ namespace osu.Game.Modes.Taiko.UI }, } }, - new Container + new ScaleFixContainer { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = left_area_size }, - Children = new Drawable[] + RelativeSizeAxes = Axes.X, + Height = DEFAULT_PLAYFIELD_HEIGHT, + Children = new[] { new Container { - X = hit_target_offset, + Name = "Transparent playfield elements", RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = left_area_size }, Children = new Drawable[] { - hitExplosionContainer = new Container + new Container { - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, - Size = new Vector2(DEFAULT_PLAYFIELD_HEIGHT), - FillMode = FillMode.Fit, - BlendingMode = BlendingMode.Additive + Name = "Hit target container", + X = hit_target_offset, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + hitExplosionContainer = new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + BlendingMode = BlendingMode.Additive + }, + barLineContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + new HitTarget + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + }, + hitObjectContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + judgementContainer = new Container + { + RelativeSizeAxes = Axes.Y, + BlendingMode = BlendingMode.Additive + }, + }, }, - barLineContainer = new Container + } + }, + leftBackgroundContainer = new Container + { + Name = "Left overlay", + Size = new Vector2(left_area_size, DEFAULT_PLAYFIELD_HEIGHT), + BorderThickness = 1, + Children = new Drawable[] + { + leftBackground = new Box { RelativeSizeAxes = Axes.Both, }, - new HitTarget + new InputDrum { - Anchor = Anchor.CentreLeft, + Anchor = Anchor.Centre, Origin = Anchor.Centre, - FillMode = FillMode.Fit + RelativePositionAxes = Axes.X, + Position = new Vector2(0.10f, 0), + Scale = new Vector2(0.9f) }, - hitObjectContainer = new HitObjectContainer + new Box { - Height = DEFAULT_PLAYFIELD_HEIGHT, - FillMode = FillMode.Fit + Anchor = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 10, + ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)), }, - judgementContainer = new Container - { - Size = new Vector2(DEFAULT_PLAYFIELD_HEIGHT), - FillMode = FillMode.Fit, - BlendingMode = BlendingMode.Additive - }, - }, - }, - } - }, - leftBackgroundContainer = new Container - { - RelativeSizeAxes = Axes.Y, - Width = left_area_size, - BorderThickness = 1, - Children = new Drawable[] - { - leftBackground = new Box - { - RelativeSizeAxes = Axes.Both, - }, - new InputDrum - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativePositionAxes = Axes.X, - Position = new Vector2(0.10f, 0), - FillMode = FillMode.Fit, - Scale = new Vector2(0.9f) - }, - new Box - { - Anchor = Anchor.TopRight, - RelativeSizeAxes = Axes.Y, - Width = 10, - ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)), + } }, } }, topLevelHitContainer = new Container { + Name = "Top level hit objects", RelativeSizeAxes = Axes.Both, } }); @@ -216,20 +225,53 @@ namespace osu.Game.Modes.Taiko.UI } /// - /// Container for hit objects. Locks width to parent width even through scale. + /// This is a very special type of container. It serves a similar purpose to , however unlike , + /// this will only adjust the scale relative to the height of its parent and will maintain the original width relative to its parent. + /// + /// + /// By adjusting the scale relative to the height of its parent, the aspect ratio of this container's children is maintained, however this is undesirable + /// in the case where the hit object container should not have its width adjusted by scale. To counteract this, another container is nested inside this + /// container which takes care of reversing the width adjustment while appearing transparent to the user. + /// /// - private class HitObjectContainer : Container + private class ScaleFixContainer : Container { - public HitObjectContainer() + protected override Container Content => widthAdjustmentContainer; + private readonly WidthAdjustmentContainer widthAdjustmentContainer; + + /// + /// We only want to apply DrawScale in the Y-axis to preserve aspect ratio and doesn't care about having its width adjusted. + /// + protected override Vector2 DrawScale => Scale * RelativeToAbsoluteFactor.Y / DrawHeight; + + public ScaleFixContainer() { - RelativeSizeAxes = Axes.X; + AddInternal(widthAdjustmentContainer = new WidthAdjustmentContainer { ParentDrawScaleReference = () => DrawScale.X }); } - protected override void Update() + /// + /// The container type that reverses the width adjustment. + /// + private class WidthAdjustmentContainer : Container { - base.Update(); + /// + /// This container needs to know its parent's so it can reverse the width adjustment caused by . + /// + public Func ParentDrawScaleReference; - Width = 1 / DrawScale.X; + public WidthAdjustmentContainer() + { + // This container doesn't care about height, it should always fill its parent + RelativeSizeAxes = Axes.Y; + } + + protected override void Update() + { + base.Update(); + + // Reverse the DrawScale adjustment + Width = Parent.DrawSize.X / ParentDrawScaleReference(); + } } } } From f4094fbde244901d1e4e159f8bf63831e1901bb2 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 14:28:28 +0900 Subject: [PATCH 12/18] Extend TestCaseTaikoPlayfield a bit. --- .../Tests/TestCaseTaikoPlayfield.cs | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs index a942535d06..a8e4382ebb 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; @@ -11,20 +12,21 @@ using osu.Game.Modes.Taiko.Judgements; using osu.Game.Modes.Taiko.Objects; using osu.Game.Modes.Taiko.Objects.Drawables; using osu.Game.Modes.Taiko.UI; +using System; namespace osu.Desktop.VisualTests.Tests { internal class TestCaseTaikoPlayfield : TestCase { - public override string Description => "Taiko playfield"; + private const double default_duration = 300; + private const float scroll_time = 1000; - private TaikoPlayfield playfield; + public override string Description => "Taiko playfield"; protected override double TimePerAction => default_duration * 2; - private const double default_duration = 300; - - private const float scroll_time = 1000; + private readonly Random rng = new Random(1337); + private TaikoPlayfield playfield; public override void Reset() { @@ -41,7 +43,11 @@ namespace osu.Desktop.VisualTests.Tests AddStep("Strong Rim", () => addRimHit(true)); AddStep("Add bar line", () => addBarLine(false)); AddStep("Add major bar line", () => addBarLine(true)); - + AddStep("Height test 1", () => changePlayfieldSize(1)); + AddStep("Height test 2", () => changePlayfieldSize(2)); + AddStep("Height test 3", () => changePlayfieldSize(3)); + AddStep("Height test 4", () => changePlayfieldSize(4)); + AddStep("Height test 5", () => changePlayfieldSize(5)); var rateAdjustClock = new StopwatchClock(true) { Rate = 1 }; @@ -57,6 +63,31 @@ namespace osu.Desktop.VisualTests.Tests }); } + private void changePlayfieldSize(int step) + { + switch (step) + { + case 1: + addCentreHit(false); + break; + case 2: + addCentreHit(true); + break; + case 3: + addDrumRoll(false); + break; + case 4: + addDrumRoll(true); + break; + case 5: + addSwell(1000); + playfield.Delay(scroll_time - 100); + break; + } + + playfield.ResizeTo(new Vector2(1, rng.Next(25, 400)), 500); + } + private void addHitJudgement() { TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great; From b57351f6e301cd0a66c3ddc7905c38e3a49671c3 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 10 Apr 2017 14:43:13 +0900 Subject: [PATCH 13/18] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 49775b9d5e..7ac3dbff36 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 49775b9d5e7a383d78ef1018532040823fe18e76 +Subproject commit 7ac3dbff3615fb410da1e330e6379b53a41292b6 From 15c1013f5b68279f65e00b9657ac6df36b2e07a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Apr 2017 17:25:46 +0900 Subject: [PATCH 14/18] Don't schedule event, it's unreliable and doesn't match the fade. --- osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index 4e383510fc..3fcd773c19 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using OpenTK.Graphics; -using osu.Framework.Threading; namespace osu.Game.Screens.Play { @@ -20,12 +19,13 @@ namespace osu.Game.Screens.Play public Action Action; private SampleChannel retrySample; - private ScheduledDelegate task; private Box overlay; private const int activate_delay = 500; private const int fadeout_delay = 200; + private bool fired; + [BackgroundDependencyLoader] private void load(AudioManager audio) { @@ -52,13 +52,6 @@ namespace osu.Game.Screens.Play if (args.Key == Key.Tilde) { overlay.FadeIn(activate_delay); - - task = Scheduler.AddDelayed(() => - { - retrySample.Play(); - Action(); - }, activate_delay); - return true; } @@ -67,14 +60,24 @@ namespace osu.Game.Screens.Play protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) { - if (args.Key == Key.Tilde) + if (args.Key == Key.Tilde && !fired) { - task?.Cancel(); overlay.FadeOut(fadeout_delay); return true; } return base.OnKeyUp(state, args); } + + protected override void Update() + { + base.Update(); + if (!fired && overlay.Alpha == 1) + { + fired = true; + retrySample.Play(); + Action?.Invoke(); + } + } } } From 3a01cfccee5db6e0fabf9e2eea7cb5e169131836 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Apr 2017 17:25:56 +0900 Subject: [PATCH 15/18] Adjust fade length and easing. --- osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index 3fcd773c19..6b30644ab0 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Play private SampleChannel retrySample; private Box overlay; - private const int activate_delay = 500; + private const int activate_delay = 400; private const int fadeout_delay = 200; private bool fired; @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play if (args.Key == Key.Tilde) { - overlay.FadeIn(activate_delay); + overlay.FadeIn(activate_delay, EasingTypes.Out); return true; } @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Play { if (args.Key == Key.Tilde && !fired) { - overlay.FadeOut(fadeout_delay); + overlay.FadeOut(fadeout_delay, EasingTypes.Out); return true; } From 43a46575404168ee8fd1e1b7ae99a6b9eb8b6ef7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Apr 2017 17:26:05 +0900 Subject: [PATCH 16/18] Remove unnecessary AlwaysPresent. --- osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index 6b30644ab0..16062bebe5 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -38,7 +38,6 @@ namespace osu.Game.Screens.Play overlay = new Box { Alpha = 0, - AlwaysPresent = true, Colour = Color4.Black, RelativeSizeAxes = Axes.Both, } From 960ea27684610167124338fb41621f9b9ee7c9f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Apr 2017 19:21:27 +0900 Subject: [PATCH 17/18] Make all Playfields completely relative. --- osu.Game.Modes.Catch/UI/CatchPlayfield.cs | 3 +-- osu.Game.Modes.Mania/UI/ManiaPlayfield.cs | 3 +-- osu.Game.Modes.Osu/UI/OsuPlayfield.cs | 2 -- osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs | 5 ----- osu.Game/Modes/UI/Playfield.cs | 7 +++++++ 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game.Modes.Catch/UI/CatchPlayfield.cs b/osu.Game.Modes.Catch/UI/CatchPlayfield.cs index cf1a665470..f8792a7fd5 100644 --- a/osu.Game.Modes.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Modes.Catch/UI/CatchPlayfield.cs @@ -14,8 +14,7 @@ namespace osu.Game.Modes.Catch.UI { public CatchPlayfield() { - RelativeSizeAxes = Axes.Y; - Size = new Vector2(512, 0.9f); + Size = new Vector2(1, 0.9f); Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; diff --git a/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs b/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs index 670d18f71f..deb4ebac25 100644 --- a/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Modes.Mania/UI/ManiaPlayfield.cs @@ -15,8 +15,7 @@ namespace osu.Game.Modes.Mania.UI { public ManiaPlayfield(int columns) { - RelativeSizeAxes = Axes.Both; - Size = new Vector2(columns / 20f, 1f); + Size = new Vector2(0.8f, 1f); Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; diff --git a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs index d89bbfd131..4164607b4d 100644 --- a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs @@ -38,8 +38,6 @@ namespace osu.Game.Modes.Osu.UI { Anchor = Anchor.Centre; Origin = Anchor.Centre; - RelativeSizeAxes = Axes.Both; - Size = new Vector2(0.75f); Add(new Drawable[] { diff --git a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs index 6fe2282d88..db3a1bc84e 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs @@ -52,11 +52,6 @@ namespace osu.Game.Modes.Taiko.UI public TaikoPlayfield() { - RelativeSizeAxes = Axes.X; - - // Default height - Height = DEFAULT_PLAYFIELD_HEIGHT; - AddInternal(new Drawable[] { rightBackgroundContainer = new Container diff --git a/osu.Game/Modes/UI/Playfield.cs b/osu.Game/Modes/UI/Playfield.cs index f31ee0f189..bf5f0acde5 100644 --- a/osu.Game/Modes/UI/Playfield.cs +++ b/osu.Game/Modes/UI/Playfield.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Modes.Objects; @@ -63,6 +64,12 @@ namespace osu.Game.Modes.UI Add(HitObjects); } + public override Axes RelativeSizeAxes + { + get { return Axes.Both; } + set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); } + } + /// /// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield. /// From b9ce98efd65965c495305158e07111a95ebec404 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Apr 2017 19:22:02 +0900 Subject: [PATCH 18/18] Add AspectAdjust to HitRenderer to allow playfield to consume ful HitRenderer size when needed. --- osu.Game.Modes.Osu/UI/OsuHitRenderer.cs | 3 +++ osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs | 12 ++++++++++++ osu.Game/Modes/UI/HitRenderer.cs | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs b/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs index ca9ff6fc61..7e314c5ba1 100644 --- a/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs +++ b/osu.Game.Modes.Osu/UI/OsuHitRenderer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK; using osu.Game.Beatmaps; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Osu.Beatmaps; @@ -46,5 +47,7 @@ namespace osu.Game.Modes.Osu.UI return new DrawableSpinner(spinner); return null; } + + protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f); } } diff --git a/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs b/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs index 29fa693d58..32476dff7f 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs @@ -17,6 +17,7 @@ using osu.Game.Modes.Taiko.Objects.Drawables; using osu.Game.Modes.Taiko.Scoring; using osu.Game.Modes.UI; using osu.Game.Modes.Taiko.Replays; +using OpenTK; namespace osu.Game.Modes.Taiko.UI { @@ -100,6 +101,17 @@ namespace osu.Game.Modes.Taiko.UI } } + protected override Vector2 GetPlayfieldAspectAdjust() + { + const float default_relative_height = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT / 768; + const float default_aspect = 16f / 9f; + + float aspectAdjust = MathHelper.Clamp(DrawWidth / DrawHeight, 0.4f, 4) / default_aspect; + + return new Vector2(1, default_relative_height * aspectAdjust); + } + + public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this); protected override IBeatmapConverter CreateBeatmapConverter() => new TaikoBeatmapConverter(); diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs index a958c61c68..afc525d686 100644 --- a/osu.Game/Modes/UI/HitRenderer.cs +++ b/osu.Game/Modes/UI/HitRenderer.cs @@ -16,6 +16,7 @@ using System.Diagnostics; using System.Linq; using osu.Game.Modes.Replays; using osu.Game.Modes.Scoring; +using OpenTK; namespace osu.Game.Modes.UI { @@ -167,6 +168,11 @@ namespace osu.Game.Modes.UI { public event Action OnJudgement; + /// + /// Whether to apply adjustments to the child based on our own size. + /// + public bool AspectAdjust = true; + public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor; protected override Container Content => content; @@ -219,6 +225,19 @@ namespace osu.Game.Modes.UI Playfield.PostProcess(); } + protected override void Update() + { + base.Update(); + + Playfield.Size = AspectAdjust ? GetPlayfieldAspectAdjust() : Vector2.One; + } + + /// + /// In some cases we want to apply changes to the relative size of our contained based on custom conditions. + /// + /// + protected virtual Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f); //a sane default + /// /// Triggered when an object's Judgement is updated. ///