mirror of
https://github.com/ppy/osu.git
synced 2024-12-28 05:02:56 +08:00
106 lines
3.6 KiB
C#
106 lines
3.6 KiB
C#
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
|||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using osu.Framework.Allocation;
|
|||
|
using osu.Framework.Configuration;
|
|||
|
using osu.Game.Rulesets.Objects.Types;
|
|||
|
using OpenTK;
|
|||
|
|
|||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// A <see cref="SliderBody"/> which changes its curve depending on the snaking progress.
|
|||
|
/// </summary>
|
|||
|
public class SnakingSliderBody : SliderBody, ISliderProgress
|
|||
|
{
|
|||
|
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
|
|||
|
|
|||
|
public readonly Bindable<bool> SnakingIn = new Bindable<bool>();
|
|||
|
public readonly Bindable<bool> SnakingOut = new Bindable<bool>();
|
|||
|
|
|||
|
public double? SnakedStart { get; private set; }
|
|||
|
public double? SnakedEnd { get; private set; }
|
|||
|
|
|||
|
public override Vector2 PathOffset => snakedPathOffset;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The top-left position of the path when fully snaked.
|
|||
|
/// </summary>
|
|||
|
private Vector2 snakedPosition;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The offset of the path from <see cref="snakedPosition"/> when fully snaked.
|
|||
|
/// </summary>
|
|||
|
private Vector2 snakedPathOffset;
|
|||
|
|
|||
|
private readonly Slider slider;
|
|||
|
|
|||
|
public SnakingSliderBody(Slider slider)
|
|||
|
{
|
|||
|
this.slider = slider;
|
|||
|
}
|
|||
|
|
|||
|
[BackgroundDependencyLoader]
|
|||
|
private void load()
|
|||
|
{
|
|||
|
// Generate the entire curve
|
|||
|
slider.Curve.GetPathToProgress(CurrentCurve, 0, 1);
|
|||
|
SetVertices(CurrentCurve);
|
|||
|
|
|||
|
// The body is sized to the full path size to avoid excessive autosize computations
|
|||
|
Size = Path.Size;
|
|||
|
|
|||
|
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
|
|||
|
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
|
|||
|
}
|
|||
|
|
|||
|
public void UpdateProgress(double completionProgress)
|
|||
|
{
|
|||
|
var span = slider.SpanAt(completionProgress);
|
|||
|
var spanProgress = slider.ProgressAt(completionProgress);
|
|||
|
|
|||
|
double start = 0;
|
|||
|
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
|
|||
|
|
|||
|
if (span >= slider.SpanCount() - 1)
|
|||
|
{
|
|||
|
if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1)
|
|||
|
{
|
|||
|
start = 0;
|
|||
|
end = SnakingOut ? spanProgress : 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
start = SnakingOut ? spanProgress : 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
setRange(start, end);
|
|||
|
}
|
|||
|
|
|||
|
private void setRange(double p0, double p1)
|
|||
|
{
|
|||
|
if (p0 > p1)
|
|||
|
MathHelper.Swap(ref p0, ref p1);
|
|||
|
|
|||
|
if (SnakedStart == p0 && SnakedEnd == p1) return;
|
|||
|
|
|||
|
SnakedStart = p0;
|
|||
|
SnakedEnd = p1;
|
|||
|
|
|||
|
slider.Curve.GetPathToProgress(CurrentCurve, p0, p1);
|
|||
|
|
|||
|
SetVertices(CurrentCurve);
|
|||
|
|
|||
|
// The bounding box of the path expands as it snakes, which in turn shifts the position of the path.
|
|||
|
// Depending on the direction of expansion, it may appear as if the path is expanding towards the position of the slider
|
|||
|
// rather than expanding out from the position of the slider.
|
|||
|
// To remove this effect, the path's position is shifted towards its final snaked position
|
|||
|
|
|||
|
Path.Position = snakedPosition - Path.PositionInBoundingBox(Vector2.Zero);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|