mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 12:42:54 +08:00
Merge pull request #1737 from Shawdooow/sliderbouncers-fix
Fix slider repeats playing sample twice
This commit is contained in:
commit
ce48890559
@ -117,11 +117,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
progress = slider.ProgressAt(progress);
|
||||
|
||||
if (repeat > currentRepeat)
|
||||
{
|
||||
if (repeat < slider.RepeatCount && ball.Tracking)
|
||||
PlaySamples();
|
||||
currentRepeat = repeat;
|
||||
}
|
||||
|
||||
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
|
||||
if (!initialCircle.Judgements.Any(j => j.IsHit))
|
||||
@ -171,9 +167,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public override Vector2 SelectionPoint => ToScreenSpace(body.Position);
|
||||
public override Quad SelectionQuad => body.PathDrawQuad;
|
||||
}
|
||||
|
||||
internal interface ISliderProgress
|
||||
{
|
||||
void UpdateProgress(double progress, int repeat);
|
||||
}
|
||||
}
|
||||
|
10
osu.Game.Rulesets.Osu/Objects/ISliderProgress.cs
Normal file
10
osu.Game.Rulesets.Osu/Objects/ISliderProgress.cs
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
public interface ISliderProgress
|
||||
{
|
||||
void UpdateProgress(double progress, int repeat);
|
||||
}
|
||||
}
|
@ -151,28 +151,22 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
private void createRepeatPoints()
|
||||
{
|
||||
var length = Curve.Distance;
|
||||
var repeatPointDistance = Math.Min(Distance, length);
|
||||
var repeatDuration = length / Velocity;
|
||||
var repeatDuration = Distance / Velocity;
|
||||
|
||||
for (var repeat = 1; repeat < RepeatCount; repeat++)
|
||||
{
|
||||
for (var d = repeatPointDistance; d <= length; d += repeatPointDistance)
|
||||
{
|
||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
||||
var distanceProgress = d / length;
|
||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
||||
|
||||
AddNested(new RepeatPoint
|
||||
{
|
||||
RepeatIndex = repeat,
|
||||
StartTime = repeatStartTime,
|
||||
Position = Curve.PositionAt(distanceProgress),
|
||||
StackHeight = StackHeight,
|
||||
Scale = Scale,
|
||||
ComboColour = ComboColour,
|
||||
Samples = new List<SampleInfo>(RepeatSamples[repeat])
|
||||
});
|
||||
}
|
||||
AddNested(new RepeatPoint
|
||||
{
|
||||
RepeatIndex = repeat,
|
||||
StartTime = repeatStartTime,
|
||||
Position = Curve.PositionAt(repeat % 2),
|
||||
StackHeight = StackHeight,
|
||||
Scale = Scale,
|
||||
ComboColour = ComboColour,
|
||||
Samples = new List<SampleInfo>(RepeatSamples[repeat])
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
70
osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs
Normal file
70
osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseHitCircle : OsuTestCase
|
||||
{
|
||||
private readonly Container content;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private bool auto;
|
||||
private int depthIndex;
|
||||
|
||||
public TestCaseHitCircle()
|
||||
{
|
||||
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
|
||||
|
||||
AddStep("Single", () => addSingle());
|
||||
AddStep("Stream", addStream);
|
||||
AddToggleStep("Auto", v => auto = v);
|
||||
}
|
||||
|
||||
private void addSingle(double timeOffset = 0, Vector2? positionOffset = null)
|
||||
{
|
||||
positionOffset = positionOffset ?? Vector2.Zero;
|
||||
|
||||
var circle = new HitCircle
|
||||
{
|
||||
StartTime = Time.Current + 1000 + timeOffset,
|
||||
Position = positionOffset.Value
|
||||
};
|
||||
|
||||
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 0 });
|
||||
|
||||
var drawable = new DrawableHitCircle(circle)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Depth = depthIndex++
|
||||
};
|
||||
|
||||
if (auto)
|
||||
drawable.State.Value = ArmedState.Hit;
|
||||
|
||||
Add(drawable);
|
||||
}
|
||||
|
||||
private void addStream()
|
||||
{
|
||||
Vector2 pos = Vector2.Zero;
|
||||
|
||||
for (int i = 0; i <= 1000; i += 100)
|
||||
{
|
||||
addSingle(i, pos);
|
||||
pos += new Vector2(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseHitObjects : OsuTestCase
|
||||
{
|
||||
private FramedClock framedClock;
|
||||
|
||||
private bool auto;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
var rateAdjustClock = new StopwatchClock(true);
|
||||
framedClock = new FramedClock(rateAdjustClock);
|
||||
|
||||
AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle));
|
||||
AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider));
|
||||
AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
|
||||
|
||||
AddToggleStep("Auto", state => { auto = state; loadHitobjects(mode); });
|
||||
AddSliderStep("Playback speed", 0.0, 2.0, 0.5, v => rateAdjustClock.Rate = v);
|
||||
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
var clockAdjustContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = framedClock,
|
||||
Children = new[]
|
||||
{
|
||||
playfieldContainer = new OsuInputManager(rulesets.GetRuleset(0)) { RelativeSizeAxes = Axes.Both },
|
||||
approachContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
};
|
||||
|
||||
Add(clockAdjustContainer);
|
||||
}
|
||||
|
||||
private HitObjectType mode = HitObjectType.Slider;
|
||||
|
||||
private Container playfieldContainer;
|
||||
private Container approachContainer;
|
||||
|
||||
private void loadHitobjects(HitObjectType mode)
|
||||
{
|
||||
this.mode = mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case HitObjectType.Circle:
|
||||
const int count = 10;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var h = new HitCircle
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600 + i * 80,
|
||||
Position = new Vector2((i - count / 2) * 14),
|
||||
};
|
||||
|
||||
add(new DrawableHitCircle(h));
|
||||
}
|
||||
break;
|
||||
case HitObjectType.Slider:
|
||||
add(new DrawableSlider(new Slider
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600,
|
||||
ControlPoints = new List<Vector2>
|
||||
{
|
||||
new Vector2(-200, 0),
|
||||
new Vector2(400, 0),
|
||||
},
|
||||
Distance = 400,
|
||||
Position = new Vector2(-200, 0),
|
||||
Velocity = 1,
|
||||
TickDistance = 100,
|
||||
}));
|
||||
break;
|
||||
case HitObjectType.Spinner:
|
||||
add(new DrawableSpinner(new Spinner
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600,
|
||||
EndTime = framedClock.CurrentTime + 1600,
|
||||
Position = new Vector2(0, 0),
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private int depth;
|
||||
|
||||
private void add(DrawableOsuHitObject h)
|
||||
{
|
||||
h.Anchor = Anchor.Centre;
|
||||
h.Depth = depth++;
|
||||
|
||||
if (auto)
|
||||
h.State.Value = ArmedState.Hit;
|
||||
|
||||
playfieldContainer.Add(h);
|
||||
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
|
||||
if (proxyable != null)
|
||||
approachContainer.Add(proxyable.ProxiedLayer.CreateProxy());
|
||||
}
|
||||
|
||||
private enum HitObjectType
|
||||
{
|
||||
Circle,
|
||||
Slider,
|
||||
Spinner
|
||||
}
|
||||
}
|
||||
}
|
130
osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs
Normal file
130
osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2007-2017 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseSlider : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableSlider) };
|
||||
|
||||
private readonly Container content;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private double speedMultiplier = 2;
|
||||
private double sliderMultiplier = 2;
|
||||
private int depthIndex;
|
||||
|
||||
public TestCaseSlider()
|
||||
{
|
||||
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
|
||||
|
||||
AddStep("Single", () => addSingle());
|
||||
AddStep("Repeated (1)", () => addRepeated(1));
|
||||
AddStep("Repeated (2)", () => addRepeated(2));
|
||||
AddStep("Repeated (3)", () => addRepeated(3));
|
||||
AddStep("Repeated (4)", () => addRepeated(4));
|
||||
AddStep("Stream", addStream);
|
||||
|
||||
AddSliderStep("SpeedMultiplier", 0.01, 10, 2, s => speedMultiplier = s);
|
||||
AddSliderStep("SliderMultiplier", 0.01, 10, 2, s => sliderMultiplier = s);
|
||||
}
|
||||
|
||||
private void addSingle(double timeOffset = 0, Vector2? positionOffset = null)
|
||||
{
|
||||
positionOffset = positionOffset ?? Vector2.Zero;
|
||||
|
||||
var slider = new Slider
|
||||
{
|
||||
StartTime = Time.Current + 1000 + timeOffset,
|
||||
Position = new Vector2(-200, 0) + positionOffset.Value,
|
||||
ControlPoints = new List<Vector2>
|
||||
{
|
||||
new Vector2(-200, 0) + positionOffset.Value,
|
||||
new Vector2(400, 0) + positionOffset.Value,
|
||||
},
|
||||
Distance = 400,
|
||||
};
|
||||
|
||||
var cpi = new ControlPointInfo();
|
||||
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
|
||||
|
||||
var difficulty = new BeatmapDifficulty
|
||||
{
|
||||
SliderMultiplier = (float)sliderMultiplier,
|
||||
CircleSize = 0
|
||||
};
|
||||
|
||||
slider.ApplyDefaults(cpi, difficulty);
|
||||
Add(new DrawableSlider(slider)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Depth = depthIndex++
|
||||
});
|
||||
}
|
||||
|
||||
private void addRepeated(int repeats)
|
||||
{
|
||||
// The first run through the slider is considered a repeat
|
||||
repeats++;
|
||||
|
||||
var repeatSamples = new List<List<SampleInfo>>();
|
||||
for (int i = 0; i < repeats; i++)
|
||||
repeatSamples.Add(new List<SampleInfo>());
|
||||
|
||||
var slider = new Slider
|
||||
{
|
||||
StartTime = Time.Current + 1000,
|
||||
Position = new Vector2(-200, 0),
|
||||
ControlPoints = new List<Vector2>
|
||||
{
|
||||
new Vector2(-200, 0),
|
||||
new Vector2(400, 0),
|
||||
},
|
||||
Distance = 400,
|
||||
RepeatCount = repeats,
|
||||
RepeatSamples = repeatSamples
|
||||
};
|
||||
|
||||
var cpi = new ControlPointInfo();
|
||||
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
|
||||
|
||||
var difficulty = new BeatmapDifficulty
|
||||
{
|
||||
SliderMultiplier = (float)sliderMultiplier,
|
||||
CircleSize = 0
|
||||
};
|
||||
|
||||
slider.ApplyDefaults(cpi, difficulty);
|
||||
Add(new DrawableSlider(slider)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Depth = depthIndex++
|
||||
});
|
||||
}
|
||||
|
||||
private void addStream()
|
||||
{
|
||||
Vector2 pos = Vector2.Zero;
|
||||
|
||||
for (int i = 0; i <= 1000; i += 100)
|
||||
{
|
||||
addSingle(i, pos);
|
||||
pos += new Vector2(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs
Normal file
45
osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseSpinner : OsuTestCase
|
||||
{
|
||||
private readonly Container content;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private int depthIndex;
|
||||
|
||||
public TestCaseSpinner()
|
||||
{
|
||||
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
|
||||
|
||||
AddStep("Single", addSingle);
|
||||
}
|
||||
|
||||
private void addSingle()
|
||||
{
|
||||
var spinner = new Spinner { StartTime = Time.Current + 1000, EndTime = Time.Current + 4000 };
|
||||
|
||||
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 0 });
|
||||
|
||||
var drawable = new DrawableSpinner(spinner)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Depth = depthIndex++
|
||||
};
|
||||
|
||||
Add(drawable);
|
||||
}
|
||||
}
|
||||
}
|
@ -75,6 +75,7 @@
|
||||
<Compile Include="Objects\Drawables\Pieces\TrianglesPiece.cs" />
|
||||
<Compile Include="Objects\Drawables\Pieces\SliderBall.cs" />
|
||||
<Compile Include="Objects\Drawables\Pieces\SliderBody.cs" />
|
||||
<Compile Include="Objects\ISliderProgress.cs" />
|
||||
<Compile Include="Objects\RepeatPoint.cs" />
|
||||
<Compile Include="Objects\SliderTick.cs" />
|
||||
<Compile Include="OsuDifficulty\OsuDifficultyCalculator.cs" />
|
||||
@ -86,8 +87,10 @@
|
||||
<Compile Include="OsuDifficulty\Utils\History.cs" />
|
||||
<Compile Include="OsuInputManager.cs" />
|
||||
<Compile Include="Replays\OsuReplayInputHandler.cs" />
|
||||
<Compile Include="Tests\TestCaseHitObjects.cs" />
|
||||
<Compile Include="Tests\TestCaseHitCircle.cs" />
|
||||
<Compile Include="Tests\TestCasePerformancePoints.cs" />
|
||||
<Compile Include="Tests\TestCaseSlider.cs" />
|
||||
<Compile Include="Tests\TestCaseSpinner.cs" />
|
||||
<Compile Include="UI\Cursor\CursorTrail.cs" />
|
||||
<Compile Include="UI\Cursor\GameplayCursor.cs" />
|
||||
<Compile Include="UI\OsuSettings.cs" />
|
||||
|
@ -38,6 +38,13 @@ namespace osu.Game.Rulesets
|
||||
/// <returns>A ruleset, if available, else null.</returns>
|
||||
public RulesetInfo GetRuleset(int id) => AvailableRulesets.FirstOrDefault(r => r.ID == id);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a ruleset using a known short name.
|
||||
/// </summary>
|
||||
/// <param name="shortName">The ruleset's short name.</param>
|
||||
/// <returns>A ruleset, if available, else null.</returns>
|
||||
public RulesetInfo GetRuleset(string shortName) => AvailableRulesets.FirstOrDefault(r => r.ShortName == shortName);
|
||||
|
||||
/// <summary>
|
||||
/// All available rulesets.
|
||||
/// </summary>
|
||||
|
Loading…
Reference in New Issue
Block a user