Merge pull request #12580 from peppy/fix-editor-slider-repeat-animation

Fix slider repeats and tails still animating with editor hit animations disabled
This commit is contained in:
Dan Balasescu
2021-04-26 17:36:51 +09:00
committed by GitHub
5 changed files with 71 additions and 46 deletions

View File

@ -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;
}
}
}
}

View File

@ -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;

View File

@ -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;
@ -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,12 @@ 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);
const float final_scale = 1.5f;
Arrow.ScaleTo(Scale * final_scale, animDuration, Easing.Out);
CirclePiece.ScaleTo(Scale * final_scale, animDuration, Easing.Out);
break;
}
}
@ -142,18 +151,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);
}
}
}

View File

@ -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)
{

View File

@ -0,0 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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; }
}
}