mirror of
https://github.com/ppy/osu.git
synced 2025-03-21 21:47:20 +08:00
commit
8bc5729f5f
@ -1 +1 @@
|
||||
Subproject commit 7ca1719b5cdc8b0a9600abe6472b38a426abedb0
|
||||
Subproject commit 7b2f4dfce7894ca7dea7626dcc34bcc32df651b9
|
@ -1,8 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
// Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Modes.Objects.Drawables;
|
||||
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Transformations;
|
||||
@ -11,6 +13,9 @@ using osu.Framework.Input;
|
||||
using OpenTK.Graphics.ES30;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Framework.Configuration;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
{
|
||||
@ -49,30 +54,77 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
};
|
||||
}
|
||||
|
||||
private Bindable<bool> snakingIn;
|
||||
private Bindable<bool> snakingOut;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
snakingIn = config.GetBindable<bool>(OsuConfig.SnakingInSliders);
|
||||
snakingOut = config.GetBindable<bool>(OsuConfig.SnakingOutSliders);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
//force application of the state that was set before we loaded.
|
||||
UpdateState(State);
|
||||
|
||||
body.PathWidth = 32;
|
||||
}
|
||||
|
||||
private void computeProgress(out int repeat, out double progress)
|
||||
{
|
||||
progress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
||||
|
||||
repeat = (int)(progress * slider.RepeatCount);
|
||||
progress = (progress * slider.RepeatCount) % 1;
|
||||
|
||||
if (repeat % 2 == 1)
|
||||
progress = 1 - progress;
|
||||
}
|
||||
|
||||
private void updateBall(double progress)
|
||||
{
|
||||
ball.Alpha = Time.Current >= slider.StartTime && Time.Current <= slider.EndTime ? 1 : 0;
|
||||
ball.Position = slider.Curve.PositionAt(progress);
|
||||
}
|
||||
|
||||
private void updateBody(int repeat, double progress)
|
||||
{
|
||||
double drawStartProgress = 0;
|
||||
double drawEndProgress = MathHelper.Clamp((Time.Current - slider.StartTime + TIME_PREEMPT) / TIME_FADEIN, 0, 1);
|
||||
|
||||
if (repeat >= slider.RepeatCount - 1)
|
||||
{
|
||||
if (Math.Min(repeat, slider.RepeatCount - 1) % 2 == 1)
|
||||
{
|
||||
drawStartProgress = 0;
|
||||
drawEndProgress = progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawStartProgress = progress;
|
||||
drawEndProgress = 1;
|
||||
}
|
||||
}
|
||||
|
||||
body.SetRange(
|
||||
snakingOut ? drawStartProgress : 0,
|
||||
snakingIn ? drawEndProgress : 1);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
ball.Alpha = Time.Current >= slider.StartTime && Time.Current <= slider.EndTime ? 1 : 0;
|
||||
double progress;
|
||||
int repeat;
|
||||
computeProgress(out repeat, out progress);
|
||||
|
||||
double t = (Time.Current - slider.StartTime) / slider.Duration;
|
||||
if (slider.RepeatCount > 1)
|
||||
{
|
||||
int currentRepeat = (int)(t * slider.RepeatCount);
|
||||
t = (t * slider.RepeatCount) % 1;
|
||||
if (currentRepeat % 2 == 1)
|
||||
t = 1 - t;
|
||||
}
|
||||
|
||||
ball.Position = slider.Curve.PositionAt(t);
|
||||
updateBall(progress);
|
||||
updateBody(repeat, progress);
|
||||
}
|
||||
|
||||
protected override void CheckJudgement(bool userTriggered)
|
||||
@ -187,7 +239,14 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
private Path path;
|
||||
private BufferedContainer container;
|
||||
|
||||
private double? drawnProgress;
|
||||
public float PathWidth
|
||||
{
|
||||
get { return path.PathWidth; }
|
||||
set { path.PathWidth = value; }
|
||||
}
|
||||
|
||||
private double? drawnProgressStart;
|
||||
private double? drawnProgressEnd;
|
||||
|
||||
private Slider slider;
|
||||
public Body(Slider s)
|
||||
@ -221,69 +280,38 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
|
||||
path.Texture = textures.Get(@"Menu/logo");
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
public void SetRange(double p0, double p1)
|
||||
{
|
||||
base.LoadComplete();
|
||||
path.PathWidth = 32;
|
||||
}
|
||||
if (p0 > p1)
|
||||
MathHelper.Swap(ref p0, ref p1);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (updateSnaking())
|
||||
if (updateSnaking(p0, p1))
|
||||
{
|
||||
// Autosizing does not give us the desired behaviour here.
|
||||
// We want the container to have the same size as the slider,
|
||||
// and to be positioned such that the slider head is at (0,0).
|
||||
container.Size = path.Size;
|
||||
container.Position = -path.HeadPosition;
|
||||
container.Position = -path.PositionInBoundingBox(slider.Curve.PositionAt(0) - currentCurve[0]);
|
||||
|
||||
container.ForceRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
private bool updateSnaking()
|
||||
private List<Vector2> currentCurve = new List<Vector2>();
|
||||
private bool updateSnaking(double p0, double p1)
|
||||
{
|
||||
double progress = MathHelper.Clamp((Time.Current - slider.StartTime + TIME_PREEMPT) / TIME_FADEIN, 0, 1);
|
||||
if (drawnProgressStart == p0 && drawnProgressEnd == p1) return false;
|
||||
|
||||
if (progress == drawnProgress) return false;
|
||||
drawnProgressStart = p0;
|
||||
drawnProgressEnd = p1;
|
||||
|
||||
bool madeChanges = false;
|
||||
if (progress == 0)
|
||||
{
|
||||
//if we have gone backwards, just clear the path for now.
|
||||
drawnProgress = 0;
|
||||
path.ClearVertices();
|
||||
madeChanges = true;
|
||||
}
|
||||
slider.Curve.GetPathToProgress(currentCurve, p0, p1);
|
||||
|
||||
Vector2 startPosition = slider.Curve.PositionAt(0);
|
||||
path.ClearVertices();
|
||||
foreach (Vector2 p in currentCurve)
|
||||
path.AddVertex(p - currentCurve[0]);
|
||||
|
||||
if (drawnProgress == null)
|
||||
{
|
||||
drawnProgress = 0;
|
||||
path.AddVertex(slider.Curve.PositionAt(drawnProgress.Value) - startPosition);
|
||||
madeChanges = true;
|
||||
}
|
||||
|
||||
double segmentSize = 1 / (slider.Curve.Length / 5);
|
||||
|
||||
while (drawnProgress + segmentSize < progress)
|
||||
{
|
||||
drawnProgress += segmentSize;
|
||||
path.AddVertex(slider.Curve.PositionAt(drawnProgress.Value) - startPosition);
|
||||
madeChanges = true;
|
||||
}
|
||||
|
||||
if (progress == 1 && drawnProgress != progress)
|
||||
{
|
||||
drawnProgress = progress;
|
||||
path.AddVertex(slider.Curve.PositionAt(drawnProgress.Value) - startPosition);
|
||||
madeChanges = true;
|
||||
}
|
||||
|
||||
return madeChanges;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
// Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.MathUtils;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Modes.Osu.Objects
|
||||
{
|
||||
@ -11,7 +18,8 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
|
||||
public CurveTypes CurveType;
|
||||
|
||||
private List<Vector2> calculatedPath;
|
||||
private List<Vector2> calculatedPath = new List<Vector2>();
|
||||
private List<double> cumulativeLength = new List<double>();
|
||||
|
||||
private List<Vector2> calculateSubpath(List<Vector2> subpath)
|
||||
{
|
||||
@ -24,9 +32,9 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
}
|
||||
}
|
||||
|
||||
public void Calculate()
|
||||
private void calculatePath()
|
||||
{
|
||||
calculatedPath = new List<Vector2>();
|
||||
calculatedPath.Clear();
|
||||
|
||||
// Sliders may consist of various subpaths separated by two consecutive vertices
|
||||
// with the same position. The following loop parses these subpaths and computes
|
||||
@ -50,18 +58,126 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateCumulativeLengthAndTrimPath()
|
||||
{
|
||||
double l = 0;
|
||||
|
||||
cumulativeLength.Clear();
|
||||
cumulativeLength.Add(l);
|
||||
|
||||
for (int i = 0; i < calculatedPath.Count - 1; ++i)
|
||||
{
|
||||
Vector2 diff = calculatedPath[i + 1] - calculatedPath[i];
|
||||
double d = diff.Length;
|
||||
|
||||
// Shorten slider curves that are too long compared to what's
|
||||
// in the .osu file.
|
||||
if (Length - l < d)
|
||||
{
|
||||
calculatedPath[i + 1] = calculatedPath[i] + diff * (float)((Length - l) / d);
|
||||
calculatedPath.RemoveRange(i + 2, calculatedPath.Count - 2 - i);
|
||||
|
||||
l = Length;
|
||||
cumulativeLength.Add(l);
|
||||
break;
|
||||
}
|
||||
|
||||
l += d;
|
||||
cumulativeLength.Add(l);
|
||||
}
|
||||
|
||||
// Lengthen slider curves that are too short compared to what's
|
||||
// in the .osu file.
|
||||
if (l < Length && calculatedPath.Count > 1)
|
||||
{
|
||||
Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2];
|
||||
double d = diff.Length;
|
||||
|
||||
if (d <= 0)
|
||||
return;
|
||||
|
||||
calculatedPath[calculatedPath.Count - 1] += diff * (float)((Length - l) / d);
|
||||
cumulativeLength[calculatedPath.Count - 1] = Length;
|
||||
}
|
||||
}
|
||||
|
||||
public void Calculate()
|
||||
{
|
||||
calculatePath();
|
||||
calculateCumulativeLengthAndTrimPath();
|
||||
}
|
||||
|
||||
private int indexOfDistance(double d)
|
||||
{
|
||||
int i = cumulativeLength.BinarySearch(d);
|
||||
if (i < 0) i = ~i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
private double progressToDistance(double progress)
|
||||
{
|
||||
return MathHelper.Clamp(progress, 0, 1) * Length;
|
||||
}
|
||||
|
||||
private Vector2 interpolateVertices(int i, double d)
|
||||
{
|
||||
if (calculatedPath.Count == 0)
|
||||
return Vector2.Zero;
|
||||
|
||||
if (i <= 0)
|
||||
return calculatedPath.First();
|
||||
else if (i >= calculatedPath.Count)
|
||||
return calculatedPath.Last();
|
||||
|
||||
Vector2 p0 = calculatedPath[i - 1];
|
||||
Vector2 p1 = calculatedPath[i];
|
||||
|
||||
double d0 = cumulativeLength[i - 1];
|
||||
double d1 = cumulativeLength[i];
|
||||
|
||||
// Avoid division by and almost-zero number in case two points are extremely close to each other.
|
||||
if (Precision.AlmostEquals(d0, d1))
|
||||
return p0;
|
||||
|
||||
double w = (d - d0) / (d1 - d0);
|
||||
return p0 + (p1 - p0) * (float)w;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the slider curve until a given progress that ranges from 0 (beginning of the slider)
|
||||
/// to 1 (end of the slider) and stores the generated path in the given list.
|
||||
/// </summary>
|
||||
/// <param name="path">The list to be filled with the computed curve.</param>
|
||||
/// <param name="progress">Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param>
|
||||
public void GetPathToProgress(List<Vector2> path, double p0, double p1)
|
||||
{
|
||||
double d0 = progressToDistance(p0);
|
||||
double d1 = progressToDistance(p1);
|
||||
|
||||
path.Clear();
|
||||
|
||||
int i = 0;
|
||||
for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i);
|
||||
|
||||
path.Add(interpolateVertices(i, d0));
|
||||
|
||||
for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i)
|
||||
path.Add(calculatedPath[i]);
|
||||
|
||||
path.Add(interpolateVertices(i, d1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the position on the slider at a given progress that ranges from 0 (beginning of the slider)
|
||||
/// to 1 (end of the slider).
|
||||
/// </summary>
|
||||
/// <param name="progress">Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param>
|
||||
/// <returns></returns>
|
||||
public Vector2 PositionAt(double progress)
|
||||
{
|
||||
progress = MathHelper.Clamp(progress, 0, 1);
|
||||
|
||||
double index = progress * (calculatedPath.Count - 1);
|
||||
int flooredIndex = (int)index;
|
||||
|
||||
Vector2 pos = calculatedPath[flooredIndex];
|
||||
if (index != flooredIndex)
|
||||
pos += (calculatedPath[flooredIndex + 1] - pos) * (float)(index - flooredIndex);
|
||||
|
||||
return pos;
|
||||
double d = progressToDistance(progress);
|
||||
return interpolateVertices(indexOfDistance(d), d);
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
double mult = 1;
|
||||
|
||||
if (applyMultipliers && samplePoint > point && ControlPoints[samplePoint].BeatLength < 0)
|
||||
if (applyMultipliers && samplePoint > point)
|
||||
mult = ControlPoints[samplePoint].VelocityAdjustment;
|
||||
|
||||
return ControlPoints[point].BeatLength * mult;
|
||||
|
@ -4,12 +4,10 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
class OsuConfigManager : ConfigManager<OsuConfig>
|
||||
public class OsuConfigManager : ConfigManager<OsuConfig>
|
||||
{
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
@ -129,7 +127,8 @@ namespace osu.Game.Configuration
|
||||
//Set(OsuConfig.Skin, SkinManager.DEFAULT_SKIN);
|
||||
Set(OsuConfig.SkinSamples, true);
|
||||
Set(OsuConfig.SkipTablet, false);
|
||||
Set(OsuConfig.SnakingSliders, true);
|
||||
Set(OsuConfig.SnakingInSliders, true);
|
||||
Set(OsuConfig.SnakingOutSliders, false);
|
||||
Set(OsuConfig.Tablet, false);
|
||||
Set(OsuConfig.UpdatePending, false);
|
||||
Set(OsuConfig.UseSkinCursor, false);
|
||||
@ -189,7 +188,7 @@ namespace osu.Game.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
enum OsuConfig
|
||||
public enum OsuConfig
|
||||
{
|
||||
// New osu:
|
||||
PlayMode,
|
||||
@ -303,7 +302,8 @@ namespace osu.Game.Configuration
|
||||
Skin,
|
||||
SkinSamples,
|
||||
SkipTablet,
|
||||
SnakingSliders,
|
||||
SnakingInSliders,
|
||||
SnakingOutSliders,
|
||||
Tablet,
|
||||
UpdatePending,
|
||||
UserFilter,
|
||||
@ -345,5 +345,6 @@ namespace osu.Game.Configuration
|
||||
Ticker,
|
||||
CompatibilityContext,
|
||||
CanForceOptimusCompatibility,
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -87,9 +87,9 @@ namespace osu.Game.Modes.Objects.Drawables
|
||||
//todo: consider making abstract.
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.Update();
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
UpdateJudgement(false);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System;
|
||||
// Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.GameModes;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -15,11 +15,7 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Processing;
|
||||
using osu.Game.IPC;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game
|
||||
{
|
||||
|
@ -1,8 +1,9 @@
|
||||
using osu.Framework;
|
||||
// Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Overlays.Options.Graphics
|
||||
@ -18,8 +19,13 @@ namespace osu.Game.Overlays.Options.Graphics
|
||||
{
|
||||
new CheckBoxOption
|
||||
{
|
||||
LabelText = "Snaking sliders",
|
||||
Bindable = config.GetBindable<bool>(OsuConfig.SnakingSliders)
|
||||
LabelText = "Snaking in sliders",
|
||||
Bindable = config.GetBindable<bool>(OsuConfig.SnakingInSliders)
|
||||
},
|
||||
new CheckBoxOption
|
||||
{
|
||||
LabelText = "Snaking out sliders",
|
||||
Bindable = config.GetBindable<bool>(OsuConfig.SnakingOutSliders)
|
||||
},
|
||||
new CheckBoxOption
|
||||
{
|
||||
|
@ -106,9 +106,9 @@ namespace osu.Game.Overlays.Toolbar
|
||||
|
||||
private Cached activeMode = new Cached();
|
||||
|
||||
protected override void UpdateLayout()
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateLayout();
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
if (!activeMode.EnsureValid())
|
||||
activeMode.Refresh(() => modeButtonLine.MoveToX(activeButton.DrawPosition.X, 200, EasingTypes.OutQuint));
|
||||
|
Loading…
x
Reference in New Issue
Block a user