diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 0bec33bf77..3acec4498d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -32,6 +32,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public SliderBall Ball { get; private set; } public SkinnableDrawable Body { get; private set; } + /// + /// A target container which can be used to add top level elements to the slider's display. + /// Intended to be used for proxy purposes only. + /// + public Container OverlayElementContainer { get; private set; } + public override bool DisplayResult => !HitObject.OnlyJudgeNestedObjects; [CanBeNull] @@ -65,6 +71,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables tailContainer = new Container { RelativeSizeAxes = Axes.Both }, tickContainer = new Container { RelativeSizeAxes = Axes.Both }, repeatContainer = new Container { RelativeSizeAxes = Axes.Both }, + headContainer = new Container { RelativeSizeAxes = Axes.Both }, + OverlayElementContainer = new Container { RelativeSizeAxes = Axes.Both, }, Ball = new SliderBall(this) { GetInitialHitAction = () => HeadCircle.HitAction, @@ -72,7 +80,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AlwaysPresent = true, Alpha = 0 }, - headContainer = new Container { RelativeSizeAxes = Axes.Both }, slidingSample = new PausableSkinnableSound { Looping = true } }; @@ -179,6 +186,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables tailContainer.Clear(false); repeatContainer.Clear(false); tickContainer.Clear(false); + + OverlayElementContainer.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 01c0d988ee..2b026e6840 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [CanBeNull] public Slider Slider => DrawableSlider?.HitObject; - protected DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; + public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; public override bool DisplayResult => HitObject?.JudgeAsNormalHitCircle ?? base.DisplayResult; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 4a2a18ffd6..673211ac6c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [CanBeNull] public Slider Slider => DrawableSlider?.HitObject; - protected DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; + public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; private double animDuration; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 7a210324d7..3afd814174 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); } - private Container circleSprites; private Drawable hitCircleSprite; - private Drawable hitCircleOverlay; + + protected Drawable HitCircleOverlay { get; private set; } private SkinnableSpriteText hitCircleText; @@ -70,28 +70,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy // expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin). Texture overlayTexture = getTextureWithFallback("overlay"); - InternalChildren = new Drawable[] + InternalChildren = new[] { - circleSprites = new Container + hitCircleSprite = new KiaiFlashingSprite { + Texture = baseTexture, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + HitCircleOverlay = new KiaiFlashingSprite + { + Texture = overlayTexture, Anchor = Anchor.Centre, Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - hitCircleSprite = new KiaiFlashingSprite - { - Texture = baseTexture, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - hitCircleOverlay = new KiaiFlashingSprite - { - Texture = overlayTexture, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - } }, }; @@ -111,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy bool overlayAboveNumber = skin.GetConfig(OsuSkinConfiguration.HitCircleOverlayAboveNumber)?.Value ?? true; if (overlayAboveNumber) - AddInternal(hitCircleOverlay.CreateProxy()); + ChangeInternalChildDepth(HitCircleOverlay, float.MinValue); accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); @@ -153,8 +144,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Hit: - circleSprites.FadeOut(legacy_fade_duration, Easing.Out); - circleSprites.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + hitCircleSprite.FadeOut(legacy_fade_duration, Easing.Out); + hitCircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + + HitCircleOverlay.FadeOut(legacy_fade_duration, Easing.Out); + HitCircleOverlay.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); if (hasNumber) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs new file mode 100644 index 0000000000..fd7bfe7e60 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -0,0 +1,67 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacyReverseArrow : CompositeDrawable + { + private ISkin skin { get; } + + [Resolved(canBeNull: true)] + private DrawableHitObject drawableHitObject { get; set; } + + private Drawable proxy; + + public LegacyReverseArrow(ISkin skin) + { + this.skin = skin; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + string lookupName = new OsuSkinComponent(OsuSkinComponents.ReverseArrow).LookupName; + + InternalChild = skin.GetAnimation(lookupName, true, true) ?? Empty(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + proxy = CreateProxy(); + + if (drawableHitObject != null) + { + drawableHitObject.HitObjectApplied += onHitObjectApplied; + onHitObjectApplied(drawableHitObject); + } + } + + private void onHitObjectApplied(DrawableHitObject drawableObject) + { + Debug.Assert(proxy.Parent == null); + + // see logic in LegacySliderHeadHitCircle. + (drawableObject as DrawableSliderRepeat)?.DrawableSlider + .OverlayElementContainer.Add(proxy); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + if (drawableHitObject != null) + drawableHitObject.HitObjectApplied -= onHitObjectApplied; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs new file mode 100644 index 0000000000..13ba42ba50 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacySliderHeadHitCircle : LegacyMainCirclePiece + { + [Resolved(canBeNull: true)] + private DrawableHitObject drawableHitObject { get; set; } + + private Drawable proxiedHitCircleOverlay; + + public LegacySliderHeadHitCircle() + : base("sliderstartcircle") + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + proxiedHitCircleOverlay = HitCircleOverlay.CreateProxy(); + + if (drawableHitObject != null) + { + drawableHitObject.HitObjectApplied += onHitObjectApplied; + onHitObjectApplied(drawableHitObject); + } + } + + private void onHitObjectApplied(DrawableHitObject drawableObject) + { + Debug.Assert(proxiedHitCircleOverlay.Parent == null); + + // see logic in LegacyReverseArrow. + (drawableObject as DrawableSliderHead)?.DrawableSlider + .OverlayElementContainer.Add(proxiedHitCircleOverlay.With(d => d.Depth = float.MinValue)); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableHitObject != null) + drawableHitObject.HitObjectApplied -= onHitObjectApplied; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 87dfd33a62..8a24e36420 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -67,7 +67,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy case OsuSkinComponents.SliderHeadHitCircle: if (hasHitCircle.Value) - return new LegacyMainCirclePiece("sliderstartcircle"); + return new LegacySliderHeadHitCircle(); + + return null; + + case OsuSkinComponents.ReverseArrow: + if (hasHitCircle.Value) + return new LegacyReverseArrow(this); return null;