From 31f6cbd8cfaf229256ce8f7879d94f0824531922 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 10 Mar 2017 11:59:08 +0900 Subject: [PATCH] Rename ScoreOverlay -> HUDOverlay, move to osu.Game, make it not overridable by rulesets. --- .../Tests/TestCaseScoreCounter.cs | 26 +- osu.Game.Modes.Catch/CatchRuleset.cs | 16 +- osu.Game.Modes.Mania/ManiaRuleset.cs | 10 +- osu.Game.Modes.Osu/OsuRuleset.cs | 16 +- osu.Game.Modes.Osu/UI/OsuComboCounter.cs | 141 -------- osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj | 2 - osu.Game.Modes.Taiko/Objects/DrumHit.cs | 15 + osu.Game.Modes.Taiko/TaikoRuleset.cs | 13 +- .../osu.Game.Modes.Taiko.csproj | 1 + osu.Game/Modes/Ruleset.cs | 15 +- osu.Game/Modes/UI/BaseComboCounter.cs | 267 ++++++++++++++ osu.Game/Modes/UI/ComboCounter.cs | 325 ++++++------------ .../UI/{ScoreOverlay.cs => HUDOverlay.cs} | 27 +- .../Modes/UI/StandardHUDOverlay.cs | 42 ++- osu.Game/Screens/Play/Player.cs | 40 +-- osu.Game/osu.Game.csproj | 6 +- 16 files changed, 499 insertions(+), 463 deletions(-) delete mode 100644 osu.Game.Modes.Osu/UI/OsuComboCounter.cs create mode 100644 osu.Game.Modes.Taiko/Objects/DrumHit.cs create mode 100644 osu.Game/Modes/UI/BaseComboCounter.cs rename osu.Game/Modes/UI/{ScoreOverlay.cs => HUDOverlay.cs} (87%) rename osu.Game.Modes.Osu/UI/OsuScoreOverlay.cs => osu.Game/Modes/UI/StandardHUDOverlay.cs (69%) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs index a3560e7400..abed40a919 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs @@ -40,7 +40,7 @@ namespace osu.Desktop.VisualTests.Tests }; Add(score); - ComboCounter standardCombo = new OsuComboCounter + BaseComboCounter comboCounter = new ComboCounter { Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, @@ -48,15 +48,15 @@ namespace osu.Desktop.VisualTests.Tests Count = 0, TextSize = 40, }; - Add(standardCombo); + Add(comboCounter); - PercentageCounter accuracyCombo = new PercentageCounter + PercentageCounter accuracyCounter = new PercentageCounter { Origin = Anchor.TopRight, Anchor = Anchor.TopRight, Position = new Vector2(-20, 60), }; - Add(accuracyCombo); + Add(accuracyCounter); StarCounter stars = new StarCounter { @@ -79,26 +79,26 @@ namespace osu.Desktop.VisualTests.Tests AddButton(@"Reset all", delegate { score.Count = 0; - standardCombo.Count = 0; + comboCounter.Count = 0; numerator = denominator = 0; - accuracyCombo.SetFraction(0, 0); + accuracyCounter.SetFraction(0, 0); stars.Count = 0; starsLabel.Text = stars.Count.ToString("0.00"); }); AddButton(@"Hit! :D", delegate { - score.Count += 300 + (ulong)(300.0 * (standardCombo.Count > 0 ? standardCombo.Count - 1 : 0) / 25.0); - standardCombo.Count++; + score.Count += 300 + (ulong)(300.0 * (comboCounter.Count > 0 ? comboCounter.Count - 1 : 0) / 25.0); + comboCounter.Count++; numerator++; denominator++; - accuracyCombo.SetFraction(numerator, denominator); + accuracyCounter.SetFraction(numerator, denominator); }); AddButton(@"miss...", delegate { - standardCombo.Roll(); + comboCounter.Roll(); denominator++; - accuracyCombo.SetFraction(numerator, denominator); + accuracyCounter.SetFraction(numerator, denominator); }); AddButton(@"Alter stars", delegate @@ -110,8 +110,8 @@ namespace osu.Desktop.VisualTests.Tests AddButton(@"Stop counters", delegate { score.StopRolling(); - standardCombo.StopRolling(); - accuracyCombo.StopRolling(); + comboCounter.StopRolling(); + accuracyCounter.StopRolling(); stars.StopAnimation(); }); } diff --git a/osu.Game.Modes.Catch/CatchRuleset.cs b/osu.Game.Modes.Catch/CatchRuleset.cs index 737bd99f94..b552278cec 100644 --- a/osu.Game.Modes.Catch/CatchRuleset.cs +++ b/osu.Game.Modes.Catch/CatchRuleset.cs @@ -1,20 +1,19 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; +using OpenTK.Input; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Modes.Catch.UI; using osu.Game.Modes.Objects; -using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; -using osu.Game.Beatmaps; +using osu.Game.Screens.Play; +using System.Collections.Generic; namespace osu.Game.Modes.Catch { public class CatchRuleset : Ruleset { - public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new CatchHitRenderer { Beatmap = beatmap, @@ -81,6 +80,13 @@ namespace osu.Game.Modes.Catch public override FontAwesome Icon => FontAwesome.fa_osu_fruits_o; + public override KeyCounter[] GameplayKeys => new KeyCounter[] + { + new KeyCounterKeyboard(Key.ShiftLeft), + new KeyCounterMouse(MouseButton.Left), + new KeyCounterMouse(MouseButton.Right) + }; + public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => null; public override HitObjectParser CreateHitObjectParser() => new NullHitObjectParser(); diff --git a/osu.Game.Modes.Mania/ManiaRuleset.cs b/osu.Game.Modes.Mania/ManiaRuleset.cs index 6d5606f796..51a33ce7bc 100644 --- a/osu.Game.Modes.Mania/ManiaRuleset.cs +++ b/osu.Game.Modes.Mania/ManiaRuleset.cs @@ -1,20 +1,18 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Modes.Mania.UI; using osu.Game.Modes.Objects; -using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; -using osu.Game.Beatmaps; +using osu.Game.Screens.Play; +using System.Collections.Generic; namespace osu.Game.Modes.Mania { public class ManiaRuleset : Ruleset { - public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new ManiaHitRenderer { Beatmap = beatmap, @@ -102,6 +100,8 @@ namespace osu.Game.Modes.Mania public override FontAwesome Icon => FontAwesome.fa_osu_mania_o; + public override KeyCounter[] GameplayKeys => new KeyCounter[] { /* Todo: Should be keymod specific */ }; + public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => null; public override HitObjectParser CreateHitObjectParser() => new NullHitObjectParser(); diff --git a/osu.Game.Modes.Osu/OsuRuleset.cs b/osu.Game.Modes.Osu/OsuRuleset.cs index 68f700cabb..72c4b6988c 100644 --- a/osu.Game.Modes.Osu/OsuRuleset.cs +++ b/osu.Game.Modes.Osu/OsuRuleset.cs @@ -1,21 +1,21 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; -using System.Linq; +using OpenTK.Input; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Modes.Objects; using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; +using osu.Game.Screens.Play; +using System.Collections.Generic; +using System.Linq; namespace osu.Game.Modes.Osu { public class OsuRuleset : Ruleset { - public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new OsuHitRenderer { Beatmap = beatmap, @@ -111,5 +111,13 @@ namespace osu.Game.Modes.Osu } protected override PlayMode PlayMode => PlayMode.Osu; + + public override KeyCounter[] GameplayKeys => new KeyCounter[] + { + new KeyCounterKeyboard(Key.Z), + new KeyCounterKeyboard(Key.X), + new KeyCounterMouse(MouseButton.Left), + new KeyCounterMouse(MouseButton.Right) + }; } } diff --git a/osu.Game.Modes.Osu/UI/OsuComboCounter.cs b/osu.Game.Modes.Osu/UI/OsuComboCounter.cs deleted file mode 100644 index fe24b021a6..0000000000 --- a/osu.Game.Modes.Osu/UI/OsuComboCounter.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Modes.UI; -using OpenTK; - -namespace osu.Game.Modes.Osu.UI -{ - /// - /// Uses the 'x' symbol and has a pop-out effect while rolling over. Used in osu! standard. - /// - public class OsuComboCounter : ComboCounter - { - protected uint ScheduledPopOutCurrentId; - - protected virtual float PopOutSmallScale => 1.1f; - protected virtual bool CanPopOutWhileRolling => false; - - public new Vector2 PopOutScale = new Vector2(1.6f); - - protected override void LoadComplete() - { - base.LoadComplete(); - - PopOutCount.Origin = Origin; - PopOutCount.Anchor = Anchor; - } - - protected override string FormatCount(ulong count) - { - return $@"{count}x"; - } - - protected virtual void TransformPopOut(ulong newValue) - { - PopOutCount.Text = FormatCount(newValue); - - PopOutCount.ScaleTo(PopOutScale); - PopOutCount.FadeTo(PopOutInitialAlpha); - PopOutCount.MoveTo(Vector2.Zero); - - PopOutCount.ScaleTo(1, PopOutDuration, PopOutEasing); - PopOutCount.FadeOut(PopOutDuration, PopOutEasing); - PopOutCount.MoveTo(DisplayedCountSpriteText.Position, PopOutDuration, PopOutEasing); - } - - protected virtual void TransformPopOutRolling(ulong newValue) - { - TransformPopOut(newValue); - TransformPopOutSmall(newValue); - } - - protected virtual void TransformNoPopOut(ulong newValue) - { - DisplayedCountSpriteText.Text = FormatCount(newValue); - DisplayedCountSpriteText.ScaleTo(1); - } - - protected virtual void TransformPopOutSmall(ulong newValue) - { - DisplayedCountSpriteText.Text = FormatCount(newValue); - DisplayedCountSpriteText.ScaleTo(PopOutSmallScale); - DisplayedCountSpriteText.ScaleTo(1, PopOutDuration, PopOutEasing); - } - - protected virtual void ScheduledPopOutSmall(uint id) - { - // Too late; scheduled task invalidated - if (id != ScheduledPopOutCurrentId) - return; - - DisplayedCount++; - } - - protected override void OnCountRolling(ulong currentValue, ulong newValue) - { - ScheduledPopOutCurrentId++; - - // Hides displayed count if was increasing from 0 to 1 but didn't finish - if (currentValue == 0 && newValue == 0) - DisplayedCountSpriteText.FadeOut(FadeOutDuration); - - base.OnCountRolling(currentValue, newValue); - } - - protected override void OnCountIncrement(ulong currentValue, ulong newValue) - { - ScheduledPopOutCurrentId++; - - if (DisplayedCount < currentValue) - DisplayedCount++; - - DisplayedCountSpriteText.Show(); - - TransformPopOut(newValue); - - uint newTaskId = ScheduledPopOutCurrentId; - Scheduler.AddDelayed(delegate - { - ScheduledPopOutSmall(newTaskId); - }, PopOutDuration); - } - - protected override void OnCountChange(ulong currentValue, ulong newValue) - { - ScheduledPopOutCurrentId++; - - if (newValue == 0) - DisplayedCountSpriteText.FadeOut(); - - base.OnCountChange(currentValue, newValue); - } - - protected override void OnDisplayedCountRolling(ulong currentValue, ulong newValue) - { - if (newValue == 0) - DisplayedCountSpriteText.FadeOut(FadeOutDuration); - else - DisplayedCountSpriteText.Show(); - - if (CanPopOutWhileRolling) - TransformPopOutRolling(newValue); - else - TransformNoPopOut(newValue); - } - - protected override void OnDisplayedCountChange(ulong newValue) - { - DisplayedCountSpriteText.FadeTo(newValue == 0 ? 0 : 1); - - TransformNoPopOut(newValue); - } - - protected override void OnDisplayedCountIncrement(ulong newValue) - { - DisplayedCountSpriteText.Show(); - - TransformPopOutSmall(newValue); - } - } -} diff --git a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj index 0571ec2956..ea03841b82 100644 --- a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj +++ b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj @@ -74,7 +74,6 @@ - @@ -85,7 +84,6 @@ - diff --git a/osu.Game.Modes.Taiko/Objects/DrumHit.cs b/osu.Game.Modes.Taiko/Objects/DrumHit.cs new file mode 100644 index 0000000000..f3fac33f76 --- /dev/null +++ b/osu.Game.Modes.Taiko/Objects/DrumHit.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace osu.Game.Modes.Taiko.Objects +{ + class DrumHit + { + } +} diff --git a/osu.Game.Modes.Taiko/TaikoRuleset.cs b/osu.Game.Modes.Taiko/TaikoRuleset.cs index 585b3e97b0..19432e5383 100644 --- a/osu.Game.Modes.Taiko/TaikoRuleset.cs +++ b/osu.Game.Modes.Taiko/TaikoRuleset.cs @@ -1,20 +1,19 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK.Input; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Modes.Objects; -using osu.Game.Modes.Osu.UI; using osu.Game.Modes.Taiko.UI; using osu.Game.Modes.UI; +using osu.Game.Screens.Play; using System.Collections.Generic; namespace osu.Game.Modes.Taiko { public class TaikoRuleset : Ruleset { - public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new TaikoHitRenderer { Beatmap = beatmap, @@ -81,6 +80,14 @@ namespace osu.Game.Modes.Taiko public override FontAwesome Icon => FontAwesome.fa_osu_taiko_o; + public override KeyCounter[] GameplayKeys => new KeyCounter[] + { + new KeyCounterKeyboard(Key.D), + new KeyCounterKeyboard(Key.F), + new KeyCounterKeyboard(Key.J), + new KeyCounterKeyboard(Key.K) + }; + public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => null; public override HitObjectParser CreateHitObjectParser() => new NullHitObjectParser(); diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index 35f5a2d686..ab9ebfa1c7 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -47,6 +47,7 @@ + diff --git a/osu.Game/Modes/Ruleset.cs b/osu.Game/Modes/Ruleset.cs index fefba6caf8..d373b62a21 100644 --- a/osu.Game/Modes/Ruleset.cs +++ b/osu.Game/Modes/Ruleset.cs @@ -1,13 +1,14 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; -using osu.Game.Modes.Objects; -using osu.Game.Modes.UI; -using System; -using System.Collections.Concurrent; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Modes.Objects; +using osu.Game.Modes.UI; +using osu.Game.Screens.Play; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; namespace osu.Game.Modes { @@ -20,9 +21,9 @@ namespace osu.Game.Modes public abstract class Ruleset { - private static ConcurrentDictionary availableRulesets = new ConcurrentDictionary(); + public abstract KeyCounter[] GameplayKeys { get; } - public abstract ScoreOverlay CreateScoreOverlay(); + private static ConcurrentDictionary availableRulesets = new ConcurrentDictionary(); public virtual IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { }; diff --git a/osu.Game/Modes/UI/BaseComboCounter.cs b/osu.Game/Modes/UI/BaseComboCounter.cs new file mode 100644 index 0000000000..73e8226c19 --- /dev/null +++ b/osu.Game/Modes/UI/BaseComboCounter.cs @@ -0,0 +1,267 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Framework.MathUtils; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Modes.UI +{ + public abstract class BaseComboCounter : Container + { + public bool IsRolling + { + get; protected set; + } + + protected SpriteText PopOutCount; + + protected virtual double PopOutDuration => 150; + protected virtual float PopOutScale => 2.0f; + protected virtual EasingTypes PopOutEasing => EasingTypes.None; + protected virtual float PopOutInitialAlpha => 0.75f; + + protected virtual double FadeOutDuration => 100; + + /// + /// Duration in milliseconds for the counter roll-up animation for each element. + /// + protected virtual double RollingDuration => 20; + + /// + /// Easing for the counter rollover animation. + /// + protected EasingTypes RollingEasing => EasingTypes.None; + + private ulong displayedCount; + + /// + /// Value shown at the current moment. + /// + public virtual ulong DisplayedCount + { + get + { + return displayedCount; + } + protected set + { + if (displayedCount.Equals(value)) + return; + updateDisplayedCount(displayedCount, value, IsRolling); + } + } + + private ulong count; + + /// + /// Actual value of counter. + /// + public virtual ulong Count + { + get + { + return count; + } + set + { + updateCount(value); + } + } + + public void Increment(ulong amount = 1) + { + Count = Count + amount; + } + + protected SpriteText DisplayedCountSpriteText; + + private float textSize; + public float TextSize + { + get { return textSize; } + set + { + textSize = value; + DisplayedCountSpriteText.TextSize = TextSize; + PopOutCount.TextSize = TextSize; + } + } + + /// + /// Base of all combo counters. + /// + protected BaseComboCounter() + { + AutoSizeAxes = Axes.Both; + + Children = new Drawable[] + { + DisplayedCountSpriteText = new OsuSpriteText + { + Alpha = 0, + }, + PopOutCount = new OsuSpriteText + { + Alpha = 0, + Margin = new MarginPadding(0.05f), + } + }; + + TextSize = 80; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + DisplayedCountSpriteText.Text = FormatCount(Count); + DisplayedCountSpriteText.Anchor = Anchor; + DisplayedCountSpriteText.Origin = Origin; + + StopRolling(); + } + + /// + /// Stops rollover animation, forcing the displayed count to be the actual count. + /// + public void StopRolling() + { + updateCount(Count); + } + + /// + /// Animates roll-up/roll-back to an specific value. + /// + /// Target value. + public virtual void Roll(ulong newValue = 0) + { + updateCount(newValue, true); + } + + /// + /// Resets count to default value. + /// + public virtual void ResetCount() + { + updateCount(0); + } + + protected virtual string FormatCount(ulong count) + { + return count.ToString(); + } + + protected abstract void OnDisplayedCountRolling(ulong currentValue, ulong newValue); + protected abstract void OnDisplayedCountIncrement(ulong newValue); + protected abstract void OnDisplayedCountChange(ulong newValue); + + protected virtual void OnCountRolling(ulong currentValue, ulong newValue) + { + transformRoll(new TransformComboRoll(), currentValue, newValue); + } + + protected virtual void OnCountIncrement(ulong currentValue, ulong newValue) { + DisplayedCount = newValue; + } + + protected virtual void OnCountChange(ulong currentValue, ulong newValue) { + DisplayedCount = newValue; + } + + private double getProportionalDuration(ulong currentValue, ulong newValue) + { + double difference = currentValue > newValue ? currentValue - newValue : newValue - currentValue; + return difference * RollingDuration; + } + + private void updateDisplayedCount(ulong currentValue, ulong newValue, bool rolling) + { + displayedCount = newValue; + if (rolling) + OnDisplayedCountRolling(currentValue, newValue); + else if (currentValue + 1 == newValue) + OnDisplayedCountIncrement(newValue); + else + OnDisplayedCountChange(newValue); + } + + private void updateCount(ulong value, bool rolling = false) + { + ulong prevCount = count; + count = value; + + if (!IsLoaded) + return; + + if (!rolling) + { + Flush(false, typeof(TransformComboRoll)); + IsRolling = false; + DisplayedCount = prevCount; + + if (prevCount + 1 == count) + OnCountIncrement(prevCount, count); + else + OnCountChange(prevCount, count); + } + else + { + OnCountRolling(displayedCount, count); + IsRolling = true; + } + } + + private void transformRoll(TransformComboRoll transform, ulong currentValue, ulong newValue) + { + Flush(false, typeof(TransformComboRoll)); + + if (RollingDuration < 1) + { + DisplayedCount = Count; + return; + } + + transform.StartTime = Time.Current; + transform.EndTime = Time.Current + getProportionalDuration(currentValue, newValue); + transform.StartValue = currentValue; + transform.EndValue = newValue; + transform.Easing = RollingEasing; + + Transforms.Add(transform); + } + + protected class TransformComboRoll : Transform + { + protected override ulong CurrentValue + { + get + { + double time = Time?.Current ?? 0; + if (time < StartTime) return StartValue; + if (time >= EndTime) return EndValue; + + return (ulong)Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); + } + } + + public override void Apply(Drawable d) + { + base.Apply(d); + ((BaseComboCounter)d).DisplayedCount = CurrentValue; + } + } + + public void Set(ulong value) + { + if (value == 0) + Roll(); + else + Count = value; + } + } +} diff --git a/osu.Game/Modes/UI/ComboCounter.cs b/osu.Game/Modes/UI/ComboCounter.cs index a549246011..7724b44940 100644 --- a/osu.Game/Modes/UI/ComboCounter.cs +++ b/osu.Game/Modes/UI/ComboCounter.cs @@ -1,267 +1,140 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Transforms; -using osu.Framework.MathUtils; -using osu.Game.Graphics.Sprites; +using OpenTK; namespace osu.Game.Modes.UI { - public abstract class ComboCounter : Container + /// + /// Uses the 'x' symbol and has a pop-out effect while rolling over. + /// + public class ComboCounter : BaseComboCounter { - public bool IsRolling - { - get; protected set; - } + protected uint ScheduledPopOutCurrentId; - protected SpriteText PopOutCount; + protected virtual float PopOutSmallScale => 1.1f; + protected virtual bool CanPopOutWhileRolling => false; - protected virtual double PopOutDuration => 150; - protected virtual float PopOutScale => 2.0f; - protected virtual EasingTypes PopOutEasing => EasingTypes.None; - protected virtual float PopOutInitialAlpha => 0.75f; - - protected virtual double FadeOutDuration => 100; - - /// - /// Duration in milliseconds for the counter roll-up animation for each element. - /// - protected virtual double RollingDuration => 20; - - /// - /// Easing for the counter rollover animation. - /// - protected EasingTypes RollingEasing => EasingTypes.None; - - private ulong displayedCount; - - /// - /// Value shown at the current moment. - /// - public virtual ulong DisplayedCount - { - get - { - return displayedCount; - } - protected set - { - if (displayedCount.Equals(value)) - return; - updateDisplayedCount(displayedCount, value, IsRolling); - } - } - - private ulong count; - - /// - /// Actual value of counter. - /// - public virtual ulong Count - { - get - { - return count; - } - set - { - updateCount(value); - } - } - - public void Increment(ulong amount = 1) - { - Count = Count + amount; - } - - protected SpriteText DisplayedCountSpriteText; - - private float textSize; - public float TextSize - { - get { return textSize; } - set - { - textSize = value; - DisplayedCountSpriteText.TextSize = TextSize; - PopOutCount.TextSize = TextSize; - } - } - - /// - /// Base of all combo counters. - /// - protected ComboCounter() - { - AutoSizeAxes = Axes.Both; - - Children = new Drawable[] - { - DisplayedCountSpriteText = new OsuSpriteText - { - Alpha = 0, - }, - PopOutCount = new OsuSpriteText - { - Alpha = 0, - Margin = new MarginPadding(0.05f), - } - }; - - TextSize = 80; - } + public new Vector2 PopOutScale = new Vector2(1.6f); protected override void LoadComplete() { base.LoadComplete(); - DisplayedCountSpriteText.Text = FormatCount(Count); - DisplayedCountSpriteText.Anchor = Anchor; - DisplayedCountSpriteText.Origin = Origin; - - StopRolling(); + PopOutCount.Origin = Origin; + PopOutCount.Anchor = Anchor; } - /// - /// Stops rollover animation, forcing the displayed count to be the actual count. - /// - public void StopRolling() + protected override string FormatCount(ulong count) { - updateCount(Count); + return $@"{count}x"; } - /// - /// Animates roll-up/roll-back to an specific value. - /// - /// Target value. - public virtual void Roll(ulong newValue = 0) + protected virtual void TransformPopOut(ulong newValue) { - updateCount(newValue, true); + PopOutCount.Text = FormatCount(newValue); + + PopOutCount.ScaleTo(PopOutScale); + PopOutCount.FadeTo(PopOutInitialAlpha); + PopOutCount.MoveTo(Vector2.Zero); + + PopOutCount.ScaleTo(1, PopOutDuration, PopOutEasing); + PopOutCount.FadeOut(PopOutDuration, PopOutEasing); + PopOutCount.MoveTo(DisplayedCountSpriteText.Position, PopOutDuration, PopOutEasing); } - /// - /// Resets count to default value. - /// - public virtual void ResetCount() + protected virtual void TransformPopOutRolling(ulong newValue) { - updateCount(0); + TransformPopOut(newValue); + TransformPopOutSmall(newValue); } - protected virtual string FormatCount(ulong count) + protected virtual void TransformNoPopOut(ulong newValue) { - return count.ToString(); + DisplayedCountSpriteText.Text = FormatCount(newValue); + DisplayedCountSpriteText.ScaleTo(1); } - protected abstract void OnDisplayedCountRolling(ulong currentValue, ulong newValue); - protected abstract void OnDisplayedCountIncrement(ulong newValue); - protected abstract void OnDisplayedCountChange(ulong newValue); - - protected virtual void OnCountRolling(ulong currentValue, ulong newValue) + protected virtual void TransformPopOutSmall(ulong newValue) { - transformRoll(new TransformComboRoll(), currentValue, newValue); + DisplayedCountSpriteText.Text = FormatCount(newValue); + DisplayedCountSpriteText.ScaleTo(PopOutSmallScale); + DisplayedCountSpriteText.ScaleTo(1, PopOutDuration, PopOutEasing); } - protected virtual void OnCountIncrement(ulong currentValue, ulong newValue) { - DisplayedCount = newValue; - } - - protected virtual void OnCountChange(ulong currentValue, ulong newValue) { - DisplayedCount = newValue; - } - - private double getProportionalDuration(ulong currentValue, ulong newValue) + protected virtual void ScheduledPopOutSmall(uint id) { - double difference = currentValue > newValue ? currentValue - newValue : newValue - currentValue; - return difference * RollingDuration; - } - - private void updateDisplayedCount(ulong currentValue, ulong newValue, bool rolling) - { - displayedCount = newValue; - if (rolling) - OnDisplayedCountRolling(currentValue, newValue); - else if (currentValue + 1 == newValue) - OnDisplayedCountIncrement(newValue); - else - OnDisplayedCountChange(newValue); - } - - private void updateCount(ulong value, bool rolling = false) - { - ulong prevCount = count; - count = value; - - if (!IsLoaded) + // Too late; scheduled task invalidated + if (id != ScheduledPopOutCurrentId) return; - if (!rolling) - { - Flush(false, typeof(TransformComboRoll)); - IsRolling = false; - DisplayedCount = prevCount; + DisplayedCount++; + } - if (prevCount + 1 == count) - OnCountIncrement(prevCount, count); - else - OnCountChange(prevCount, count); - } + protected override void OnCountRolling(ulong currentValue, ulong newValue) + { + ScheduledPopOutCurrentId++; + + // Hides displayed count if was increasing from 0 to 1 but didn't finish + if (currentValue == 0 && newValue == 0) + DisplayedCountSpriteText.FadeOut(FadeOutDuration); + + base.OnCountRolling(currentValue, newValue); + } + + protected override void OnCountIncrement(ulong currentValue, ulong newValue) + { + ScheduledPopOutCurrentId++; + + if (DisplayedCount < currentValue) + DisplayedCount++; + + DisplayedCountSpriteText.Show(); + + TransformPopOut(newValue); + + uint newTaskId = ScheduledPopOutCurrentId; + Scheduler.AddDelayed(delegate + { + ScheduledPopOutSmall(newTaskId); + }, PopOutDuration); + } + + protected override void OnCountChange(ulong currentValue, ulong newValue) + { + ScheduledPopOutCurrentId++; + + if (newValue == 0) + DisplayedCountSpriteText.FadeOut(); + + base.OnCountChange(currentValue, newValue); + } + + protected override void OnDisplayedCountRolling(ulong currentValue, ulong newValue) + { + if (newValue == 0) + DisplayedCountSpriteText.FadeOut(FadeOutDuration); else - { - OnCountRolling(displayedCount, count); - IsRolling = true; - } - } + DisplayedCountSpriteText.Show(); - private void transformRoll(TransformComboRoll transform, ulong currentValue, ulong newValue) - { - Flush(false, typeof(TransformComboRoll)); - - if (RollingDuration < 1) - { - DisplayedCount = Count; - return; - } - - transform.StartTime = Time.Current; - transform.EndTime = Time.Current + getProportionalDuration(currentValue, newValue); - transform.StartValue = currentValue; - transform.EndValue = newValue; - transform.Easing = RollingEasing; - - Transforms.Add(transform); - } - - protected class TransformComboRoll : Transform - { - protected override ulong CurrentValue - { - get - { - double time = Time?.Current ?? 0; - if (time < StartTime) return StartValue; - if (time >= EndTime) return EndValue; - - return (ulong)Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); - } - } - - public override void Apply(Drawable d) - { - base.Apply(d); - ((ComboCounter)d).DisplayedCount = CurrentValue; - } - } - - public void Set(ulong value) - { - if (value == 0) - Roll(); + if (CanPopOutWhileRolling) + TransformPopOutRolling(newValue); else - Count = value; + TransformNoPopOut(newValue); + } + + protected override void OnDisplayedCountChange(ulong newValue) + { + DisplayedCountSpriteText.FadeTo(newValue == 0 ? 0 : 1); + + TransformNoPopOut(newValue); + } + + protected override void OnDisplayedCountIncrement(ulong newValue) + { + DisplayedCountSpriteText.Show(); + + TransformPopOutSmall(newValue); } } } diff --git a/osu.Game/Modes/UI/ScoreOverlay.cs b/osu.Game/Modes/UI/HUDOverlay.cs similarity index 87% rename from osu.Game/Modes/UI/ScoreOverlay.cs rename to osu.Game/Modes/UI/HUDOverlay.cs index 09f34d4c2e..dc8ea5103c 100644 --- a/osu.Game/Modes/UI/ScoreOverlay.cs +++ b/osu.Game/Modes/UI/HUDOverlay.cs @@ -1,24 +1,24 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Modes.Objects; -using OpenTK; -using osu.Framework.Graphics.Primitives; using osu.Game.Screens.Play; -using osu.Framework.Allocation; -using osu.Game.Configuration; -using osu.Framework.Configuration; +using System; namespace osu.Game.Modes.UI { - public abstract class ScoreOverlay : Container + internal abstract class HUDOverlay : Container { public KeyCounterCollection KeyCounter; - public ComboCounter ComboCounter; + public BaseComboCounter ComboCounter; public ScoreCounter ScoreCounter; public PercentageCounter AccuracyCounter; public HealthDisplay HealthDisplay; @@ -26,8 +26,8 @@ namespace osu.Game.Modes.UI private Bindable showKeyCounter; - protected abstract KeyCounterCollection CreateKeyCounter(); - protected abstract ComboCounter CreateComboCounter(); + protected abstract KeyCounterCollection CreateKeyCounter(KeyCounter[] keyCounters); + protected abstract BaseComboCounter CreateComboCounter(); protected abstract PercentageCounter CreateAccuracyCounter(); protected abstract ScoreCounter CreateScoreCounter(); protected virtual HealthDisplay CreateHealthDisplay() => new HealthDisplay @@ -50,12 +50,13 @@ namespace osu.Game.Modes.UI AccuracyCounter?.Set(AccuracyCounter.Count - 0.01f); } - protected ScoreOverlay() + protected HUDOverlay(Ruleset ruleset) { RelativeSizeAxes = Axes.Both; - Children = new Drawable[] { - KeyCounter = CreateKeyCounter(), + Children = new Drawable[] + { + KeyCounter = CreateKeyCounter(ruleset.GameplayKeys), ComboCounter = CreateComboCounter(), ScoreCounter = CreateScoreCounter(), AccuracyCounter = CreateAccuracyCounter(), diff --git a/osu.Game.Modes.Osu/UI/OsuScoreOverlay.cs b/osu.Game/Modes/UI/StandardHUDOverlay.cs similarity index 69% rename from osu.Game.Modes.Osu/UI/OsuScoreOverlay.cs rename to osu.Game/Modes/UI/StandardHUDOverlay.cs index d91a751c26..09c53632a5 100644 --- a/osu.Game.Modes.Osu/UI/OsuScoreOverlay.cs +++ b/osu.Game/Modes/UI/StandardHUDOverlay.cs @@ -1,26 +1,21 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; -using osu.Game.Modes.UI; + using OpenTK; -using OpenTK.Input; +using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; +using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Play; -namespace osu.Game.Modes.Osu.UI +namespace osu.Game.Modes.UI { - public class OsuScoreOverlay : ScoreOverlay + internal class StandardHUDOverlay : HUDOverlay { - protected override ScoreCounter CreateScoreCounter() => new ScoreCounter(6) + public StandardHUDOverlay(Ruleset ruleset) + : base(ruleset) { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - TextSize = 40, - Position = new Vector2(0, 30), - Margin = new MarginPadding { Right = 5 }, - }; + } protected override PercentageCounter CreateAccuracyCounter() => new PercentageCounter { @@ -31,26 +26,29 @@ namespace osu.Game.Modes.Osu.UI Margin = new MarginPadding { Right = 5 }, }; - protected override ComboCounter CreateComboCounter() => new OsuComboCounter + protected override BaseComboCounter CreateComboCounter() => new ComboCounter { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, }; - protected override KeyCounterCollection CreateKeyCounter() => new KeyCounterCollection + protected override KeyCounterCollection CreateKeyCounter(KeyCounter[] keyCounters) => new KeyCounterCollection { IsCounting = true, FadeTime = 50, Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, Margin = new MarginPadding(10), - Children = new KeyCounter[] - { - new KeyCounterKeyboard(Key.Z), - new KeyCounterKeyboard(Key.X), - new KeyCounterMouse(MouseButton.Left), - new KeyCounterMouse(MouseButton.Right), - } + Children = keyCounters + }; + + protected override ScoreCounter CreateScoreCounter() => new ScoreCounter(6) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + TextSize = 40, + Position = new Vector2(0, 30), + Margin = new MarginPadding { Right = 5 }, }; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index cb494ef79f..3119fd5d74 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1,29 +1,29 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK; +using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; -using osu.Framework.Graphics; -using osu.Framework.Timing; -using osu.Game.Database; -using osu.Game.Modes; -using osu.Game.Screens.Backgrounds; -using OpenTK; -using osu.Framework.Screens; -using osu.Game.Modes.UI; -using osu.Game.Screens.Ranking; -using osu.Game.Configuration; using osu.Framework.Configuration; -using System; -using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; -using OpenTK.Graphics; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; using osu.Framework.Input; using osu.Framework.Logging; +using osu.Framework.Screens; +using osu.Framework.Timing; +using osu.Game.Configuration; +using osu.Game.Database; using osu.Game.Input.Handlers; +using osu.Game.Modes; +using osu.Game.Modes.UI; +using osu.Game.Screens.Backgrounds; +using osu.Game.Screens.Ranking; +using System; +using System.Linq; namespace osu.Game.Screens.Play { @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play private Bindable dimLevel; private SkipButton skipButton; - private ScoreOverlay scoreOverlay; + private HUDOverlay hudOverlay; private PauseOverlay pauseOverlay; [BackgroundDependencyLoader] @@ -112,8 +112,8 @@ namespace osu.Game.Screens.Play ruleset = Ruleset.GetRuleset(Beatmap.PlayMode); - scoreOverlay = ruleset.CreateScoreOverlay(); - scoreOverlay.BindProcessor(scoreProcessor = ruleset.CreateScoreProcessor(beatmap.HitObjects.Count)); + hudOverlay = new StandardHUDOverlay(ruleset); + hudOverlay.BindProcessor(scoreProcessor = ruleset.CreateScoreProcessor(beatmap.HitObjects.Count)); pauseOverlay = new PauseOverlay { @@ -135,7 +135,7 @@ namespace osu.Game.Screens.Play hitRenderer.InputManager.ReplayInputHandler = ReplayInputHandler; } - scoreOverlay.BindHitRenderer(hitRenderer); + hudOverlay.BindHitRenderer(hitRenderer); //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation) hitRenderer.OnJudgement += scoreProcessor.AddJudgement; @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Play }, } }, - scoreOverlay, + hudOverlay, pauseOverlay }; } @@ -196,7 +196,7 @@ namespace osu.Game.Screens.Play if (canPause || force) { lastPauseActionTime = Time.Current; - scoreOverlay.KeyCounter.IsCounting = false; + hudOverlay.KeyCounter.IsCounting = false; pauseOverlay.Retries = RestartCount; pauseOverlay.Show(); sourceClock.Stop(); @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Play public void Resume() { lastPauseActionTime = Time.Current; - scoreOverlay.KeyCounter.IsCounting = true; + hudOverlay.KeyCounter.IsCounting = true; pauseOverlay.Hide(); sourceClock.Start(); IsPaused = false; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 61c31a6cee..d0f2d6f042 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -167,6 +167,8 @@ + + @@ -181,9 +183,9 @@ - + - +