diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs
index 029de2cac0..e30988d8f7 100644
--- a/osu.Game.Rulesets.Catch/UI/Catcher.cs
+++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs
@@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
@@ -37,6 +36,11 @@ namespace osu.Game.Rulesets.Catch.UI
///
public static readonly Color4 DEFAULT_CATCHER_HYPER_DASH_COLOUR = Color4.OrangeRed;
+ ///
+ /// The duration between transitioning to hyper-dash state.
+ ///
+ public const double HYPER_DASH_TRANSITION_DURATION = 180;
+
///
/// Whether we are hyper-dashing or not.
///
@@ -49,10 +53,10 @@ namespace osu.Game.Rulesets.Catch.UI
public Container ExplodingFruitTarget;
- private readonly Container additiveTarget;
- private Container dashTrails;
- private Container hyperDashTrails;
- private Container endGlowSprites;
+ [NotNull]
+ private readonly Container trailsTarget;
+
+ private CatcherTrailDisplay trails;
public CatcherAnimationState CurrentState { get; private set; }
@@ -66,33 +70,23 @@ namespace osu.Game.Rulesets.Catch.UI
///
internal float CatchWidth => CatcherArea.CATCHER_SIZE * Math.Abs(Scale.X) * allowed_catch_range;
- protected bool Dashing
+ ///
+ /// The drawable catcher for .
+ ///
+ internal Drawable CurrentDrawableCatcher => currentCatcher.Drawable;
+
+ private bool dashing;
+
+ public bool Dashing
{
get => dashing;
- set
+ protected set
{
if (value == dashing) return;
dashing = value;
- Trail |= dashing;
- }
- }
-
- ///
- /// Activate or deactivate the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met.
- ///
- protected bool Trail
- {
- get => trail;
- set
- {
- if (value == trail || additiveTarget == null) return;
-
- trail = value;
-
- if (Trail)
- beginTrail();
+ trails.DisplayTrail |= dashing;
}
}
@@ -109,17 +103,13 @@ namespace osu.Game.Rulesets.Catch.UI
private int currentDirection;
- private bool dashing;
-
- private bool trail;
-
private double hyperDashModifier = 1;
private int hyperDashDirection;
private float hyperDashTargetPosition;
- public Catcher([NotNull] Container additiveTarget, BeatmapDifficulty difficulty = null)
+ public Catcher([NotNull] Container trailsTarget, BeatmapDifficulty difficulty = null)
{
- this.additiveTarget = additiveTarget;
+ this.trailsTarget = trailsTarget;
RelativePositionAxes = Axes.X;
X = 0.5f;
@@ -158,12 +148,7 @@ namespace osu.Game.Rulesets.Catch.UI
}
};
- additiveTarget?.AddRange(new[]
- {
- dashTrails = new Container { RelativeSizeAxes = Axes.Both },
- hyperDashTrails = new Container { RelativeSizeAxes = Axes.Both, Colour = hyperDashColour },
- endGlowSprites = new Container { RelativeSizeAxes = Axes.Both, Colour = hyperDashEndGlowColour }
- });
+ trailsTarget.Add(trails = new CatcherTrailDisplay(this));
updateCatcher();
}
@@ -257,7 +242,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (wasHyperDashing)
{
updateCatcherColour(false);
- Trail &= Dashing;
+ trails.DisplayTrail &= Dashing;
}
}
else
@@ -269,21 +254,15 @@ namespace osu.Game.Rulesets.Catch.UI
if (!wasHyperDashing)
{
updateCatcherColour(true);
- Trail = true;
- var hyperDashEndGlow = createAdditiveSprite(endGlowSprites);
- hyperDashEndGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In);
- hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.95f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In);
- hyperDashEndGlow.FadeOut(1200);
- hyperDashEndGlow.Expire(true);
+ trails.DisplayTrail = true;
+ trails.DisplayEndGlow();
}
}
}
private void updateCatcherColour(bool hyperDashing)
{
- const float hyper_dash_transition_length = 180;
-
if (hyperDashing)
{
// special behaviour for catcher colour if no skin overrides.
@@ -292,17 +271,17 @@ namespace osu.Game.Rulesets.Catch.UI
? DEFAULT_CATCHER_HYPER_DASH_COLOUR
: hyperDashColour;
- this.FadeColour(catcherColour, hyper_dash_transition_length, Easing.OutQuint);
- this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
+ this.FadeColour(catcherColour, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
+ this.FadeTo(0.2f, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
}
else
{
- this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
- this.FadeTo(1f, hyper_dash_transition_length, Easing.OutQuint);
+ this.FadeColour(Color4.White, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
+ this.FadeTo(1f, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
}
- hyperDashTrails?.FadeColour(hyperDashColour, hyper_dash_transition_length, Easing.OutQuint);
- endGlowSprites?.FadeColour(hyperDashEndGlowColour, hyper_dash_transition_length, Easing.OutQuint);
+ trails.HyperDashTrailsColour = hyperDashColour;
+ trails.EndGlowSpritesColour = hyperDashEndGlowColour;
}
public bool OnPressed(CatchAction action)
@@ -453,22 +432,6 @@ namespace osu.Game.Rulesets.Catch.UI
(currentCatcher.Drawable as IFramedAnimation)?.GotoFrame(0);
}
- private void beginTrail()
- {
- if (!dashing && !HyperDashing)
- {
- Trail = false;
- return;
- }
-
- var additive = createAdditiveSprite(HyperDashing ? hyperDashTrails : dashTrails);
-
- additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
- additive.Expire(true);
-
- Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
- }
-
private void updateState(CatcherAnimationState state)
{
if (CurrentState == state)
@@ -478,27 +441,6 @@ namespace osu.Game.Rulesets.Catch.UI
updateCatcher();
}
- private CatcherTrailSprite createAdditiveSprite(Container target)
- {
- if (target == null)
- return null;
-
- var tex = (currentCatcher.Drawable as TextureAnimation)?.CurrentFrame ?? ((Sprite)currentCatcher.Drawable).Texture;
-
- var sprite = new CatcherTrailSprite(tex)
- {
- Anchor = Anchor,
- Scale = Scale,
- Blending = BlendingParameters.Additive,
- RelativePositionAxes = RelativePositionAxes,
- Position = Position
- };
-
- target.Add(sprite);
-
- return sprite;
- }
-
private void removeFromPlateWithTransform(DrawableHitObject fruit, Action action)
{
if (ExplodingFruitTarget != null)
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs
new file mode 100644
index 0000000000..afbfac9a51
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs
@@ -0,0 +1,137 @@
+// 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 osu.Framework.Graphics;
+using osu.Framework.Graphics.Animations;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.UI
+{
+ ///
+ /// Represents a component responsible for displaying
+ /// the appropriate catcher trails when requested to.
+ ///
+ public class CatcherTrailDisplay : CompositeDrawable
+ {
+ private readonly Catcher catcher;
+
+ private readonly Container dashTrails;
+ private readonly Container hyperDashTrails;
+ private readonly Container endGlowSprites;
+
+ private Color4 hyperDashTrailsColour;
+
+ public Color4 HyperDashTrailsColour
+ {
+ get => hyperDashTrailsColour;
+ set
+ {
+ if (hyperDashTrailsColour == value)
+ return;
+
+ hyperDashTrailsColour = value;
+ hyperDashTrails.FadeColour(hyperDashTrailsColour, Catcher.HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
+ }
+ }
+
+ private Color4 endGlowSpritesColour;
+
+ public Color4 EndGlowSpritesColour
+ {
+ get => endGlowSpritesColour;
+ set
+ {
+ if (endGlowSpritesColour == value)
+ return;
+
+ endGlowSpritesColour = value;
+ endGlowSprites.FadeColour(endGlowSpritesColour, Catcher.HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
+ }
+ }
+
+ private bool trail;
+
+ ///
+ /// Whether to start displaying trails following the catcher.
+ ///
+ public bool DisplayTrail
+ {
+ get => trail;
+ set
+ {
+ if (trail == value)
+ return;
+
+ trail = value;
+
+ if (trail)
+ displayTrail();
+ }
+ }
+
+ public CatcherTrailDisplay(Catcher catcher)
+ {
+ this.catcher = catcher ?? throw new ArgumentNullException(nameof(catcher));
+
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new[]
+ {
+ dashTrails = new Container { RelativeSizeAxes = Axes.Both },
+ hyperDashTrails = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
+ endGlowSprites = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
+ };
+ }
+
+ ///
+ /// Displays a single end-glow catcher sprite.
+ ///
+ public void DisplayEndGlow()
+ {
+ var endGlow = createTrailSprite(endGlowSprites);
+
+ endGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In);
+ endGlow.ScaleTo(endGlow.Scale * 0.95f).ScaleTo(endGlow.Scale * 1.2f, 1200, Easing.In);
+ endGlow.FadeOut(1200);
+ endGlow.Expire(true);
+ }
+
+ private void displayTrail()
+ {
+ if (!catcher.Dashing && !catcher.HyperDashing)
+ {
+ DisplayTrail = false;
+ return;
+ }
+
+ var sprite = createTrailSprite(catcher.HyperDashing ? hyperDashTrails : dashTrails);
+
+ sprite.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
+ sprite.Expire(true);
+
+ Scheduler.AddDelayed(displayTrail, catcher.HyperDashing ? 25 : 50);
+ }
+
+ private CatcherTrailSprite createTrailSprite(Container target)
+ {
+ var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture;
+
+ var sprite = new CatcherTrailSprite(texture)
+ {
+ Anchor = catcher.Anchor,
+ Scale = catcher.Scale,
+ Blending = BlendingParameters.Additive,
+ RelativePositionAxes = catcher.RelativePositionAxes,
+ Position = catcher.Position
+ };
+
+ target.Add(sprite);
+
+ return sprite;
+ }
+ }
+}