From 7dd9951c448515bb438992ca4aa127a3f770e604 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 17:41:08 +0900 Subject: [PATCH 01/11] Split out reverse arrow implementations to allow better animation --- .../Objects/Drawables/DrawableSliderRepeat.cs | 8 +++- .../Skinning/Argon/ArgonReverseArrow.cs | 48 ++++++++++++++----- ...seArrowPiece.cs => DefaultReverseArrow.cs} | 13 ++--- .../Skinning/Legacy/LegacyReverseArrow.cs | 18 ++++++- 4 files changed, 63 insertions(+), 24 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/Default/{ReverseArrowPiece.cs => DefaultReverseArrow.cs} (78%) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 5721328057..ac4d733672 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public SkinnableDrawable CirclePiece { get; private set; } - public ReverseArrowPiece Arrow { get; private set; } + public SkinnableDrawable Arrow { get; private set; } private Drawable scaleContainer; @@ -65,7 +65,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - Arrow = new ReverseArrowPiece(), + Arrow = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow), _ => new DefaultReverseArrow()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, } }); diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 67fc1b2304..61077e08a4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -2,12 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; 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.ControlPoints; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osuTK; @@ -15,14 +19,19 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public partial class ArgonReverseArrow : CompositeDrawable + public partial class ArgonReverseArrow : BeatSyncedContainer { + [Resolved] + private DrawableHitObject drawableRepeat { get; set; } = null!; + private Bindable accentColour = null!; private SpriteIcon icon = null!; + private Container main = null!; + [BackgroundDependencyLoader] - private void load(DrawableHitObject hitObject) + private void load(TextureStore textures, DrawableHitObject hitObject) { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -31,24 +40,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon InternalChildren = new Drawable[] { - new Circle + main = new Container { - Size = new Vector2(40, 20), - Colour = Color4.White, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - icon = new SpriteIcon - { - Icon = FontAwesome.Solid.AngleDoubleRight, - Size = new Vector2(16), + RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, + Children = new Drawable[] + { + new Circle + { + Size = new Vector2(40, 20), + Colour = Color4.White, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + icon = new SpriteIcon + { + Icon = FontAwesome.Solid.AngleDoubleRight, + Size = new Vector2(16), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } }, }; accentColour = hitObject.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4), true); } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!drawableRepeat.Judged) + main.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs similarity index 78% rename from osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index 27868db2f6..251f048fb6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -9,17 +9,16 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public partial class ReverseArrowPiece : BeatSyncedContainer + public partial class DefaultReverseArrow : BeatSyncedContainer { [Resolved] private DrawableHitObject drawableRepeat { get; set; } = null!; - public ReverseArrowPiece() + public DefaultReverseArrow() { Divisor = 2; MinimumBeatLength = 200; @@ -29,14 +28,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Size = OsuHitObject.OBJECT_DIMENSIONS; - Child = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon + Child = new SpriteIcon { RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, Icon = FontAwesome.Solid.ChevronRight, - Size = new Vector2(0.35f) - }) - { + Size = new Vector2(0.35f), Anchor = Anchor.Centre, Origin = Anchor.Centre, }; @@ -44,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { - if (!drawableRepeat.IsHit) + if (!drawableRepeat.Judged) Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 3a80607522..c63ae35a3f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -3,9 +3,11 @@ using System.Diagnostics; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -14,8 +16,11 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public partial class LegacyReverseArrow : CompositeDrawable + public partial class LegacyReverseArrow : BeatSyncedContainer { + [Resolved] + private DrawableHitObject drawableRepeat { get; set; } = null!; + [Resolved(canBeNull: true)] private DrawableHitObject? drawableHitObject { get; set; } @@ -30,6 +35,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skinSource) { + Divisor = 2; + MinimumBeatLength = 200; + AutoSizeAxes = Axes.Both; string lookupName = new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow).LookupName; @@ -59,6 +67,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } } + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!drawableRepeat.Judged) + Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + } + private void onHitObjectApplied(DrawableHitObject drawableObject) { Debug.Assert(proxy.Parent == null); From 455fc228ad5c572a772648a7da53084ea034dd5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 18:26:35 +0900 Subject: [PATCH 02/11] Add edge piece to argon reverse arrow --- .../Skinning/Argon/ArgonReverseArrow.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 61077e08a4..aed7d1a55f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -29,10 +29,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private SpriteIcon icon = null!; private Container main = null!; + private Sprite side = null!; [BackgroundDependencyLoader] private void load(TextureStore textures, DrawableHitObject hitObject) { + Divisor = 2; + MinimumBeatLength = 120; + EarlyActivationMilliseconds = 30; + Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -63,6 +68,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }, } }, + side = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Texture = textures.Get("Gameplay/osu/repeat-edge-piece"), + Size = new Vector2(ArgonMainCirclePiece.OUTER_GRADIENT_SIZE), + } }; accentColour = hitObject.AccentColour.GetBoundCopy(); @@ -72,7 +84,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (!drawableRepeat.Judged) - main.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + { + main.ScaleTo(1.3f, 30, Easing.Out) + .Then() + .ScaleTo(1f, timingPoint.BeatLength / 2, Easing.Out); + side + .MoveToX(-12, 30, Easing.Out) + .Then() + .MoveToX(0, timingPoint.BeatLength / 2, Easing.Out); + } } } } From ad4e988520def03498327625be3c9369be0d0a7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 18:34:21 +0900 Subject: [PATCH 03/11] Adjust reverse arrows to bounce more --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs | 7 +++---- .../Skinning/Default/DefaultReverseArrow.cs | 2 +- .../Skinning/Legacy/LegacyReverseArrow.cs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index aed7d1a55f..1ce3a32900 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -35,8 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private void load(TextureStore textures, DrawableHitObject hitObject) { Divisor = 2; - MinimumBeatLength = 120; - EarlyActivationMilliseconds = 30; + MinimumBeatLength = 150; Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -85,11 +84,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { if (!drawableRepeat.Judged) { - main.ScaleTo(1.3f, 30, Easing.Out) + main.ScaleTo(1.3f, timingPoint.BeatLength / 8, Easing.Out) .Then() .ScaleTo(1f, timingPoint.BeatLength / 2, Easing.Out); side - .MoveToX(-12, 30, Easing.Out) + .MoveToX(-12, timingPoint.BeatLength / 8, Easing.Out) .Then() .MoveToX(0, timingPoint.BeatLength / 2, Easing.Out); } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index 251f048fb6..f1deba7782 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default public DefaultReverseArrow() { Divisor = 2; - MinimumBeatLength = 200; + MinimumBeatLength = 150; Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index c63ae35a3f..e1d1b088a2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private void load(ISkinSource skinSource) { Divisor = 2; - MinimumBeatLength = 200; + MinimumBeatLength = 150; AutoSizeAxes = Axes.Both; From 8010410487c9e43434e4785af10f64156f4d81d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 19:09:57 +0900 Subject: [PATCH 04/11] Stop beat syncing (and close match stable's implementation of arrow animation) --- .../Skinning/Argon/ArgonReverseArrow.cs | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 1ce3a32900..d4084a76f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -10,8 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osuTK; @@ -19,24 +16,20 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public partial class ArgonReverseArrow : BeatSyncedContainer + public partial class ArgonReverseArrow : CompositeDrawable { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } = null!; + private DrawableHitObject drawableObject { get; set; } = null!; private Bindable accentColour = null!; private SpriteIcon icon = null!; - private Container main = null!; private Sprite side = null!; [BackgroundDependencyLoader] - private void load(TextureStore textures, DrawableHitObject hitObject) + private void load(TextureStore textures) { - Divisor = 2; - MinimumBeatLength = 150; - Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -76,22 +69,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } }; - accentColour = hitObject.AccentColour.GetBoundCopy(); + accentColour = drawableObject.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4), true); + + drawableObject.ApplyCustomUpdateState += updateStateTransforms; } - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) { - if (!drawableRepeat.Judged) + const float move_distance = -12; + const double move_out_duration = 35; + const double move_in_duration = 250; + const double total = 300; + + switch (state) { - main.ScaleTo(1.3f, timingPoint.BeatLength / 8, Easing.Out) - .Then() - .ScaleTo(1f, timingPoint.BeatLength / 2, Easing.Out); - side - .MoveToX(-12, timingPoint.BeatLength / 8, Easing.Out) - .Then() - .MoveToX(0, timingPoint.BeatLength / 2, Easing.Out); + case ArmedState.Idle: + main.ScaleTo(1.3f, move_out_duration, Easing.Out) + .Then() + .ScaleTo(1f, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + side + .MoveToX(move_distance, move_out_duration, Easing.Out) + .Then() + .MoveToX(0, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + break; } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } From e4ac8362ecd5329458356013e0c66eff310cf40d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 19:17:45 +0900 Subject: [PATCH 05/11] Update other implementations to use non-beat-sync logic --- .../Skinning/Default/DefaultReverseArrow.cs | 42 +++++++++---- .../Skinning/Legacy/LegacyReverseArrow.cs | 61 ++++++++++--------- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index f1deba7782..a019a4767b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -2,33 +2,28 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public partial class DefaultReverseArrow : BeatSyncedContainer + public partial class DefaultReverseArrow : CompositeDrawable { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } = null!; + private DrawableHitObject drawableObject { get; set; } = null!; public DefaultReverseArrow() { - Divisor = 2; - MinimumBeatLength = 150; - Anchor = Anchor.Centre; Origin = Anchor.Centre; Size = OsuHitObject.OBJECT_DIMENSIONS; - Child = new SpriteIcon + InternalChild = new SpriteIcon { RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, @@ -39,10 +34,33 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default }; } - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + [BackgroundDependencyLoader] + private void load() { - if (!drawableRepeat.Judged) - Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + } + + private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) + { + const double move_out_duration = 35; + const double move_in_duration = 250; + const double total = 300; + + switch (state) + { + case ArmedState.Idle: + InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) + .Then() + .ScaleTo(1f, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + break; + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index e1d1b088a2..98ac770dd0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -3,11 +3,9 @@ using System.Diagnostics; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -16,13 +14,10 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public partial class LegacyReverseArrow : BeatSyncedContainer + public partial class LegacyReverseArrow : CompositeDrawable { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } = null!; - - [Resolved(canBeNull: true)] - private DrawableHitObject? drawableHitObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; private Drawable proxy = null!; @@ -35,9 +30,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skinSource) { - Divisor = 2; - MinimumBeatLength = 150; - AutoSizeAxes = Axes.Both; string lookupName = new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow).LookupName; @@ -46,6 +38,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()); textureIsDefaultSkin = skin is ISkinTransformer transformer && transformer.Skin is DefaultLegacySkin; + + drawableObject.ApplyCustomUpdateState += updateStateTransforms; } protected override void LoadComplete() @@ -54,23 +48,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy proxy = CreateProxy(); - if (drawableHitObject != null) + drawableObject.HitObjectApplied += onHitObjectApplied; + onHitObjectApplied(drawableObject); + + accentColour = drawableObject.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(c => { - drawableHitObject.HitObjectApplied += onHitObjectApplied; - onHitObjectApplied(drawableHitObject); - - accentColour = drawableHitObject.AccentColour.GetBoundCopy(); - accentColour.BindValueChanged(c => - { - arrow.Colour = textureIsDefaultSkin && c.NewValue.R + c.NewValue.G + c.NewValue.B > (600 / 255f) ? Color4.Black : Color4.White; - }, true); - } - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - if (!drawableRepeat.Judged) - Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + arrow.Colour = textureIsDefaultSkin && c.NewValue.R + c.NewValue.G + c.NewValue.B > (600 / 255f) ? Color4.Black : Color4.White; + }, true); } private void onHitObjectApplied(DrawableHitObject drawableObject) @@ -82,11 +67,29 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy .OverlayElementContainer.Add(proxy); } + private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) + { + const double move_out_duration = 35; + const double move_in_duration = 250; + const double total = 300; + + switch (state) + { + case ArmedState.Idle: + InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) + .Then() + .ScaleTo(1f, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + break; + } + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - if (drawableHitObject != null) - drawableHitObject.HitObjectApplied -= onHitObjectApplied; + + drawableObject.HitObjectApplied -= onHitObjectApplied; + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } From 1bee7bf353d286978b1b975c1d202c2730ce7b2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 19:22:24 +0900 Subject: [PATCH 06/11] Add note about rotation --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 98ac770dd0..81781bc6b0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -76,6 +76,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Idle: + // TODO: rotate slightly if Version < 1 (aka UseNewLayout) InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) .Then() .ScaleTo(1f, move_in_duration, Easing.Out) From f0070eecf10ce1fe7193e973eee20ae1720e9a12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 20:09:39 +0900 Subject: [PATCH 07/11] Add rotation support for very old skins --- .../Resources/old-skin/reversearrow.png | Bin 0 -> 4853 bytes .../Skinning/Legacy/LegacyReverseArrow.cs | 26 ++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/old-skin/reversearrow.png diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/reversearrow.png b/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/reversearrow.png new file mode 100644 index 0000000000000000000000000000000000000000..7ebdec37d356490d018f711ae525abb3250be3fd GIT binary patch literal 4853 zcmbtY_d6S2)K3TvF=AJY#9lQ+X=~T6O-qYfvDz9{dqfawR;=11ZH=O}s)``Awptzb zh+1DWsG^iN?|<+<&wHP9@A=`LAMUyLbI$pkn`myT&qxoW2LJ$!h6Xy86pi`c38tm2 zpVgg*D2h8k*EYb)*F7NE+20MIh4OWALl}BHd$?J;Iio_K4!EfT0IWHNI$G8tGusYy ze%89MU3(B%07OSunwYKw;u4JEO|ne7^3o{OyjsNNlUYlR^p^>T`RpD`i6LrpagI4i z?BFU(8YW&C2kA~?H9lfU~o91h-_28Sn)_H7H3 zH^njMCDtdJH*Vb6j_2`lI$R(1Pz(Qq5^7K1Blti;gpOh~lp|}_G`rK%)6-K^T8fF1MIbOHxpL8J z=j6|0P(SFR=waPVjWGGI4wMDKXp;-%U{*gt2zlVx1m)!X=7#f-%8QZ5^XI(}3*p-d5Ziwu*NI}%r9ohCT zMVdlYRaLgy+S)>f35o@2a1C`SdHH%xR>Q{t=6j&)1*rwmk!OFD&SFf9Zq^TEiapE3 z)Ee@n{5RirYco_Pakj3G$nh_eM-;H&fX875KO#ReY97C{`+5$ znF8HIUCfPVYsBQV^6|7@!2VI{a> z5H&%;Ziy)B;jZJws8IzZvLy(rWAJKJML71O)H3}HLM02qH*K_4G0KO zOioI2QJxQAOHN5aq0wlW)3%YKTYVpW<_9MxCSWGiEF_hs2)B#Hel6M#9q?_luJ#J;l+m^~h3^ukW9ivun(B!5#qEAJ#5-j4xzj5f0gPWOAy(!$j z-ES+#>9TKrj%RdDQ#}CN9J^B)cYpMrwG9iqSzTGVv?%oasWcrtCTF3Fak}THaC9dR z-31W8OPZ_4-+tbp50A`>i;K(C+W<3?*vrey{f}yMu?|<5`Oo``)xv*%9@LUgi2mMi zszm(#-#42HH&};W#KqjR(fZuntKYy2kD9cb4pRi~aq5ngrff$&w6L&Prhxj}zBG)_ z3t?kEI#T;>%ESb~8ll`;6BC>knAOK0o|4M1HsiM6D&?-a9q!^HILZiEIp-**AQMWb z7K`?YrgBS)knO-Y|tgIx_jTw)Rw(gq3ZHdZaOOi?sSWerbEU z@x1s+q&x}wHAEOxN{i-doR@Sb@G>UR`Q>H+tSU^~qh)wJ8Coy?ZiOnz7&y^7m2}NC zJ?2T)Z)j*RGT6}f{0V1?>8peyJB=CUO4uF{t8l~!P-)&mvCL&OIsH}9tza41207}w zs~>#kZ~i&k>qN4KIQaPNj-Q`LSm#+ofHw49LlzPpQKp1)y>SMn#z&Ya?VX{##d=r$ zG%i)nX!WygWY7{3h&Fq8@%FWT+U~1Q9maY4Zt>iX5@=fdBwg1XHYYY1(LNMIxjvy5 zB(+R>41)Ki!98NHFs~(6NCD$~o*Zrdm>akixM|J!_JUgRj5+zfG>xNV zeAR9>V@z|4C0Ry{_{K03Iw{S{gxFeW4=pD9ak`3hp z)KQX=cK*?{;?^CGt{m}h*}LwM@0@#QZ-ktMr^48x|fOo|qJ&Ag}{{-982Uo&mozGBTLPwikumgIb`fz4rx9{6E(;OE%7r zzoZe85g>j^WIOw|>hp9--_|zdBZ0uHts(6$1ZPkDqRpT4z!^(RdE2(pfdPqI z5hs3O4h|0WuXaZzUmI6O+}J8BYHqVi%&i6!A?e3<0(BeN!&{WGav9pcWX(x@}CMHI3i#Sts?1vp_Nc~k#f%9iZwqks$&9gca zo1lcWG`Mz-`V@L6=@sJvak{~6=u;By$0yVNxu8yc@N1*Qw$(~{28IurR9mllI9~#{;Nj2M`B`P@Ym+@4yt{EpeQ|y zvx$Xje36|m-!mGZdDPEgR``#bDu1Z}#$M-ppk=^*p; zjErve(-k(Ei2Tz~?UQvZIT=e{9j=A0>9`+k7uU%WIY1}W@B7c2IO{h5jNICj`w%X0 zX0Ow2_IlAy2IONwI8e|vpHQC+-kAxMLzT(s4dlrtkR4gk`Q}??+GIV_9ofZqchPn# z(S%pjciY~@`F5Pfd+hgHNC|n!7O97Gzu-uGdT-7K=CV&~d8y7`yzqS0v&IC_($cd1 zD^262{KYZ53_m;GE-vID-u%+?q{-;X9{J5X=l5d(f_fVT`tJ@Rroz9RoD4(g>HP8rBHpcI&rB-36`2k=dKx|D5efW#<6#`S5f?!~T=+R@3RbxuiS=L8}m zZB}wOX}*iFlD)ioFH~i76PG8{=4gOYk;Ga*L13!NTT(@D81j5AvaXEEg@WPuh28nK zC;_X37Ba^Q62gGZc(k|%b>gRWHgBalG8>)C%*$)hAyiD@NXTrmgBw+Y8|=rlriU!n z^X$(~BaT;cI&N!MFMF{j>0w*Y4y<+icJ})pkLJxTzOXelHHpNitQxUfxLhZ-4bmC+ zWLsB#D@i?&>MyOSsWAc@XK22(8Bp97+3(?U{E~WAe)-{n(3qgG0m0_pitT-?!71zR zU=AQol>|}ndtca6eMJ=DkB}~1JN|L>M=Et7(%>ZFa5nMy6x=o2a}?9f_&hOR@`V)rEB0Axu4 zu;u3ZwFIU`&y^`taKEihuu^wJW4Xf4O}s8D#nD%f)RqFEl=5owv>OVgxQh*>9RpE~ zGD08_*6z&LA~al<)CR1!j3@;Wdu@QQSO4b)OrhFM4;4sz*wM1OE((QG*3jq#^gL~= z%BzCvW)OSr?Ta2iq5>!>DV30r=YM8>L)S(m_-i^fMi+mztT4|-q>fb4w~-d`N<<~} zCqqL+4IHO|b~&T4A15s%O!yy0W&bige3P)b!PPtoFfY^9)g6+{>-f7_om}N_mvn3Q zQ*5H8jPbjG&Cxz{phKg@8m=Eyq^YgQ?vK}NLqBXvG z`^~=q*h9>P<(lz$5(7*WZxMsU=&@>ATYq<`qop+|B{6}ZFS6b>G#or}b|!^?((Oq_ zawd++(bI^HkB|S0jg5s{8kT;=gnI#qAD^v{P}t0BfyMAX#X-k9>1q*8rM;38QA`_D^AS+kwx4|%KPJaj?FUDnkd!odJkAmF->YqEfp2Jfr5+G%9s`dj zC}+b7c^aCTmH0HzJ|5HX_*QN*S;$6=W)f5gQAZ#U+Bl-)W1zAiriw;fu;1j)or1JI z*C@5Yx>}m4u=qMTaq-IV#g53!!I9&I@drdkB>=P`PQ1k>7^}iRt$ol6= zTCud!!U_yrO!!XDW*#rV5B9N2N<*@DP8mnyu+U$r%I_ugF?D1L1zs0MWY%T9!fplH zZlFaqm1u1Fsz$zkjT4=s?0;2WT;WlFkYt!CT5spu&T*mn#NK|+(wY9eNyATIhH(D_ zG`<$fRQPeE=w@L4ZKnAW@?k}BSQ4aBgoy5%ZuB^`^iA$*kU%1zQ9Z8OLLNz$^g)T5 zF#y9DB9Z8^*S4pg<#EVFO6HV)H2z0{_d9t|s+P?8uB@z#2dSV??6EF|hA9H)Djf)j z=n^BUq}4q>1yuj?($Z3~r(~Sa`~!bIK!!<(tbyi?lbSAU6w>H=7{vPNM=0=XI&pNg z*38&=c=6Ti*Uu5tY;gGK83Xt6zM}|ThcGLV*S5U~kV@3Ao!r z*}a=9D=YKvqA~hKyfZ0=xS7(%G4Q;&DleRaL#Zx!Z-F4qU8wt8tT%dWg9`nY%+elh zUS7WIEX-On+ZwoqbQg*45N~v->7hVTm!X%^>A&xDC@4Srz1;-z)Z?ji$G5w{VraNmlnNJO_;l(~ zf`W!iHUZ)SHxd@#R8*w7n#>c8*<}9aM)%V;F4cNsnFIqESh2XD z3LN)fM~a70uSc(l7?GLAk)`#w6YhV&q}?CRbK#8ONJT_q|F{GwrZCmKMKSE9OFN_b zSdPran$|n}KE$;18e55$fvMMb2E7-KYTlA=W1z2uv0>RFt{I@~KfeoUdMlD#KPi|1 zjzwarHwzu+PH#V=4K=E``8`!wlI}Y-+}^*iU@{j&;r^XJqOOFJH;0ehOwMTkWgB#t zI7FbTi(SkinConfiguration.LegacySetting.Version)?.Value <= 1; } protected override void LoadComplete() @@ -76,11 +80,23 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Idle: - // TODO: rotate slightly if Version < 1 (aka UseNewLayout) - InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) - .Then() - .ScaleTo(1f, move_in_duration, Easing.Out) - .Loop(total - (move_in_duration + move_out_duration)); + if (shouldRotate) + { + InternalChild.ScaleTo(1.3f, move_out_duration) + .RotateTo(5.625f) + .Then() + .ScaleTo(1f, move_in_duration) + .RotateTo(-5.625f, move_in_duration) + .Loop(total - (move_in_duration + move_out_duration)); + } + else + { + InternalChild.ScaleTo(1.3f) + .Then() + .ScaleTo(1f, move_in_duration) + .Loop(total - (move_in_duration + move_out_duration)); + } + break; } } From 94e49a34fdd1d827a500d0235800e40fff1cab41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 22:26:57 +0900 Subject: [PATCH 08/11] Adjust legacy reverse arrow implementation to match stable more closely --- .../Skinning/Legacy/LegacyReverseArrow.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 09625c2aed..7e69c7a25b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -73,28 +73,26 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) { - const double move_out_duration = 35; - const double move_in_duration = 250; - const double total = 300; + const double duration = 300; + const float rotation = 5.625f; switch (state) { case ArmedState.Idle: if (shouldRotate) { - InternalChild.ScaleTo(1.3f, move_out_duration) - .RotateTo(5.625f) + InternalChild.ScaleTo(1.3f) + .RotateTo(rotation) .Then() - .ScaleTo(1f, move_in_duration) - .RotateTo(-5.625f, move_in_duration) - .Loop(total - (move_in_duration + move_out_duration)); + .ScaleTo(1f, duration) + .RotateTo(-rotation, duration) + .Loop(); } else { - InternalChild.ScaleTo(1.3f) - .Then() - .ScaleTo(1f, move_in_duration) - .Loop(total - (move_in_duration + move_out_duration)); + InternalChild.ScaleTo(1.3f).Then() + .ScaleTo(1f, duration, Easing.Out) + .Loop(); } break; From 3aa51301e8b9f94c7088b59af796daf7d011e3fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 22:28:33 +0900 Subject: [PATCH 09/11] Add null checks in disposal flow --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs | 5 ++++- .../Skinning/Default/DefaultReverseArrow.cs | 5 ++++- .../Skinning/Legacy/LegacyReverseArrow.cs | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index d4084a76f1..160edb6f67 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -101,7 +102,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + + if (drawableObject.IsNotNull()) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index a019a4767b..b44f6571b9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -60,7 +61,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + + if (drawableObject.IsNotNull()) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 7e69c7a25b..34bcf95e1d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; @@ -103,8 +104,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { base.Dispose(isDisposing); - drawableObject.HitObjectApplied -= onHitObjectApplied; - drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + if (drawableObject.IsNotNull()) + { + drawableObject.HitObjectApplied -= onHitObjectApplied; + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } } From 16fcc4eaaa9818989a1ad39cb6921822ab35abc7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 12:32:52 +0900 Subject: [PATCH 10/11] Fix incorrect anchor/origin causing rotation to look wrong on legacy skin arrows --- .../Skinning/Legacy/LegacyReverseArrow.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 34bcf95e1d..25de6d2381 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -39,7 +39,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy var skin = skinSource.FindProvider(s => s.GetTexture(lookupName) != null); - InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()); + InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()).With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + }); + textureIsDefaultSkin = skin is ISkinTransformer transformer && transformer.Skin is DefaultLegacySkin; drawableObject.ApplyCustomUpdateState += updateStateTransforms; From 2cbec6dbdf115562d64d44f515ee9ad520e20416 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:11:52 +0900 Subject: [PATCH 11/11] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 58e18d3187..0ee922e53a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - +