From 4f34d42b3372aea76d29a3a09e771fac1b6f2af7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Dec 2018 21:11:35 +0900 Subject: [PATCH] Major code refactors --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 222 +++++++++++++++- .../Objects/Drawables/DrawableOsuBlinds.cs | 243 ------------------ .../Drawables/Pieces/ModBlindsPanelSprite.cs | 26 -- 3 files changed, 217 insertions(+), 274 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs delete mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index f216ae5814..4078dce643 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -2,38 +2,250 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { public class OsuModBlinds : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor { public override string Name => "Blinds"; + public override string Description => "Play with blinds on your screen."; public override string Acronym => "BL"; + public override FontAwesome Icon => FontAwesome.fa_adjust; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Play with blinds on your screen."; + public override bool Ranked => false; public override double ScoreMultiplier => 1.12; - private DrawableOsuBlinds flashlight; + private DrawableOsuBlinds blinds; public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { bool hasEasy = rulesetContainer.ActiveMods.Any(m => m is ModEasy); bool hasHardrock = rulesetContainer.ActiveMods.Any(m => m is ModHardRock); - rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); + rulesetContainer.Overlays.Add(blinds = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); } public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { - scoreProcessor.Health.ValueChanged += val => { flashlight.AnimateTarget((float)val); }; + scoreProcessor.Health.ValueChanged += val => { blinds.AnimateClosedness((float)val); }; + } + + /// + /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. + /// + public class DrawableOsuBlinds : Container + { + /// + /// Black background boxes behind blind panel textures. + /// + private Box blackBoxLeft, blackBoxRight; + + private Drawable panelLeft, panelRight, bgPanelLeft, bgPanelRight; + + private readonly Beatmap beatmap; + + /// + /// Value between 0 and 1 setting a maximum "closedness" for the blinds. + /// Useful for animating how far the blinds can be opened while keeping them at the original position if they are wider open than this. + /// + private const float target_clamp = 1; + + private readonly float targetBreakMultiplier = 0; + private readonly float easing = 1; + + private const float black_depth = 10; + private const float bg_panel_depth = 8; + private const float fg_panel_depth = 4; + + private readonly CompositeDrawable restrictTo; + private readonly bool modEasy, modHardrock; + + /// + /// + /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. + /// + /// + /// -1 would mean the blinds always cover the whole screen no matter health. + /// 0 would mean the blinds will only ever be on the edge of the playfield on 0% health. + /// 1 would mean the blinds are fully outside the playfield on 50% health. + /// Infinity would mean the blinds are always outside the playfield except on 100% health. + /// + /// + private const float leniency = 0.1f; + + public DrawableOsuBlinds(CompositeDrawable restrictTo, bool hasEasy, bool hasHardrock, Beatmap beatmap) + { + this.restrictTo = restrictTo; + this.beatmap = beatmap; + + modEasy = hasEasy; + modHardrock = hasHardrock; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + Children = new[] + { + blackBoxLeft = new Box + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 0, + Height = 1, + Depth = black_depth + }, + blackBoxRight = new Box + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 0, + Height = 1, + Depth = black_depth + }, + bgPanelLeft = new ModBlindsPanel + { + Origin = Anchor.TopRight, + Colour = Color4.Gray, + Depth = bg_panel_depth + 1 + }, + panelLeft = new ModBlindsPanel + { + Origin = Anchor.TopRight, + Depth = bg_panel_depth + }, + bgPanelRight = new ModBlindsPanel + { + Origin = Anchor.TopLeft, + Colour = Color4.Gray, + Depth = fg_panel_depth + 1 + }, + panelRight = new ModBlindsPanel + { + Origin = Anchor.TopLeft, + Depth = fg_panel_depth + }, + }; + } + + private float applyGap(float value) + { + const float easy_multiplier = 0.95f; + const float hardrock_multiplier = 1.1f; + + float multiplier = 1; + if (modEasy) + { + multiplier = easy_multiplier; + // TODO: include OD/CS + } + else if (modHardrock) + { + multiplier = hardrock_multiplier; + // TODO: include OD/CS + } + + return MathHelper.Clamp(value * multiplier, 0, target_clamp) * targetBreakMultiplier; + } + + private static float applyAdjustmentCurve(float value) + { + // lagrange polinominal for (0,0) (0.5,0.35) (1,1) should make a good curve + return 0.6f * value * value + 0.4f * value; + } + + protected override void Update() + { + float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; + float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; + + float rawWidth = end - start; + + start -= rawWidth * leniency * 0.5f; + end += rawWidth * leniency * 0.5f; + + float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); + + // different values in case the playfield ever moves from center to somewhere else. + blackBoxLeft.Width = start + width; + blackBoxRight.Width = DrawWidth - end + width; + + panelLeft.X = start + width; + panelRight.X = end - width; + bgPanelLeft.X = start; + bgPanelRight.X = end; + } + + protected override void LoadComplete() + { + const float break_open_early = 500; + const float break_close_late = 250; + + base.LoadComplete(); + + var firstObj = beatmap.HitObjects[0]; + var startDelay = firstObj.StartTime - firstObj.TimePreempt; + + using (BeginAbsoluteSequence(startDelay + break_close_late, true)) + leaveBreak(); + + foreach (var breakInfo in beatmap.Breaks) + { + if (breakInfo.HasEffect) + { + using (BeginAbsoluteSequence(breakInfo.StartTime - break_open_early, true)) + { + enterBreak(); + using (BeginDelayedSequence(breakInfo.Duration + break_open_early + break_close_late, true)) + leaveBreak(); + } + } + } + } + + private void enterBreak() => this.TransformTo(nameof(targetBreakMultiplier), 0f, 1000, Easing.OutSine); + + private void leaveBreak() => this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); + + /// + /// 0 is open, 1 is closed. + /// + public void AnimateClosedness(float value) => this.TransformTo(nameof(easing), value, 200, Easing.OutQuint); + + public class ModBlindsPanel : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + InternalChild = new SkinnableDrawable("Play/osu/blinds-panel", s => new Sprite { Texture = textures.Get("Play/osu/blinds-panel") }) + { + RelativeSizeAxes = Axes.Both, + }; + } + } } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs deleted file mode 100644 index d06f1250d8..0000000000 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Game.Beatmaps; -using osu.Game.Skinning; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Rulesets.Osu.Objects.Drawables -{ - /// - /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. - /// - public class DrawableOsuBlinds : Container - { - /// - /// Black background boxes behind blind panel textures. - /// - private Box blackBoxLeft, blackBoxRight; - private Sprite panelLeft, panelRight; - private Sprite bgPanelLeft, bgPanelRight; - - private readonly Beatmap beatmap; - - private ISkinSource skin; - - private float targetClamp = 1; - private readonly float targetBreakMultiplier = 0; - private float target = 1; - private readonly float easing = 1; - - private const float black_depth = 10; - private const float bg_panel_depth = 8; - private const float fg_panel_depth = 4; - - private readonly CompositeDrawable restrictTo; - private readonly bool modEasy, modHardrock; - - /// - /// - /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. - /// - /// - /// -1 would mean the blinds always cover the whole screen no matter health. - /// 0 would mean the blinds will only ever be on the edge of the playfield on 0% health. - /// 1 would mean the blinds are fully outside the playfield on 50% health. - /// Infinity would mean the blinds are always outside the playfield except on 100% health. - /// - /// - private const float leniency = 0.1f; - - public DrawableOsuBlinds(CompositeDrawable restrictTo, bool hasEasy, bool hasHardrock, Beatmap beatmap) - { - this.restrictTo = restrictTo; - this.beatmap = beatmap; - - modEasy = hasEasy; - modHardrock = hasHardrock; - } - - [BackgroundDependencyLoader] - private void load(ISkinSource skin, TextureStore textures) - { - RelativeSizeAxes = Axes.Both; - Width = 1; - Height = 1; - - Add(blackBoxLeft = new Box - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Y, - Width = 0, - Height = 1, - Depth = black_depth - }); - Add(blackBoxRight = new Box - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Y, - Width = 0, - Height = 1, - Depth = black_depth - }); - - Add(bgPanelLeft = new ModBlindsPanelSprite { - Origin = Anchor.TopRight, - Colour = Color4.Gray, - Depth = bg_panel_depth + 1 - }); - Add(panelLeft = new ModBlindsPanelSprite { - Origin = Anchor.TopRight, - Depth = bg_panel_depth - }); - - Add(bgPanelRight = new ModBlindsPanelSprite { - Origin = Anchor.TopLeft, - Colour = Color4.Gray, - Depth = fg_panel_depth + 1 - }); - Add(panelRight = new ModBlindsPanelSprite { - Origin = Anchor.TopLeft, - Depth = fg_panel_depth - }); - - this.skin = skin; - skin.SourceChanged += skinChanged; - PanelTexture = textures.Get("Play/osu/blinds-panel"); - } - - private void skinChanged() - { - PanelTexture = skin.GetTexture("Play/osu/blinds-panel"); - } - - private float applyGap(float value) - { - const float easy_multiplier = 0.95f; - const float hardrock_multiplier = 1.1f; - - float multiplier = 1; - if (modEasy) - { - multiplier = easy_multiplier; - // TODO: include OD/CS - } - else if (modHardrock) - { - multiplier = hardrock_multiplier; - // TODO: include OD/CS - } - - return MathHelper.Clamp(value * multiplier, 0, targetClamp) * targetBreakMultiplier; - } - - private static float applyAdjustmentCurve(float value) - { - // lagrange polinominal for (0,0) (0.5,0.35) (1,1) should make a good curve - return 0.6f * value * value + 0.4f * value; - } - - protected override void Update() - { - float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; - float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; - float rawWidth = end - start; - start -= rawWidth * leniency * 0.5f; - end += rawWidth * leniency * 0.5f; - - float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); - // different values in case the playfield ever moves from center to somewhere else. - blackBoxLeft.Width = start + width; - blackBoxRight.Width = DrawWidth - end + width; - - panelLeft.X = start + width; - panelRight.X = end - width; - bgPanelLeft.X = start; - bgPanelRight.X = end; - } - - protected override void LoadComplete() - { - const float break_open_early = 500; - const float break_close_late = 250; - - base.LoadComplete(); - - var firstObj = beatmap.HitObjects[0]; - var startDelay = firstObj.StartTime - firstObj.TimePreempt; - - using (BeginAbsoluteSequence(startDelay + break_close_late, true)) - LeaveBreak(); - - foreach (var breakInfo in beatmap.Breaks) - { - if (breakInfo.HasEffect) - { - using (BeginAbsoluteSequence(breakInfo.StartTime - break_open_early, true)) - { - EnterBreak(); - using (BeginDelayedSequence(breakInfo.Duration + break_open_early + break_close_late, true)) - LeaveBreak(); - } - } - } - } - - public void EnterBreak() - { - this.TransformTo(nameof(targetBreakMultiplier), 0f, 1000, Easing.OutSine); - } - - public void LeaveBreak() - { - this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); - } - - /// - /// Value between 0 and 1 setting a maximum "closedness" for the blinds. - /// Useful for animating how far the blinds can be opened while keeping them at the original position if they are wider open than this. - /// - public float TargetClamp - { - get => targetClamp; - set => targetClamp = value; - } - - /// - /// Health between 0 and 1 for the blinds to base the width on. Will get animated for 200ms using out-quintic easing. - /// - public void AnimateTarget(float value) - { - target = value; - this.TransformTo(nameof(easing), target, 200, Easing.OutQuint); - } - - public float Target - { - get => target; - } - - public Texture PanelTexture - { - set - { - panelLeft.Texture = value; - panelRight.Texture = value; - bgPanelLeft.Texture = value; - bgPanelRight.Texture = value; - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs deleted file mode 100644 index c6e2db1842..0000000000 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; - -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces -{ - public class ModBlindsPanelSprite : Sprite - { - public ModBlindsPanelSprite() - { - RelativeSizeAxes = Axes.None; - Anchor = Anchor.TopLeft; - } - - protected override void Update() - { - Height = Parent?.DrawHeight ?? 0; - if (Height == 0 || Texture == null) - Width = 0; - else - Width = Texture.Width / (float)Texture.Height * Height; - } - } -}