From aa7ade8186df4033412bf93db2b970c5ae18a8fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Apr 2021 15:22:17 +0900 Subject: [PATCH 1/4] Expose presence of `MainCirclePiece` via an interface --- .../Objects/Drawables/DrawableHitCircle.cs | 2 +- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 +- .../Objects/Drawables/DrawableSliderTail.cs | 11 ++++++----- .../Skinning/Default/IHasMainCirclePiece.cs | 12 ++++++++++++ 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index fb6c110b3c..1bf9e76d7d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableHitCircle : DrawableOsuHitObject + public class DrawableHitCircle : DrawableOsuHitObject, IHasMainCirclePiece { public OsuAction? HitAction => HitArea.HitAction; protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 5af2a38559..cc7d9d1b23 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking + public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking, IHasMainCirclePiece { public new SliderRepeat HitObject => (SliderRepeat)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index 84b9b881a2..d81af053d1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, ITrackSnaking + public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, ITrackSnaking, IHasMainCirclePiece { public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject; @@ -35,7 +35,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public bool Tracking { get; set; } - private SkinnableDrawable circlePiece; + public SkinnableDrawable CirclePiece { get; private set; } + private Container scaleContainer; public DrawableSliderTail() @@ -64,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new Drawable[] { // no default for this; only visible in legacy skins. - circlePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) + CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) } }, }; @@ -76,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateInitialTransforms(); - circlePiece.FadeInFromZero(HitObject.TimeFadeIn); + CirclePiece.FadeInFromZero(HitObject.TimeFadeIn); } protected override void UpdateHitStateTransforms(ArmedState state) @@ -85,7 +86,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Debug.Assert(HitObject.HitWindows != null); - (circlePiece.Drawable as IMainCirclePiece)?.Animate(state); + (CirclePiece.Drawable as IMainCirclePiece)?.Animate(state); switch (state) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs new file mode 100644 index 0000000000..8bb7629542 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Osu.Skinning.Default +{ + public interface IHasMainCirclePiece + { + SkinnableDrawable CirclePiece { get; } + } +} From 4da964c3f3235661b8f4b9c9d7c32cb60f3e711b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Apr 2021 15:22:42 +0900 Subject: [PATCH 2/4] Expose `DrawableSliderRepeat`'s arrow and move transforms to children --- .../Objects/Drawables/DrawableSliderRepeat.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index cc7d9d1b23..5db012c4f8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -28,8 +28,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public SkinnableDrawable CirclePiece { get; private set; } + public ReverseArrowPiece Arrow { get; private set; } + private Drawable scaleContainer; - private ReverseArrowPiece arrow; public override bool DisplayResult => false; @@ -57,8 +58,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new Drawable[] { // no default for this; only visible in legacy skins. - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()), - arrow = new ReverseArrowPiece(), + CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + Arrow = new ReverseArrowPiece(), } }; @@ -105,8 +110,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables break; case ArmedState.Hit: - this.FadeOut(animDuration, Easing.Out) - .ScaleTo(Scale * 1.5f, animDuration, Easing.Out); + this.FadeOut(animDuration, Easing.Out); + + Arrow.ScaleTo(Scale * 1.5f, animDuration, Easing.Out); + CirclePiece.ScaleTo(Scale * 1.5f, animDuration, Easing.Out); break; } } @@ -142,18 +149,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } float aimRotation = MathUtils.RadiansToDegrees(MathF.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X)); - while (Math.Abs(aimRotation - arrow.Rotation) > 180) - aimRotation += aimRotation < arrow.Rotation ? 360 : -360; + while (Math.Abs(aimRotation - Arrow.Rotation) > 180) + aimRotation += aimRotation < Arrow.Rotation ? 360 : -360; if (!hasRotation) { - arrow.Rotation = aimRotation; + Arrow.Rotation = aimRotation; hasRotation = true; } else { // If we're already snaking, interpolate to smooth out sharp curves (linear sliders, mainly). - arrow.Rotation = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 100), arrow.Rotation, aimRotation, 0, 50, Easing.OutQuint); + Arrow.Rotation = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 100), Arrow.Rotation, aimRotation, 0, 50, Easing.OutQuint); } } } From 8795c5f0824e1f1cd9b1aae00d429ac2968713f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Apr 2021 15:23:21 +0900 Subject: [PATCH 3/4] Update osu! editor transform logic to allow adjustments to `DrawableSliderRepeat` and `DrawableSliderTail` --- .../Edit/DrawableOsuEditorRuleset.cs | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs index 7227e2b511..aeeae84d14 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs @@ -11,6 +11,7 @@ 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; @@ -56,43 +57,45 @@ namespace osu.Game.Rulesets.Osu.Edit if (state == ArmedState.Idle || hitAnimations.Value) return; - // adjust the visuals of certain object types to make them stay on screen for longer than usual. - switch (hitObject) + if (hitObject is DrawableHitCircle circle) { - default: - // there are quite a few drawable hit types we don't want to extend (spinners, ticks etc.) - return; + circle.ApproachCircle + .FadeOutFromOne(editor_hit_object_fade_out_extension * 4) + .Expire(); - case DrawableSlider _: - // no specifics to sliders but let them fade slower below. - break; - - case DrawableHitCircle circle: // also handles slider heads - circle.ApproachCircle - .FadeOutFromOne(editor_hit_object_fade_out_extension * 4) - .Expire(); - - circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); - - var circlePieceDrawable = circle.CirclePiece.Drawable; - - // clear any explode animation logic. - circlePieceDrawable.ApplyTransformsAt(circle.HitStateUpdateTime, true); - circlePieceDrawable.ClearTransformsAfter(circle.HitStateUpdateTime, true); - - break; + circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); } - // Get the existing fade out transform - var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); + if (hitObject is IHasMainCirclePiece mainPieceContainer) + { + // clear any explode animation logic. + mainPieceContainer.CirclePiece.ApplyTransformsAt(hitObject.HitStateUpdateTime, true); + mainPieceContainer.CirclePiece.ClearTransformsAfter(hitObject.HitStateUpdateTime, true); + } - if (existing == null) - return; + if (hitObject is DrawableSliderRepeat repeat) + { + repeat.Arrow.ApplyTransformsAt(hitObject.HitStateUpdateTime, true); + repeat.Arrow.ClearTransformsAfter(hitObject.HitStateUpdateTime, true); + } - hitObject.RemoveTransform(existing); + // 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)); - using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime)) - hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); + if (existing == null) + return; + + hitObject.RemoveTransform(existing); + + using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime)) + hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); + break; + } } } } From d10aac851debb1a7b185a855f76c491833e193ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Apr 2021 15:30:22 +0900 Subject: [PATCH 4/4] Extract scale constant --- .../Objects/Drawables/DrawableSliderRepeat.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 5db012c4f8..7b4188edab 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -112,8 +112,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables case ArmedState.Hit: this.FadeOut(animDuration, Easing.Out); - Arrow.ScaleTo(Scale * 1.5f, animDuration, Easing.Out); - CirclePiece.ScaleTo(Scale * 1.5f, animDuration, Easing.Out); + const float final_scale = 1.5f; + + Arrow.ScaleTo(Scale * final_scale, animDuration, Easing.Out); + CirclePiece.ScaleTo(Scale * final_scale, animDuration, Easing.Out); break; } }