From 1b2c07e1423ef313b6e5228f347641176255f74e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 May 2022 19:25:51 +0900 Subject: [PATCH 01/11] Extend lifetime of `OsuSelectionBlueprint` to allow for lingering display --- .../Edit/Blueprints/OsuSelectionBlueprint.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index 994c5cebeb..dbf53ac9a6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -1,19 +1,27 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Screens.Edit; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { public abstract class OsuSelectionBlueprint : HitObjectSelectionBlueprint where T : OsuHitObject { + [Resolved] + private EditorClock editorClock { get; set; } + protected new DrawableOsuHitObject DrawableObject => (DrawableOsuHitObject)base.DrawableObject; protected override bool AlwaysShowWhenSelected => true; + protected override bool ShouldBeAlive => base.ShouldBeAlive || editorClock.CurrentTime - Item.GetEndTime() < DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION; + protected OsuSelectionBlueprint(T hitObject) : base(hitObject) { From c63e65c677b5103e4fc18e11cef67bb32ad497a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 May 2022 19:26:13 +0900 Subject: [PATCH 02/11] Don't hide `SelectionBlueprint`s themselves, only their children --- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 12ab89f79e..5e5bc9036d 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -89,16 +89,12 @@ namespace osu.Game.Rulesets.Edit // set the body piece's alpha directly to avoid arbitrarily rendering frame buffers etc. of children. foreach (var d in InternalChildren) d.Hide(); - - Hide(); } protected virtual void OnSelected() { foreach (var d in InternalChildren) d.Show(); - - Show(); } // When not selected, input is only required for the blueprint itself to receive IsHovering From be3d4c9bf5a52e5dfcdb78d834f068389db47035 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 May 2022 19:26:34 +0900 Subject: [PATCH 03/11] Add circle overlap marker, bringing back stable-like visibility of circles in the past --- .../Components/HitCircleOverlapMarker.cs | 87 +++++++++++++++++++ .../HitCircles/HitCircleSelectionBlueprint.cs | 9 +- .../Blueprints/Sliders/SliderCircleOverlay.cs | 23 ++++- 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs new file mode 100644 index 0000000000..34e5e120f1 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -0,0 +1,87 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Skinning.Default; +using osu.Game.Screens.Edit; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components +{ + public class HitCircleOverlapMarker : BlueprintPiece + { + private readonly Circle circle; + private readonly RingPiece ring; + + [Resolved] + private EditorClock editorClock { get; set; } + + public HitCircleOverlapMarker() + { + Origin = Anchor.Centre; + + Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); + + InternalChildren = new Drawable[] + { + circle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + ring = new RingPiece + { + BorderThickness = 4, + } + }; + } + + [Resolved] + private ISkinSource skin { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + circle.BorderColour = colours.Yellow; + } + + public override void UpdateFrom(HitCircle hitObject) + { + base.UpdateFrom(hitObject); + + Scale = new Vector2(hitObject.Scale); + + if ((hitObject is IHasComboInformation combo)) + ring.BorderColour = combo.GetComboColour(skin); + + bool hasReachedObject = editorClock.CurrentTime >= hitObject.StartTime; + float interpolation = Interpolation.ValueAt(editorClock.CurrentTime, 0, 1f, hitObject.StartTime, hitObject.StartTime + DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION, Easing.In); + float interpolation2 = MathHelper.Clamp(Interpolation.ValueAt(editorClock.CurrentTime, 0, 1f, hitObject.StartTime, hitObject.StartTime + DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION / 2, Easing.OutQuint), 0, 1); + float interpolation3 = Interpolation.ValueAt(editorClock.CurrentTime, 0, 1f, hitObject.StartTime, hitObject.StartTime + DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION); + + if (hasReachedObject) + { + circle.Scale = new Vector2(1 - 0.05f * interpolation3); + ring.Scale = new Vector2(1 + 0.1f * interpolation2); + Alpha = 0.9f * (1 - (interpolation)); + } + else + Alpha = 0; + } + + public override void Hide() + { + // intentional no op so we are not hidden when not selected. + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index b21a3e038e..3f9cfe21d4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; @@ -14,11 +15,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles protected new DrawableHitCircle DrawableObject => (DrawableHitCircle)base.DrawableObject; protected readonly HitCirclePiece CirclePiece; + private readonly HitCircleOverlapMarker marker; public HitCircleSelectionBlueprint(HitCircle circle) : base(circle) { - InternalChild = CirclePiece = new HitCirclePiece(); + InternalChildren = new Drawable[] + { + marker = new HitCircleOverlapMarker(), + CirclePiece = new HitCirclePiece(), + }; } protected override void Update() @@ -26,6 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles base.Update(); CirclePiece.UpdateFrom(HitObject); + marker.UpdateFrom(HitObject); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.HitArea.ReceivePositionalInputAt(screenSpacePos); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs index 241ff70a18..d31d2aed97 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; @@ -13,20 +14,38 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private readonly Slider slider; private readonly SliderPosition position; + private readonly HitCircleOverlapMarker marker; public SliderCircleOverlay(Slider slider, SliderPosition position) { this.slider = slider; this.position = position; - InternalChild = CirclePiece = new HitCirclePiece(); + InternalChildren = new Drawable[] + { + marker = new HitCircleOverlapMarker(), + CirclePiece = new HitCirclePiece(), + }; } protected override void Update() { base.Update(); - CirclePiece.UpdateFrom(position == SliderPosition.Start ? (HitCircle)slider.HeadCircle : slider.TailCircle); + var circle = position == SliderPosition.Start ? (HitCircle)slider.HeadCircle : slider.TailCircle; + + CirclePiece.UpdateFrom(circle); + marker.UpdateFrom(circle); + } + + public override void Hide() + { + CirclePiece.Hide(); + } + + public override void Show() + { + CirclePiece.Show(); } } } From f22ff4e087d5567831e6c2388bb0b031080728d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 May 2022 19:28:56 +0900 Subject: [PATCH 04/11] Remove editor animation toggling (replaced by overlap markers) --- .../Editor/TestSceneOsuEditorHitAnimations.cs | 114 ------------------ .../Edit/DrawableOsuEditorRuleset.cs | 76 ------------ osu.Game/Configuration/OsuConfigManager.cs | 2 - osu.Game/Screens/Edit/Editor.cs | 1 - 4 files changed, 193 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorHitAnimations.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorHitAnimations.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorHitAnimations.cs deleted file mode 100644 index 7ffa2c1f94..0000000000 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorHitAnimations.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Transforms; -using osu.Framework.Testing; -using osu.Framework.Utils; -using osu.Game.Configuration; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; - -namespace osu.Game.Rulesets.Osu.Tests.Editor -{ - [TestFixture] - public class TestSceneOsuEditorHitAnimations : TestSceneOsuEditor - { - [Resolved] - private OsuConfigManager config { get; set; } - - [Test] - public void TestHitCircleAnimationDisable() - { - HitCircle hitCircle = null; - DrawableHitCircle drawableHitCircle = null; - - AddStep("retrieve first hit circle", () => hitCircle = getHitCircle(0)); - toggleAnimations(true); - seekSmoothlyTo(() => hitCircle.StartTime + 10); - - AddStep("retrieve drawable", () => drawableHitCircle = (DrawableHitCircle)getDrawableObjectFor(hitCircle)); - assertFutureTransforms(() => drawableHitCircle.CirclePiece, true); - - AddStep("retrieve second hit circle", () => hitCircle = getHitCircle(1)); - toggleAnimations(false); - seekSmoothlyTo(() => hitCircle.StartTime + 10); - - AddStep("retrieve drawable", () => drawableHitCircle = (DrawableHitCircle)getDrawableObjectFor(hitCircle)); - assertFutureTransforms(() => drawableHitCircle.CirclePiece, false); - AddAssert("hit circle has longer fade-out applied", () => - { - var alphaTransform = drawableHitCircle.Transforms.Last(t => t.TargetMember == nameof(Alpha)); - return alphaTransform.EndTime - alphaTransform.StartTime == DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION; - }); - } - - [Test] - public void TestSliderAnimationDisable() - { - Slider slider = null; - DrawableSlider drawableSlider = null; - DrawableSliderRepeat sliderRepeat = null; - - AddStep("retrieve first slider with repeats", () => slider = getSliderWithRepeats(0)); - toggleAnimations(true); - seekSmoothlyTo(() => slider.StartTime + slider.SpanDuration + 10); - - retrieveDrawables(); - assertFutureTransforms(() => sliderRepeat, true); - - AddStep("retrieve second slider with repeats", () => slider = getSliderWithRepeats(1)); - toggleAnimations(false); - seekSmoothlyTo(() => slider.StartTime + slider.SpanDuration + 10); - - retrieveDrawables(); - assertFutureTransforms(() => sliderRepeat.Arrow, false); - seekSmoothlyTo(() => slider.GetEndTime()); - AddAssert("slider has longer fade-out applied", () => - { - var alphaTransform = drawableSlider.Transforms.Last(t => t.TargetMember == nameof(Alpha)); - return alphaTransform.EndTime - alphaTransform.StartTime == DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION; - }); - - void retrieveDrawables() => - AddStep("retrieve drawables", () => - { - drawableSlider = (DrawableSlider)getDrawableObjectFor(slider); - sliderRepeat = (DrawableSliderRepeat)getDrawableObjectFor(slider.NestedHitObjects.OfType().First()); - }); - } - - private HitCircle getHitCircle(int index) - => EditorBeatmap.HitObjects.OfType().ElementAt(index); - - private Slider getSliderWithRepeats(int index) - => EditorBeatmap.HitObjects.OfType().Where(s => s.RepeatCount >= 1).ElementAt(index); - - private DrawableHitObject getDrawableObjectFor(HitObject hitObject) - => this.ChildrenOfType().Single(ho => ho.HitObject == hitObject); - - private IEnumerable getTransformsRecursively(Drawable drawable) - => drawable.ChildrenOfType().SelectMany(d => d.Transforms); - - private void toggleAnimations(bool enabled) - => AddStep($"toggle animations {(enabled ? "on" : "off")}", () => config.SetValue(OsuSetting.EditorHitAnimations, enabled)); - - private void seekSmoothlyTo(Func targetTime) - { - AddStep("seek smoothly", () => EditorClock.SeekSmoothlyTo(targetTime.Invoke())); - AddUntilStep("wait for seek", () => Precision.AlmostEquals(targetTime.Invoke(), EditorClock.CurrentTime)); - } - - private void assertFutureTransforms(Func getDrawable, bool hasFutureTransforms) - => AddAssert($"object {(hasFutureTransforms ? "has" : "has no")} future transforms", - () => getTransformsRecursively(getDrawable()).Any(t => t.EndTime >= EditorClock.CurrentTime) == hasFutureTransforms); - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs index c89527d8bd..f542c88d89 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs @@ -2,16 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; using osuTK; @@ -37,80 +29,12 @@ namespace osu.Game.Rulesets.Osu.Edit private class OsuEditorPlayfield : OsuPlayfield { - private Bindable hitAnimations; - protected override GameplayCursorContainer CreateCursor() => null; public OsuEditorPlayfield() { HitPolicy = new AnyOrderHitPolicy(); } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - hitAnimations = config.GetBindable(OsuSetting.EditorHitAnimations); - } - - protected override void OnNewDrawableHitObject(DrawableHitObject d) - { - d.ApplyCustomUpdateState += updateState; - } - - private void updateState(DrawableHitObject hitObject, ArmedState state) - { - if (state == ArmedState.Idle || hitAnimations.Value) - return; - - if (hitObject is DrawableHitCircle circle) - { - using (circle.BeginAbsoluteSequence(circle.HitStateUpdateTime)) - { - circle.ApproachCircle - .FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4) - .Expire(); - - circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); - } - } - - if (hitObject is IHasMainCirclePiece mainPieceContainer) - { - // clear any explode animation logic. - // this is scheduled after children to ensure that the clear happens after invocations of ApplyCustomUpdateState on the circle piece's nested skinnables. - ScheduleAfterChildren(() => - { - if (hitObject.HitObject == null) return; - - mainPieceContainer.CirclePiece.ApplyTransformsAt(hitObject.StateUpdateTime, true); - mainPieceContainer.CirclePiece.ClearTransformsAfter(hitObject.StateUpdateTime, true); - }); - } - - if (hitObject is DrawableSliderRepeat repeat) - { - repeat.Arrow.ApplyTransformsAt(hitObject.StateUpdateTime, true); - repeat.Arrow.ClearTransformsAfter(hitObject.StateUpdateTime, true); - } - - // adjust the visuals of top-level object types to make them stay on screen for longer than usual. - switch (hitObject) - { - case DrawableSlider _: - case DrawableHitCircle _: - // Get the existing fade out transform - var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); - - if (existing == null) - return; - - hitObject.RemoveTransform(existing); - - using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime)) - hitObject.FadeOut(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION).Expire(); - break; - } - } } } } diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 026a83cceb..20d555c16c 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -163,7 +163,6 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f); - SetDefault(OsuSetting.EditorHitAnimations, false); } public IDictionary GetLoggableState() => @@ -356,7 +355,6 @@ namespace osu.Game.Configuration GameplayDisableWinKey, SeasonalBackgroundMode, EditorWaveformOpacity, - EditorHitAnimations, DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 947c184009..75d2480a97 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -270,7 +270,6 @@ namespace osu.Game.Screens.Edit Items = new MenuItem[] { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), - new HitAnimationsMenuItem(config.GetBindable(OsuSetting.EditorHitAnimations)) } } } From 0c335592b3ed4eebd8428fa91dd4c90abb98010c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 May 2022 19:42:35 +0900 Subject: [PATCH 05/11] Tidy up interpolation and move `const` to new home --- .../Components/HitCircleOverlapMarker.cs | 23 +++++++++++++------ .../Edit/Blueprints/OsuSelectionBlueprint.cs | 3 ++- .../Edit/DrawableOsuEditorRuleset.cs | 6 ----- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index 34e5e120f1..579c9ef356 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -18,6 +18,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { public class HitCircleOverlapMarker : BlueprintPiece { + /// + /// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay. + /// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points. + /// + public const double FADE_OUT_EXTENSION = 700; + private readonly Circle circle; private readonly RingPiece ring; @@ -64,16 +70,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components if ((hitObject is IHasComboInformation combo)) ring.BorderColour = combo.GetComboColour(skin); - bool hasReachedObject = editorClock.CurrentTime >= hitObject.StartTime; - float interpolation = Interpolation.ValueAt(editorClock.CurrentTime, 0, 1f, hitObject.StartTime, hitObject.StartTime + DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION, Easing.In); - float interpolation2 = MathHelper.Clamp(Interpolation.ValueAt(editorClock.CurrentTime, 0, 1f, hitObject.StartTime, hitObject.StartTime + DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION / 2, Easing.OutQuint), 0, 1); - float interpolation3 = Interpolation.ValueAt(editorClock.CurrentTime, 0, 1f, hitObject.StartTime, hitObject.StartTime + DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION); + double editorTime = editorClock.CurrentTime; + double hitObjectTime = hitObject.StartTime; + bool hasReachedObject = editorTime >= hitObjectTime; if (hasReachedObject) { - circle.Scale = new Vector2(1 - 0.05f * interpolation3); - ring.Scale = new Vector2(1 + 0.1f * interpolation2); - Alpha = 0.9f * (1 - (interpolation)); + float alpha = Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION, Easing.In); + float circleScale = Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION); + float ringScale = MathHelper.Clamp(Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION / 2, Easing.OutQuint), 0, 1); + + circle.Scale = new Vector2(1 - 0.05f * circleScale); + ring.Scale = new Vector2(1 + 0.1f * ringScale); + Alpha = 0.9f * (1 - alpha); } else Alpha = 0; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index dbf53ac9a6..1d32e922ac 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Screens.Edit; @@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints protected override bool AlwaysShowWhenSelected => true; - protected override bool ShouldBeAlive => base.ShouldBeAlive || editorClock.CurrentTime - Item.GetEndTime() < DrawableOsuEditorRuleset.EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION; + protected override bool ShouldBeAlive => base.ShouldBeAlive || editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION; protected OsuSelectionBlueprint(T hitObject) : base(hitObject) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs index f542c88d89..516b34d807 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs @@ -12,12 +12,6 @@ namespace osu.Game.Rulesets.Osu.Edit { public class DrawableOsuEditorRuleset : DrawableOsuRuleset { - /// - /// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay. - /// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points. - /// - public const double EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION = 700; - public DrawableOsuEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { From 0318944b807d8c3a2aa75735f78f955ec3dab837 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 May 2022 23:37:29 +0900 Subject: [PATCH 06/11] Fix incorrect alive criteria causing clicking future objects to be too greedy --- osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index 1d32e922ac..2d0c6fe81d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -21,7 +21,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints protected override bool AlwaysShowWhenSelected => true; - protected override bool ShouldBeAlive => base.ShouldBeAlive || editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION; + protected override bool ShouldBeAlive => base.ShouldBeAlive + || (editorClock.CurrentTime >= Item.StartTime && editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION); protected OsuSelectionBlueprint(T hitObject) : base(hitObject) From 15291623180b570b3687f1e4ae3b2eda1875ad0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 May 2022 21:28:45 +0900 Subject: [PATCH 07/11] Remove circle scaling (apparently the fixed scale is required for spacing) --- .../Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index 579c9ef356..e00abadb7e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -77,10 +77,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components if (hasReachedObject) { float alpha = Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION, Easing.In); - float circleScale = Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION); float ringScale = MathHelper.Clamp(Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION / 2, Easing.OutQuint), 0, 1); - circle.Scale = new Vector2(1 - 0.05f * circleScale); ring.Scale = new Vector2(1 + 0.1f * ringScale); Alpha = 0.9f * (1 - alpha); } From 38b8baf0954a95cbf993144a5533b1d582abda44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 May 2022 21:28:50 +0900 Subject: [PATCH 08/11] Remove unused border colour --- .../HitCircles/Components/HitCircleOverlapMarker.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index e00abadb7e..b2fc310dcb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Utils; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; @@ -55,12 +54,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components [Resolved] private ISkinSource skin { get; set; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - circle.BorderColour = colours.Yellow; - } - public override void UpdateFrom(HitCircle hitObject) { base.UpdateFrom(hitObject); From d9782b5ef67627ab3597176f2b38a6d0efd0a37e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 May 2022 21:31:49 +0900 Subject: [PATCH 09/11] Remove redundant parenthesis --- .../Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index b2fc310dcb..b9d0d37d02 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components Scale = new Vector2(hitObject.Scale); - if ((hitObject is IHasComboInformation combo)) + if (hitObject is IHasComboInformation combo) ring.BorderColour = combo.GetComboColour(skin); double editorTime = editorClock.CurrentTime; From 35026ad6428f35b100575cdd0653d4694bdca3e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 May 2022 21:39:54 +0900 Subject: [PATCH 10/11] Add missing `EditorClock` caching --- osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index c3fb3bfc17..5448783f6d 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -2,16 +2,21 @@ // See the LICENCE file in the repository root for full licence text. using JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Screens.Edit; namespace osu.Game.Tests.Visual { public abstract class SelectionBlueprintTestScene : OsuManualInputManagerTestScene { + [Cached] + private readonly EditorClock editorClock = new EditorClock(); + protected override Container Content => content ?? base.Content; private readonly Container content; From cf3ead80477621b7b911010f5435269964127d38 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 May 2022 22:06:30 +0900 Subject: [PATCH 11/11] Remove unused local --- .../Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index b9d0d37d02..ad4be2017e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components /// public const double FADE_OUT_EXTENSION = 700; - private readonly Circle circle; private readonly RingPiece ring; [Resolved] @@ -37,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components InternalChildren = new Drawable[] { - circle = new Circle + new Circle { Anchor = Anchor.Centre, Origin = Anchor.Centre,