-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into android
- Loading branch information
Showing
44 changed files
with
934 additions
and
437 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using osu.Game.Audio; | ||
|
@@ -25,6 +24,11 @@ public class JuiceStream : CatchHitObject, IHasCurve | |
public double Velocity; | ||
public double TickDistance; | ||
|
||
/// <summary> | ||
/// The length of one span of this <see cref="JuiceStream"/>. | ||
/// </summary> | ||
public double SpanDuration => Duration / this.SpanCount(); | ||
|
||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) | ||
{ | ||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty); | ||
|
@@ -41,19 +45,6 @@ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, B | |
protected override void CreateNestedHitObjects() | ||
{ | ||
base.CreateNestedHitObjects(); | ||
createTicks(); | ||
} | ||
|
||
private void createTicks() | ||
{ | ||
if (TickDistance == 0) | ||
return; | ||
|
||
var length = Path.Distance; | ||
var tickDistance = Math.Min(TickDistance, length); | ||
var spanDuration = length / Velocity; | ||
|
||
var minDistanceFromEnd = Velocity * 0.01; | ||
|
||
var tickSamples = Samples.Select(s => new SampleInfo | ||
{ | ||
|
@@ -62,81 +53,59 @@ private void createTicks() | |
Volume = s.Volume | ||
}).ToList(); | ||
|
||
AddNested(new Fruit | ||
{ | ||
Samples = Samples, | ||
StartTime = StartTime, | ||
X = X | ||
}); | ||
|
||
double lastTickTime = StartTime; | ||
SliderEventDescriptor? lastEvent = null; | ||
|
||
for (int span = 0; span < this.SpanCount(); span++) | ||
foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset)) | ||
{ | ||
var spanStartTime = StartTime + span * spanDuration; | ||
var reversed = span % 2 == 1; | ||
|
||
for (double d = tickDistance;; d += tickDistance) | ||
// generate tiny droplets since the last point | ||
if (lastEvent != null) | ||
{ | ||
bool isLastTick = false; | ||
if (d + minDistanceFromEnd >= length) | ||
{ | ||
d = length; | ||
isLastTick = true; | ||
} | ||
|
||
var timeProgress = d / length; | ||
var distanceProgress = reversed ? 1 - timeProgress : timeProgress; | ||
double sinceLastTick = e.Time - lastEvent.Value.Time; | ||
|
||
double time = spanStartTime + timeProgress * spanDuration; | ||
|
||
if (LegacyLastTickOffset != null) | ||
if (sinceLastTick > 80) | ||
{ | ||
// If we're the last tick, apply the legacy offset | ||
if (span == this.SpanCount() - 1 && isLastTick) | ||
time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value); | ||
} | ||
double timeBetweenTiny = sinceLastTick; | ||
while (timeBetweenTiny > 100) | ||
timeBetweenTiny /= 2; | ||
|
||
int tinyTickCount = 1; | ||
double tinyTickInterval = time - lastTickTime; | ||
while (tinyTickInterval > 100 && tinyTickCount < 10000) | ||
{ | ||
tinyTickInterval /= 2; | ||
tinyTickCount *= 2; | ||
for (double t = timeBetweenTiny; t < sinceLastTick; t += timeBetweenTiny) | ||
{ | ||
AddNested(new TinyDroplet | ||
{ | ||
Samples = tickSamples, | ||
StartTime = t + lastEvent.Value.Time, | ||
X = X + Path.PositionAt( | ||
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH, | ||
}); | ||
} | ||
} | ||
} | ||
|
||
for (int tinyTickIndex = 0; tinyTickIndex < tinyTickCount - 1; tinyTickIndex++) | ||
{ | ||
var t = lastTickTime + (tinyTickIndex + 1) * tinyTickInterval; | ||
double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; | ||
// this also includes LegacyLastTick and this is used for TinyDroplet generation above. | ||
// this means that the final segment of TinyDroplets are increasingly mistimed where LegacyLastTickOffset is being applied. | ||
lastEvent = e; | ||
|
||
AddNested(new TinyDroplet | ||
switch (e.Type) | ||
{ | ||
case SliderEventType.Tick: | ||
AddNested(new Droplet | ||
{ | ||
StartTime = t, | ||
X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, | ||
Samples = tickSamples | ||
Samples = tickSamples, | ||
StartTime = e.Time, | ||
X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH, | ||
}); | ||
break; | ||
case SliderEventType.Head: | ||
case SliderEventType.Tail: | ||
case SliderEventType.Repeat: | ||
AddNested(new Fruit | ||
{ | ||
Samples = Samples, | ||
StartTime = e.Time, | ||
X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH, | ||
}); | ||
} | ||
|
||
lastTickTime = time; | ||
|
||
if (isLastTick) | ||
break; | ||
|
||
AddNested(new Droplet | ||
{ | ||
StartTime = time, | ||
X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, | ||
Samples = tickSamples | ||
}); | ||
} | ||
|
||
AddNested(new Fruit | ||
{ | ||
Samples = Samples, | ||
StartTime = spanStartTime + spanDuration, | ||
X = X + Path.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH | ||
}); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using NUnit.Framework; | ||
|
||
namespace osu.Game.Rulesets.Osu.Tests | ||
{ | ||
[TestFixture] | ||
public class TestCaseOsuPlayer : Game.Tests.Visual.TestCasePlayer | ||
{ | ||
public TestCaseOsuPlayer() | ||
: base(new OsuRuleset()) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.