mirror of
https://github.com/osukey/osukey.git
synced 2025-08-05 07:33:55 +09:00
Merge branch 'master' into argon-spinner-sides
This commit is contained in:
@ -108,18 +108,23 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
accentColour.BindValueChanged(colour =>
|
||||
{
|
||||
outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4);
|
||||
outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f));
|
||||
innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f));
|
||||
flash.Colour = colour.NewValue;
|
||||
}, true);
|
||||
|
||||
indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true);
|
||||
|
||||
accentColour.BindValueChanged(colour =>
|
||||
{
|
||||
// A colour transform is applied.
|
||||
// Without removing transforms first, when it is rewound it may apply an old colour.
|
||||
outerGradient.ClearTransforms(targetMember: nameof(Colour));
|
||||
outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f));
|
||||
|
||||
outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4);
|
||||
innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f));
|
||||
flash.Colour = colour.NewValue;
|
||||
|
||||
updateStateTransforms(drawableObject, drawableObject.State.Value);
|
||||
}, true);
|
||||
|
||||
drawableObject.ApplyCustomUpdateState += updateStateTransforms;
|
||||
updateStateTransforms(drawableObject, drawableObject.State.Value);
|
||||
}
|
||||
|
||||
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
|
||||
@ -173,11 +178,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
||||
.FadeOut(flash_in_duration);
|
||||
}
|
||||
|
||||
// The flash layer starts white to give the wanted brightness, but is almost immediately
|
||||
// recoloured to the accent colour. This would more correctly be done with two layers (one for the initial flash)
|
||||
// but works well enough with the colour fade.
|
||||
flash.FadeTo(1, flash_in_duration, Easing.OutQuint);
|
||||
flash.FlashColour(accentColour.Value, fade_out_time, Easing.OutQuint);
|
||||
|
||||
this.FadeOut(fade_out_time, Easing.OutQuad);
|
||||
break;
|
||||
|
@ -134,10 +134,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Hit:
|
||||
CircleSprite.FadeOut(legacy_fade_duration, Easing.Out);
|
||||
CircleSprite.FadeOut(legacy_fade_duration);
|
||||
CircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||
|
||||
OverlaySprite.FadeOut(legacy_fade_duration, Easing.Out);
|
||||
OverlaySprite.FadeOut(legacy_fade_duration);
|
||||
OverlaySprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||
|
||||
if (hasNumber)
|
||||
@ -146,11 +146,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
|
||||
if (legacyVersion >= 2.0m)
|
||||
// legacy skins of version 2.0 and newer only apply very short fade out to the number piece.
|
||||
hitCircleText.FadeOut(legacy_fade_duration / 4, Easing.Out);
|
||||
hitCircleText.FadeOut(legacy_fade_duration / 4);
|
||||
else
|
||||
{
|
||||
// old skins scale and fade it normally along other pieces.
|
||||
hitCircleText.FadeOut(legacy_fade_duration, Easing.Out);
|
||||
hitCircleText.FadeOut(legacy_fade_duration);
|
||||
hitCircleText.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||
}
|
||||
}
|
||||
|
@ -107,8 +107,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt))
|
||||
this.FadeOut();
|
||||
|
||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimeFadeIn / 2))
|
||||
this.FadeInFromZero(spinner.TimeFadeIn / 2);
|
||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimeFadeIn))
|
||||
this.FadeInFromZero(spinner.TimeFadeIn);
|
||||
|
||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt))
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
[Resolved(canBeNull: true)]
|
||||
private DrawableHitObject? parentObject { get; set; }
|
||||
|
||||
public Color4 BallColour => animationContent.Colour;
|
||||
|
||||
private Sprite layerNd = null!;
|
||||
private Sprite layerSpec = null!;
|
||||
|
||||
@ -61,6 +64,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
};
|
||||
}
|
||||
|
||||
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -69,6 +74,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
parentObject.ApplyCustomUpdateState += updateStateTransforms;
|
||||
updateStateTransforms(parentObject, parentObject.State.Value);
|
||||
|
||||
if (skin.GetConfig<SkinConfiguration.LegacySetting, bool>(SkinConfiguration.LegacySetting.AllowSliderBallTint)?.Value == true)
|
||||
{
|
||||
accentColour.BindTo(parentObject.AccentColour);
|
||||
accentColour.BindValueChanged(a => animationContent.Colour = a.NewValue, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
spin = new Sprite
|
||||
{
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
Texture = source.GetTexture("spinner-spin"),
|
||||
@ -82,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
},
|
||||
bonusCounter = new LegacySpriteText(LegacyFont.Score)
|
||||
{
|
||||
Alpha = 0f,
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(SPRITE_SCALE),
|
||||
@ -179,6 +180,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
spmCounter.MoveToOffset(new Vector2(0, -spm_hide_offset), d.HitObject.TimeFadeIn, Easing.Out);
|
||||
}
|
||||
|
||||
using (BeginAbsoluteSequence(d.HitObject.StartTime - d.HitObject.TimeFadeIn / 2))
|
||||
spin.FadeInFromZero(d.HitObject.TimeFadeIn / 2);
|
||||
|
||||
using (BeginAbsoluteSequence(d.HitObject.StartTime))
|
||||
ApproachCircle?.ScaleTo(SPRITE_SCALE * 0.1f, d.HitObject.Duration);
|
||||
|
||||
|
@ -9,7 +9,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
SliderBorderSize,
|
||||
SliderPathRadius,
|
||||
AllowSliderBallTint,
|
||||
CursorCentre,
|
||||
CursorExpand,
|
||||
CursorRotate,
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -22,8 +23,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
public abstract class SmokeSegment : Drawable, ITexturedShaderDrawable
|
||||
{
|
||||
private const int max_point_count = 18_000;
|
||||
|
||||
// fade anim values
|
||||
private const double initial_fade_out_duration = 4000;
|
||||
|
||||
@ -85,12 +84,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
totalDistance = pointInterval;
|
||||
}
|
||||
|
||||
private Vector2 nextPointDirection()
|
||||
{
|
||||
float angle = RNG.NextSingle(0, 2 * MathF.PI);
|
||||
return new Vector2(MathF.Sin(angle), -MathF.Cos(angle));
|
||||
}
|
||||
|
||||
public void AddPosition(Vector2 position, double time)
|
||||
{
|
||||
lastPosition ??= position;
|
||||
@ -107,33 +100,27 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
Vector2 pointPos = (pointInterval - (totalDistance - delta)) * increment + (Vector2)lastPosition;
|
||||
increment *= pointInterval;
|
||||
|
||||
if (SmokePoints.Count > 0 && SmokePoints[^1].Time > time)
|
||||
{
|
||||
int index = ~SmokePoints.BinarySearch(new SmokePoint { Time = time }, new SmokePoint.UpperBoundComparer());
|
||||
SmokePoints.RemoveRange(index, SmokePoints.Count - index);
|
||||
}
|
||||
|
||||
totalDistance %= pointInterval;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
if (SmokePoints.Count == 0 || SmokePoints[^1].Time <= time)
|
||||
{
|
||||
SmokePoints.Add(new SmokePoint
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Position = pointPos,
|
||||
Time = time,
|
||||
Direction = nextPointDirection(),
|
||||
});
|
||||
SmokePoints.Add(new SmokePoint
|
||||
{
|
||||
Position = pointPos,
|
||||
Time = time,
|
||||
Angle = RNG.NextSingle(0, 2 * MathF.PI),
|
||||
});
|
||||
|
||||
pointPos += increment;
|
||||
pointPos += increment;
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
}
|
||||
|
||||
lastPosition = position;
|
||||
|
||||
if (SmokePoints.Count >= max_point_count)
|
||||
FinishDrawing(time);
|
||||
}
|
||||
|
||||
public void FinishDrawing(double time)
|
||||
@ -157,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
public Vector2 Position;
|
||||
public double Time;
|
||||
public Vector2 Direction;
|
||||
public float Angle;
|
||||
|
||||
public struct UpperBoundComparer : IComparer<SmokePoint>
|
||||
{
|
||||
@ -171,6 +158,17 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
return x.Time > target.Time ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public struct LowerBoundComparer : IComparer<SmokePoint>
|
||||
{
|
||||
public int Compare(SmokePoint x, SmokePoint target)
|
||||
{
|
||||
// Similar logic as UpperBoundComparer, except returned index will always be
|
||||
// the first element larger or equal
|
||||
|
||||
return x.Time < target.Time ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class SmokeDrawNode : TexturedShaderDrawNode
|
||||
@ -187,11 +185,11 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
private Vector2 drawSize;
|
||||
private Texture? texture;
|
||||
private int rotationSeed;
|
||||
private int rotationIndex;
|
||||
private int firstVisiblePointIndex;
|
||||
|
||||
// anim calculation vars (color, scale, direction)
|
||||
private double initialFadeOutDurationTrunc;
|
||||
private double firstVisiblePointTime;
|
||||
private double firstVisiblePointTimeAfterSmokeEnded;
|
||||
|
||||
private double initialFadeOutTime;
|
||||
private double reFadeInTime;
|
||||
@ -206,9 +204,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
base.ApplyState();
|
||||
|
||||
points.Clear();
|
||||
points.AddRange(Source.SmokePoints);
|
||||
|
||||
radius = Source.radius;
|
||||
drawSize = Source.DrawSize;
|
||||
texture = Source.Texture;
|
||||
@ -220,11 +215,18 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
rotationSeed = Source.rotationSeed;
|
||||
|
||||
initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime);
|
||||
firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc;
|
||||
firstVisiblePointTimeAfterSmokeEnded = SmokeEndTime - initialFadeOutDurationTrunc;
|
||||
|
||||
initialFadeOutTime = CurrentTime;
|
||||
reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / re_fade_in_speed);
|
||||
finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / final_fade_out_speed);
|
||||
initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime);
|
||||
reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / re_fade_in_speed);
|
||||
finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / final_fade_out_speed);
|
||||
|
||||
double firstVisiblePointTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc;
|
||||
firstVisiblePointIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisiblePointTime }, new SmokePoint.LowerBoundComparer());
|
||||
int futurePointIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer());
|
||||
|
||||
points.Clear();
|
||||
points.AddRange(Source.SmokePoints.Skip(firstVisiblePointIndex).Take(futurePointIndex - firstVisiblePointIndex));
|
||||
}
|
||||
|
||||
public sealed override void Draw(IRenderer renderer)
|
||||
@ -234,9 +236,14 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
if (points.Count == 0)
|
||||
return;
|
||||
|
||||
rotationIndex = 0;
|
||||
quadBatch ??= renderer.CreateQuadBatch<TexturedVertex2D>(200, 4);
|
||||
|
||||
if (points.Count > quadBatch.Size && quadBatch.Size != IRenderer.MAX_QUADS)
|
||||
{
|
||||
int batchSize = Math.Min(quadBatch.Size * 2, IRenderer.MAX_QUADS);
|
||||
quadBatch = renderer.CreateQuadBatch<TexturedVertex2D>(batchSize, 4);
|
||||
}
|
||||
|
||||
quadBatch ??= renderer.CreateQuadBatch<TexturedVertex2D>(max_point_count / 10, 10);
|
||||
texture ??= renderer.WhitePixel;
|
||||
RectangleF textureRect = texture.GetTextureRect();
|
||||
|
||||
@ -248,8 +255,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
shader.Bind();
|
||||
texture.Bind();
|
||||
|
||||
foreach (var point in points)
|
||||
drawPointQuad(point, textureRect);
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
drawPointQuad(points[i], textureRect, i + firstVisiblePointIndex);
|
||||
|
||||
shader.Unbind();
|
||||
renderer.PopLocalMatrix();
|
||||
@ -263,30 +270,34 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
var color = Color4.White;
|
||||
|
||||
double timeDoingInitialFadeOut = Math.Min(initialFadeOutTime, SmokeEndTime) - point.Time;
|
||||
double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed;
|
||||
|
||||
if (timeDoingInitialFadeOut > 0)
|
||||
if (timeDoingFinalFadeOut > 0 && point.Time >= firstVisiblePointTimeAfterSmokeEnded)
|
||||
{
|
||||
float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1);
|
||||
color.A = (1 - fraction) * initial_alpha;
|
||||
float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1);
|
||||
fraction = MathF.Pow(fraction, 5);
|
||||
color.A = (1 - fraction) * re_fade_in_alpha;
|
||||
}
|
||||
|
||||
if (color.A > 0)
|
||||
else
|
||||
{
|
||||
double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed;
|
||||
double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed;
|
||||
double timeDoingInitialFadeOut = initialFadeOutTime - point.Time;
|
||||
|
||||
if (timeDoingFinalFadeOut > 0)
|
||||
if (timeDoingInitialFadeOut > 0)
|
||||
{
|
||||
float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1);
|
||||
fraction = MathF.Pow(fraction, 5);
|
||||
color.A = (1 - fraction) * re_fade_in_alpha;
|
||||
float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1);
|
||||
color.A = (1 - fraction) * initial_alpha;
|
||||
}
|
||||
else if (timeDoingReFadeIn > 0)
|
||||
|
||||
if (point.Time > firstVisiblePointTimeAfterSmokeEnded)
|
||||
{
|
||||
float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1);
|
||||
fraction = 1 - MathF.Pow(1 - fraction, 5);
|
||||
color.A = fraction * (re_fade_in_alpha - color.A) + color.A;
|
||||
double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed;
|
||||
|
||||
if (timeDoingReFadeIn > 0)
|
||||
{
|
||||
float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1);
|
||||
fraction = 1 - MathF.Pow(1 - fraction, 5);
|
||||
color.A = fraction * (re_fade_in_alpha - color.A) + color.A;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,33 +312,33 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
return fraction * (final_scale - initial_scale) + initial_scale;
|
||||
}
|
||||
|
||||
protected virtual Vector2 PointDirection(SmokePoint point)
|
||||
protected virtual Vector2 PointDirection(SmokePoint point, int index)
|
||||
{
|
||||
float initialAngle = MathF.Atan2(point.Direction.Y, point.Direction.X);
|
||||
float finalAngle = initialAngle + nextRotation();
|
||||
|
||||
double timeDoingRotation = CurrentTime - point.Time;
|
||||
float fraction = Math.Clamp((float)(timeDoingRotation / rotation_duration), 0, 1);
|
||||
fraction = 1 - MathF.Pow(1 - fraction, 5);
|
||||
float angle = fraction * (finalAngle - initialAngle) + initialAngle;
|
||||
float angle = fraction * getRotation(index) + point.Angle;
|
||||
|
||||
return new Vector2(MathF.Sin(angle), -MathF.Cos(angle));
|
||||
}
|
||||
|
||||
private float nextRotation() => max_rotation * (StatelessRNG.NextSingle(rotationSeed, rotationIndex++) * 2 - 1);
|
||||
private float getRotation(int index) => max_rotation * (StatelessRNG.NextSingle(rotationSeed, index) * 2 - 1);
|
||||
|
||||
private void drawPointQuad(SmokePoint point, RectangleF textureRect)
|
||||
private void drawPointQuad(SmokePoint point, RectangleF textureRect, int index)
|
||||
{
|
||||
Debug.Assert(quadBatch != null);
|
||||
|
||||
var colour = PointColour(point);
|
||||
float scale = PointScale(point);
|
||||
var dir = PointDirection(point);
|
||||
var ortho = dir.PerpendicularLeft;
|
||||
|
||||
if (colour.A == 0 || scale == 0)
|
||||
if (colour.A == 0)
|
||||
return;
|
||||
|
||||
float scale = PointScale(point);
|
||||
if (scale == 0)
|
||||
return;
|
||||
|
||||
var dir = PointDirection(point, index);
|
||||
var ortho = dir.PerpendicularLeft;
|
||||
|
||||
var localTopLeft = point.Position + (radius * scale * (-ortho - dir));
|
||||
var localTopRight = point.Position + (radius * scale * (-ortho + dir));
|
||||
var localBotLeft = point.Position + (radius * scale * (ortho - dir));
|
||||
|
Reference in New Issue
Block a user