1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-20 19:23:22 +08:00

Remove use of Loop (and transforms) for slider repeat arrow animations

Less transforms in gameplay is always better.

This fixes repeat arrows animating completely incorrectly in the editor
(and probably gameplay when rewinding).
This commit is contained in:
Dean Herbert 2025-01-02 18:36:58 +09:00
parent 1cb2c86104
commit 794765ba85
No known key found for this signature in database
3 changed files with 58 additions and 82 deletions

View File

@ -5,12 +5,12 @@ using System;
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;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Utils;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -75,44 +75,38 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
accentColour = drawableRepeat.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4), true);
drawableRepeat.ApplyCustomUpdateState += updateStateTransforms;
}
private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state)
protected override void Update()
{
base.Update();
if (Time.Current >= drawableRepeat.HitStateUpdateTime && drawableRepeat.State.Value == ArmedState.Hit)
{
double animDuration = Math.Min(300, drawableRepeat.HitObject.SpanDuration);
Scale = new Vector2(Interpolation.ValueAt(Time.Current, 1, 1.5f, drawableRepeat.HitStateUpdateTime, drawableRepeat.HitStateUpdateTime + animDuration, Easing.Out));
}
else
Scale = Vector2.One;
const float move_distance = -12;
const float scale_amount = 1.3f;
const double move_out_duration = 35;
const double move_in_duration = 250;
const double total = 300;
switch (state)
{
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;
double loopCurrentTime = (Time.Current - drawableRepeat.AnimationStartTime.Value) % total;
case ArmedState.Hit:
double animDuration = Math.Min(300, drawableRepeat.HitObject.SpanDuration);
this.ScaleTo(1.5f, animDuration, Easing.Out);
break;
}
}
if (loopCurrentTime < move_out_duration)
main.Scale = new Vector2(Interpolation.ValueAt(loopCurrentTime, 1, scale_amount, 0, move_out_duration, Easing.Out));
else
main.Scale = new Vector2(Interpolation.ValueAt(loopCurrentTime, scale_amount, 1f, move_out_duration, move_out_duration + move_in_duration, Easing.Out));
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (drawableRepeat.IsNotNull())
drawableRepeat.ApplyCustomUpdateState -= updateStateTransforms;
if (loopCurrentTime < move_out_duration)
side.X = Interpolation.ValueAt(loopCurrentTime, 1, move_distance, 0, move_out_duration, Easing.Out);
else
side.X = Interpolation.ValueAt(loopCurrentTime, move_distance, 1f, move_out_duration, move_out_duration + move_in_duration, Easing.Out);
}
}
}

View File

@ -3,10 +3,10 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -40,37 +40,31 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
private void load(DrawableHitObject drawableObject)
{
drawableRepeat = (DrawableSliderRepeat)drawableObject;
drawableRepeat.ApplyCustomUpdateState += updateStateTransforms;
}
private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state)
protected override void Update()
{
const double move_out_duration = 35;
const double move_in_duration = 250;
const double total = 300;
base.Update();
switch (state)
if (Time.Current >= drawableRepeat.HitStateUpdateTime && drawableRepeat.State.Value == ArmedState.Hit)
{
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;
case ArmedState.Hit:
double animDuration = Math.Min(300, drawableRepeat.HitObject.SpanDuration);
InternalChild.ScaleTo(1.5f, animDuration, Easing.Out);
break;
double animDuration = Math.Min(300, drawableRepeat.HitObject.SpanDuration);
Scale = new Vector2(Interpolation.ValueAt(Time.Current, 1, 1.5f, drawableRepeat.HitStateUpdateTime, drawableRepeat.HitStateUpdateTime + animDuration, Easing.Out));
}
}
else
{
const float scale_amount = 1.3f;
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
const double move_out_duration = 35;
const double move_in_duration = 250;
const double total = 300;
if (drawableRepeat.IsNotNull())
drawableRepeat.ApplyCustomUpdateState -= updateStateTransforms;
double loopCurrentTime = (Time.Current - drawableRepeat.AnimationStartTime.Value) % total;
if (loopCurrentTime < move_out_duration)
Scale = new Vector2(Interpolation.ValueAt(loopCurrentTime, 1, scale_amount, 0, move_out_duration, Easing.Out));
else
Scale = new Vector2(Interpolation.ValueAt(loopCurrentTime, scale_amount, 1f, move_out_duration, move_out_duration + move_in_duration, Easing.Out));
}
}
}
}

View File

@ -9,10 +9,12 @@ using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
@ -51,8 +53,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
textureIsDefaultSkin = skin is ISkinTransformer transformer && transformer.Skin is DefaultLegacySkin;
drawableObject.ApplyCustomUpdateState += updateStateTransforms;
shouldRotate = skinSource.GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value <= 1;
}
@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
accentColour = drawableRepeat.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(c =>
{
arrow.Colour = textureIsDefaultSkin && c.NewValue.R + c.NewValue.G + c.NewValue.B > (600 / 255f) ? Color4.Black : Color4.White;
arrow.Colour = textureIsDefaultSkin && c.NewValue.R + c.NewValue.G + c.NewValue.B > 600 / 255f ? Color4.Black : Color4.White;
}, true);
}
@ -80,36 +80,25 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
drawableRepeat.DrawableSlider.OverlayElementContainer.Add(proxy);
}
private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state)
protected override void Update()
{
const double duration = 300;
const float rotation = 5.625f;
base.Update();
switch (state)
if (Time.Current >= drawableRepeat.HitStateUpdateTime && drawableRepeat.State.Value == ArmedState.Hit)
{
case ArmedState.Idle:
if (shouldRotate)
{
InternalChild.ScaleTo(1.3f)
.RotateTo(rotation)
.Then()
.ScaleTo(1f, duration)
.RotateTo(-rotation, duration)
.Loop();
}
else
{
InternalChild.ScaleTo(1.3f).Then()
.ScaleTo(1f, duration, Easing.Out)
.Loop();
}
double animDuration = Math.Min(300, drawableRepeat.HitObject.SpanDuration);
arrow.Scale = new Vector2(Interpolation.ValueAt(Time.Current, 1, 1.4f, drawableRepeat.HitStateUpdateTime, drawableRepeat.HitStateUpdateTime + animDuration, Easing.Out));
}
else
{
const double duration = 300;
const float rotation = 5.625f;
break;
double loopCurrentTime = (Time.Current - drawableRepeat.AnimationStartTime.Value) % duration;
case ArmedState.Hit:
double animDuration = Math.Min(300, drawableRepeat.HitObject.SpanDuration);
InternalChild.ScaleTo(1.4f, animDuration, Easing.Out);
break;
if (shouldRotate)
arrow.Rotation = Interpolation.ValueAt(loopCurrentTime, rotation, -rotation, 0, duration);
arrow.Scale = new Vector2(Interpolation.ValueAt(loopCurrentTime, 1.3f, 1, 0, duration));
}
}
@ -120,7 +109,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
if (drawableRepeat.IsNotNull())
{
drawableRepeat.HitObjectApplied -= onHitObjectApplied;
drawableRepeat.ApplyCustomUpdateState -= updateStateTransforms;
}
}
}