Merge pull request #10700 from peppy/add-spinner-spin

Add support for spinner "spin" text in legacy skins
This commit is contained in:
Dan Balasescu 2020-11-06 16:13:44 +09:00 committed by GitHub
commit ca94d93d29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 94 deletions

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
/// Legacy skinned spinner with two main spinning layers, one fixed overlay and one final spinning overlay.
/// No background layer.
/// </summary>
public class LegacyNewStyleSpinner : CompositeDrawable
public class LegacyNewStyleSpinner : LegacySpinner
{
private Sprite glow;
private Sprite discBottom;
@ -27,66 +27,61 @@ namespace osu.Game.Rulesets.Osu.Skinning
private Sprite spinningMiddle;
private Sprite fixedMiddle;
private DrawableSpinner drawableSpinner;
private const float final_scale = 0.625f;
private readonly Color4 glowColour = new Color4(3, 151, 255, 255);
private Container scaleContainer;
[BackgroundDependencyLoader]
private void load(ISkinSource source, DrawableHitObject drawableObject)
private void load(ISkinSource source)
{
drawableSpinner = (DrawableSpinner)drawableObject;
Scale = new Vector2(final_scale);
InternalChildren = new Drawable[]
AddInternal(scaleContainer = new Container
{
glow = new Sprite
Scale = new Vector2(SPRITE_SCALE),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-glow"),
Blending = BlendingParameters.Additive,
Colour = glowColour,
},
discBottom = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-bottom")
},
discTop = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-top")
},
fixedMiddle = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-middle")
},
spinningMiddle = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-middle2")
glow = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-glow"),
Blending = BlendingParameters.Additive,
Colour = glowColour,
},
discBottom = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-bottom")
},
discTop = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-top")
},
fixedMiddle = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-middle")
},
spinningMiddle = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-middle2")
}
}
};
});
}
protected override void LoadComplete()
protected override void UpdateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{
base.LoadComplete();
base.UpdateStateTransforms(drawableHitObject, state);
drawableSpinner.ApplyCustomUpdateState += updateStateTransforms;
updateStateTransforms(drawableSpinner, drawableSpinner.State.Value);
}
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{
switch (drawableHitObject)
{
case DrawableSpinner d:
@ -125,20 +120,12 @@ namespace osu.Game.Rulesets.Osu.Skinning
protected override void Update()
{
base.Update();
spinningMiddle.Rotation = discTop.Rotation = drawableSpinner.RotationTracker.Rotation;
spinningMiddle.Rotation = discTop.Rotation = DrawableSpinner.RotationTracker.Rotation;
discBottom.Rotation = discTop.Rotation / 3;
glow.Alpha = drawableSpinner.Progress;
glow.Alpha = DrawableSpinner.Progress;
Scale = new Vector2(final_scale * (0.8f + (float)Interpolation.ApplyEasing(Easing.Out, drawableSpinner.Progress) * 0.2f));
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (drawableSpinner != null)
drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms;
scaleContainer.Scale = new Vector2(SPRITE_SCALE * (0.8f + (float)Interpolation.ApplyEasing(Easing.Out, DrawableSpinner.Progress) * 0.2f));
}
}
}

View File

@ -18,28 +18,22 @@ namespace osu.Game.Rulesets.Osu.Skinning
/// <summary>
/// Legacy skinned spinner with one main spinning layer and a background layer.
/// </summary>
public class LegacyOldStyleSpinner : CompositeDrawable
public class LegacyOldStyleSpinner : LegacySpinner
{
private DrawableSpinner drawableSpinner;
private Sprite disc;
private Sprite metreSprite;
private Container metre;
private bool spinnerBlink;
private const float sprite_scale = 1 / 1.6f;
private const float final_metre_height = 692 * sprite_scale;
private const float final_metre_height = 692 * SPRITE_SCALE;
[BackgroundDependencyLoader]
private void load(ISkinSource source, DrawableHitObject drawableObject)
private void load(ISkinSource source)
{
spinnerBlink = source.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.SpinnerNoBlink)?.Value != true;
drawableSpinner = (DrawableSpinner)drawableObject;
RelativeSizeAxes = Axes.Both;
InternalChild = new Container
AddInternal(new Container
{
// the old-style spinner relied heavily on absolute screen-space coordinate values.
// wrap everything in a container simulating absolute coords to preserve alignment
@ -55,14 +49,14 @@ namespace osu.Game.Rulesets.Osu.Skinning
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-background"),
Scale = new Vector2(sprite_scale)
Scale = new Vector2(SPRITE_SCALE)
},
disc = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-circle"),
Scale = new Vector2(sprite_scale)
Scale = new Vector2(SPRITE_SCALE)
},
metre = new Container
{
@ -78,23 +72,17 @@ namespace osu.Game.Rulesets.Osu.Skinning
Texture = source.GetTexture("spinner-metre"),
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Scale = new Vector2(0.625f)
Scale = new Vector2(SPRITE_SCALE)
}
}
}
};
});
}
protected override void LoadComplete()
protected override void UpdateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{
base.LoadComplete();
base.UpdateStateTransforms(drawableHitObject, state);
drawableSpinner.ApplyCustomUpdateState += updateStateTransforms;
updateStateTransforms(drawableSpinner, drawableSpinner.State.Value);
}
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{
if (!(drawableHitObject is DrawableSpinner d))
return;
@ -110,11 +98,11 @@ namespace osu.Game.Rulesets.Osu.Skinning
protected override void Update()
{
base.Update();
disc.Rotation = drawableSpinner.RotationTracker.Rotation;
disc.Rotation = DrawableSpinner.RotationTracker.Rotation;
// careful: need to call this exactly once for all calculations in a frame
// as the function has a random factor in it
var metreHeight = getMetreHeight(drawableSpinner.Progress);
var metreHeight = getMetreHeight(DrawableSpinner.Progress);
// hack to make the metre blink up from below than down from above.
// move down the container to be able to apply masking for the metre,
@ -140,13 +128,5 @@ namespace osu.Game.Rulesets.Osu.Skinning
return (float)barCount / total_bars * final_metre_height;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (drawableSpinner != null)
drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms;
}
}
}

View File

@ -0,0 +1,84 @@
// 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 System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Osu.Skinning
{
public abstract class LegacySpinner : CompositeDrawable
{
protected const float SPRITE_SCALE = 0.625f;
protected DrawableSpinner DrawableSpinner { get; private set; }
private Sprite spin;
[BackgroundDependencyLoader]
private void load(DrawableHitObject drawableHitObject, ISkinSource source)
{
RelativeSizeAxes = Axes.Both;
DrawableSpinner = (DrawableSpinner)drawableHitObject;
AddRangeInternal(new[]
{
spin = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Depth = float.MinValue,
Texture = source.GetTexture("spinner-spin"),
Scale = new Vector2(SPRITE_SCALE),
Y = 120 - 45 // offset temporarily to avoid overlapping default spin counter
},
});
}
protected override void LoadComplete()
{
base.LoadComplete();
DrawableSpinner.ApplyCustomUpdateState += UpdateStateTransforms;
UpdateStateTransforms(DrawableSpinner, DrawableSpinner.State.Value);
}
protected virtual void UpdateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{
switch (drawableHitObject)
{
case DrawableSpinner d:
double fadeOutLength = Math.Min(400, d.HitObject.Duration);
using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime - fadeOutLength, true))
spin.FadeOutFromOne(fadeOutLength);
break;
case DrawableSpinnerTick d:
if (state == ArmedState.Hit)
{
using (BeginAbsoluteSequence(d.HitStateUpdateTime, true))
spin.FadeOut(300);
}
break;
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (DrawableSpinner != null)
DrawableSpinner.ApplyCustomUpdateState -= UpdateStateTransforms;
}
}
}

View File

@ -546,7 +546,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
var endTime = HitObject.GetEndTime();
Result.TimeOffset = Math.Min(HitObject.HitWindows.WindowFor(HitResult.Miss), Time.Current - endTime);
Result.TimeOffset = Time.Current - endTime;
double missWindow = HitObject.HitWindows.WindowFor(HitResult.Miss);
if (missWindow > 0)
Result.TimeOffset = Math.Min(Result.TimeOffset, missWindow);
if (Result.HasResult)
updateState(Result.IsHit ? ArmedState.Hit : ArmedState.Miss);