Make HitObjects construct nested hit objects

This commit is contained in:
smoogipoo
2017-12-22 21:42:54 +09:00
parent 6ef575c005
commit 6a29f6020a
22 changed files with 216 additions and 242 deletions

View File

@ -37,9 +37,9 @@ namespace osu.Game.Rulesets.Catch.Objects
/// </summary> /// </summary>
public CatchHitObject HyperDashTarget; public CatchHitObject HyperDashTarget;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using OpenTK; using OpenTK;
@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
RelativeChildSize = new Vector2(1, (float)HitObject.Duration) RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
}; };
foreach (CatchHitObject tick in s.Ticks) foreach (CatchHitObject tick in s.NestedHitObjects.OfType<CatchHitObject>())
{ {
TinyDroplet tiny = tick as TinyDroplet; TinyDroplet tiny = tick as TinyDroplet;
if (tiny != null) if (tiny != null)

View File

@ -11,8 +11,6 @@ using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using OpenTK; using OpenTK;
using osu.Framework.Lists;
using osu.Framework.Extensions.IEnumerableExtensions;
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {
@ -30,14 +28,9 @@ namespace osu.Game.Rulesets.Catch.Objects
public double Velocity; public double Velocity;
public double TickDistance; public double TickDistance;
private ControlPointInfo controlPointInfo; protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
private BeatmapDifficulty difficulty;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
this.controlPointInfo = controlPointInfo;
this.difficulty = difficulty;
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
@ -48,95 +41,94 @@ namespace osu.Game.Rulesets.Catch.Objects
TickDistance = scoringDistance / difficulty.SliderTickRate; TickDistance = scoringDistance / difficulty.SliderTickRate;
} }
public IEnumerable<CatchHitObject> Ticks protected override void CreateNestedHitObjects()
{ {
get base.CreateNestedHitObjects();
createTicks();
}
private void createTicks()
{
if (TickDistance == 0)
return;
var length = Curve.Distance;
var tickDistance = Math.Min(TickDistance, length);
var repeatDuration = length / Velocity;
var minDistanceFromEnd = Velocity * 0.01;
AddNested(new Fruit
{ {
SortedList<CatchHitObject> ticks = new SortedList<CatchHitObject>((a, b) => a.StartTime.CompareTo(b.StartTime)); Samples = Samples,
ComboColour = ComboColour,
StartTime = StartTime,
X = X
});
if (TickDistance == 0) for (var repeat = 0; repeat < RepeatCount; repeat++)
return ticks; {
var repeatStartTime = StartTime + repeat * repeatDuration;
var reversed = repeat % 2 == 1;
var length = Curve.Distance; for (var d = tickDistance; d <= length; d += tickDistance)
var tickDistance = Math.Min(TickDistance, length);
var repeatDuration = length / Velocity;
var minDistanceFromEnd = Velocity * 0.01;
ticks.Add(new Fruit
{ {
Samples = Samples, if (d > length - minDistanceFromEnd)
ComboColour = ComboColour, break;
StartTime = StartTime,
X = X
});
for (var repeat = 0; repeat < RepeatCount; repeat++) var timeProgress = d / length;
{ var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
var repeatStartTime = StartTime + repeat * repeatDuration;
var reversed = repeat % 2 == 1;
for (var d = tickDistance; d <= length; d += tickDistance) var lastTickTime = repeatStartTime + timeProgress * repeatDuration;
AddNested(new Droplet
{ {
if (d > length - minDistanceFromEnd) StartTime = lastTickTime,
break;
var timeProgress = d / length;
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
var lastTickTime = repeatStartTime + timeProgress * repeatDuration;
ticks.Add(new Droplet
{
StartTime = lastTickTime,
ComboColour = ComboColour,
X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
Samples = new SampleInfoList(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
});
}
double tinyTickInterval = tickDistance / length * repeatDuration;
while (tinyTickInterval > 100)
tinyTickInterval /= 2;
for (double t = 0; t < repeatDuration; t += tinyTickInterval)
{
double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration;
ticks.Add(new TinyDroplet
{
StartTime = repeatStartTime + t,
ComboColour = ComboColour,
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
Samples = new SampleInfoList(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
});
}
ticks.Add(new Fruit
{
Samples = Samples,
ComboColour = ComboColour, ComboColour = ComboColour,
StartTime = repeatStartTime + repeatDuration, X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH Samples = new SampleInfoList(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
}); });
} }
if (controlPointInfo != null && difficulty != null) double tinyTickInterval = tickDistance / length * repeatDuration;
ticks.ForEach(t => t.ApplyDefaults(controlPointInfo, difficulty)); while (tinyTickInterval > 100)
tinyTickInterval /= 2;
return ticks; for (double t = 0; t < repeatDuration; t += tinyTickInterval)
{
double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration;
AddNested(new TinyDroplet
{
StartTime = repeatStartTime + t,
ComboColour = ComboColour,
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
Samples = new SampleInfoList(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
});
}
AddNested(new Fruit
{
Samples = Samples,
ComboColour = ComboColour,
StartTime = repeatStartTime + repeatDuration,
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
});
} }
} }
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity; public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH; public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH;

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Scoring
AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
foreach (var unused in stream.Ticks) foreach (var unused in stream.NestedHitObjects.OfType<CatchHitObject>())
AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
continue; continue;

View File

@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
} }
}); });
foreach (var tick in HitObject.Ticks) foreach (var tick in HitObject.NestedHitObjects.OfType<HoldNoteTick>())
{ {
var drawableTick = new DrawableHoldNoteTick(tick) var drawableTick = new DrawableHoldNoteTick(tick)
{ {

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
@ -63,15 +62,9 @@ namespace osu.Game.Rulesets.Mania.Objects
/// </summary> /// </summary>
private double tickSpacing = 50; private double tickSpacing = 50;
private ControlPointInfo controlPointInfo; protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
private BeatmapDifficulty difficulty;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
this.controlPointInfo = controlPointInfo;
this.difficulty = difficulty;
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate; tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate;
@ -80,34 +73,27 @@ namespace osu.Game.Rulesets.Mania.Objects
Tail.ApplyDefaults(controlPointInfo, difficulty); Tail.ApplyDefaults(controlPointInfo, difficulty);
} }
/// <summary> protected override void CreateNestedHitObjects()
/// The scoring scoring ticks of the hold note.
/// </summary>
public IEnumerable<HoldNoteTick> Ticks => ticks ?? (ticks = createTicks());
private List<HoldNoteTick> ticks;
private List<HoldNoteTick> createTicks()
{ {
var ret = new List<HoldNoteTick>(); base.CreateNestedHitObjects();
createTicks();
}
private void createTicks()
{
if (tickSpacing == 0) if (tickSpacing == 0)
return ret; return;
for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing) for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing)
{ {
var tick = new HoldNoteTick AddNested(new HoldNoteTick
{ {
StartTime = t, StartTime = t,
Column = Column Column = Column
}; });
if (controlPointInfo != null && difficulty != null)
tick.ApplyDefaults(controlPointInfo, difficulty);
ret.Add(tick);
} }
return ret;
} }
/// <summary> /// <summary>
@ -121,9 +107,9 @@ namespace osu.Game.Rulesets.Mania.Objects
/// </summary> /// </summary>
private const double release_window_lenience = 1.5; private const double release_window_lenience = 1.5;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
HitWindows *= release_window_lenience; HitWindows *= release_window_lenience;
} }

View File

@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Mania.Objects
[JsonIgnore] [JsonIgnore]
public HitWindows HitWindows { get; protected set; } = new HitWindows(); public HitWindows HitWindows { get; protected set; } = new HitWindows();
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
HitWindows = new HitWindows(difficulty.OverallDifficulty); HitWindows = new HitWindows(difficulty.OverallDifficulty);
} }

View File

@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
AddJudgement(new ManiaJudgement { Result = HitResult.Perfect }); AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
// Ticks // Ticks
int tickCount = holdNote.Ticks.Count(); int tickCount = holdNote.NestedHitObjects.OfType<HoldNoteTick>().Count();
for (int i = 0; i < tickCount; i++) for (int i = 0; i < tickCount; i++)
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect }); AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
} }

View File

@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AddNested(initialCircle); AddNested(initialCircle);
var repeatDuration = s.Curve.Distance / s.Velocity; var repeatDuration = s.Curve.Distance / s.Velocity;
foreach (var tick in s.Ticks) foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
{ {
var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration; var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration;
var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2);
@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AddNested(drawableTick); AddNested(drawableTick);
} }
foreach (var repeatPoint in s.RepeatPoints) foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
{ {
var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration; var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration;
var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2);

View File

@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Osu.Objects
return HitResult.Miss; return HitResult.Miss;
} }
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2; Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
} }

View File

@ -74,15 +74,9 @@ namespace osu.Game.Rulesets.Osu.Objects
public double Velocity; public double Velocity;
public double TickDistance; public double TickDistance;
private ControlPointInfo controlPointInfo; protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
private BeatmapDifficulty difficulty;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
this.controlPointInfo = controlPointInfo;
this.difficulty = difficulty;
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
@ -105,85 +99,78 @@ namespace osu.Game.Rulesets.Osu.Objects
public int RepeatAt(double progress) => (int)(progress * RepeatCount); public int RepeatAt(double progress) => (int)(progress * RepeatCount);
public IEnumerable<SliderTick> Ticks protected override void CreateNestedHitObjects()
{ {
get base.CreateNestedHitObjects();
createTicks();
createRepeatPoints();
}
private void createTicks()
{
if (TickDistance == 0) return;
var length = Curve.Distance;
var tickDistance = Math.Min(TickDistance, length);
var repeatDuration = length / Velocity;
var minDistanceFromEnd = Velocity * 0.01;
for (var repeat = 0; repeat < RepeatCount; repeat++)
{ {
if (TickDistance == 0) yield break; var repeatStartTime = StartTime + repeat * repeatDuration;
var reversed = repeat % 2 == 1;
var length = Curve.Distance; for (var d = tickDistance; d <= length; d += tickDistance)
var tickDistance = Math.Min(TickDistance, length);
var repeatDuration = length / Velocity;
var minDistanceFromEnd = Velocity * 0.01;
for (var repeat = 0; repeat < RepeatCount; repeat++)
{ {
var repeatStartTime = StartTime + repeat * repeatDuration; if (d > length - minDistanceFromEnd)
var reversed = repeat % 2 == 1; break;
for (var d = tickDistance; d <= length; d += tickDistance) var distanceProgress = d / length;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
AddNested(new SliderTick
{ {
if (d > length - minDistanceFromEnd) RepeatIndex = repeat,
break; StartTime = repeatStartTime + timeProgress * repeatDuration,
Position = Curve.PositionAt(distanceProgress),
var distanceProgress = d / length; StackHeight = StackHeight,
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; Scale = Scale,
ComboColour = ComboColour,
var ret = new SliderTick Samples = new SampleInfoList(Samples.Select(s => new SampleInfo
{ {
RepeatIndex = repeat, Bank = s.Bank,
StartTime = repeatStartTime + timeProgress * repeatDuration, Name = @"slidertick",
Position = Curve.PositionAt(distanceProgress), Volume = s.Volume
StackHeight = StackHeight, }))
Scale = Scale, });
ComboColour = ComboColour,
Samples = new SampleInfoList(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
};
if (controlPointInfo != null && difficulty != null)
ret.ApplyDefaults(controlPointInfo, difficulty);
yield return ret;
}
} }
} }
} }
public IEnumerable<RepeatPoint> RepeatPoints
private void createRepeatPoints()
{ {
get var length = Curve.Distance;
var repeatPointDistance = Math.Min(Distance, length);
var repeatDuration = length / Velocity;
for (var repeat = 1; repeat < RepeatCount; repeat++)
{ {
var length = Curve.Distance; for (var d = repeatPointDistance; d <= length; d += repeatPointDistance)
var repeatPointDistance = Math.Min(Distance, length);
var repeatDuration = length / 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;
AddNested(new RepeatPoint
{ {
var repeatStartTime = StartTime + repeat * repeatDuration; RepeatIndex = repeat,
var distanceProgress = d / length; StartTime = repeatStartTime,
Position = Curve.PositionAt(distanceProgress),
var ret = new RepeatPoint StackHeight = StackHeight,
{ Scale = Scale,
RepeatIndex = repeat, ComboColour = ComboColour,
StartTime = repeatStartTime, });
Position = Curve.PositionAt(distanceProgress),
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
};
if (controlPointInfo != null && difficulty != null)
ret.ApplyDefaults(controlPointInfo, difficulty);
yield return ret;
}
} }
} }
} }

View File

@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Osu.Objects
public override bool NewCombo => true; public override bool NewCombo => true;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5)); SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));

View File

@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
} }
}); });
var scoringTimes = slider.Ticks.Select(t => t.StartTime).Concat(slider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t); var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime);
foreach (var time in scoringTimes) foreach (var time in scoringTimes)
computeVertex(time); computeVertex(time);
computeVertex(slider.EndTime); computeVertex(slider.EndTime);

View File

@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
beatmapMaxCombo = Beatmap.HitObjects.Count; beatmapMaxCombo = Beatmap.HitObjects.Count;
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.RepeatCount + s.Ticks.Count()); beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count) + 1;
} }
public override double Calculate(Dictionary<string, double> categoryRatings = null) public override double Calculate(Dictionary<string, double> categoryRatings = null)

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
@ -39,11 +40,11 @@ namespace osu.Game.Rulesets.Osu.Scoring
AddJudgement(new OsuJudgement { Result = HitResult.Great }); AddJudgement(new OsuJudgement { Result = HitResult.Great });
// Ticks // Ticks
foreach (var unused in slider.Ticks) foreach (var unused in slider.NestedHitObjects.OfType<SliderTick>())
AddJudgement(new OsuJudgement { Result = HitResult.Great }); AddJudgement(new OsuJudgement { Result = HitResult.Great });
//Repeats //Repeats
foreach (var unused in slider.RepeatPoints) foreach (var unused in slider.NestedHitObjects.OfType<RepeatPoint>())
AddJudgement(new OsuJudgement { Result = HitResult.Great }); AddJudgement(new OsuJudgement { Result = HitResult.Great });
} }

View File

@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
RelativeChildSize = new Vector2((float)HitObject.Duration, 1) RelativeChildSize = new Vector2((float)HitObject.Duration, 1)
}); });
foreach (var tick in drumRoll.Ticks) foreach (var tick in drumRoll.NestedHitObjects.OfType<DrumRollTick>())
{ {
var newTick = new DrawableDrumRollTick(tick); var newTick = new DrawableDrumRollTick(tick);
newTick.OnJudgement += onTickJudgement; newTick.OnJudgement += onTickJudgement;

View File

@ -3,7 +3,6 @@
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -37,52 +36,40 @@ namespace osu.Game.Rulesets.Taiko.Objects
/// </summary> /// </summary>
public double RequiredGreatHits { get; protected set; } public double RequiredGreatHits { get; protected set; }
/// <summary>
/// Total number of drum roll ticks.
/// </summary>
public int TotalTicks => Ticks.Count();
/// <summary>
/// Initializes the drum roll ticks if not initialized and returns them.
/// </summary>
public IEnumerable<DrumRollTick> Ticks => ticks ?? (ticks = createTicks());
private List<DrumRollTick> ticks;
/// <summary> /// <summary>
/// The length (in milliseconds) between ticks of this drumroll. /// The length (in milliseconds) between ticks of this drumroll.
/// <para>Half of this value is the hit window of the ticks.</para> /// <para>Half of this value is the hit window of the ticks.</para>
/// </summary> /// </summary>
private double tickSpacing = 100; private double tickSpacing = 100;
private ControlPointInfo controlPointInfo; protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
private BeatmapDifficulty difficulty;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
this.controlPointInfo = controlPointInfo;
this.difficulty = difficulty;
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
tickSpacing = timingPoint.BeatLength / TickRate; tickSpacing = timingPoint.BeatLength / TickRate;
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
} }
private List<DrumRollTick> createTicks() protected override void CreateNestedHitObjects()
{ {
var ret = new List<DrumRollTick>(); base.CreateNestedHitObjects();
createTicks();
}
private void createTicks()
{
if (tickSpacing == 0) if (tickSpacing == 0)
return ret; return;
bool first = true; bool first = true;
for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing) for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing)
{ {
var tick = new DrumRollTick AddNested(new DrumRollTick
{ {
FirstTick = first, FirstTick = first,
TickSpacing = tickSpacing, TickSpacing = tickSpacing,
@ -94,16 +81,10 @@ namespace osu.Game.Rulesets.Taiko.Objects
Name = @"slidertick", Name = @"slidertick",
Volume = s.Volume Volume = s.Volume
})) }))
}; });
if (controlPointInfo != null && difficulty != null)
tick.ApplyDefaults(controlPointInfo, difficulty);
ret.Add(tick);
first = false; first = false;
} }
return ret;
} }
} }
} }

View File

@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Taiko.Objects
/// </summary> /// </summary>
public double HitWindowMiss = 95; public double HitWindowMiss = 95;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20); HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50); HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects;
@ -83,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
} }
else if (drumRoll != null) else if (drumRoll != null)
{ {
foreach (var tick in drumRoll.Ticks) foreach (var tick in drumRoll.NestedHitObjects.OfType<DrumRollTick>())
{ {
Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2)); Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2));
hitButton = !hitButton; hitButton = !hitButton;

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -88,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
} }
else if (obj is DrumRoll) else if (obj is DrumRoll)
{ {
for (int i = 0; i < ((DrumRoll)obj).TotalTicks; i++) for (int i = 0; i < ((DrumRoll)obj).NestedHitObjects.OfType<DrumRollTick>().Count(); i++)
{ {
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great }); AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });

View File

@ -1,7 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Lists;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
@ -40,12 +43,26 @@ namespace osu.Game.Rulesets.Objects
[JsonIgnore] [JsonIgnore]
public bool Kiai { get; private set; } public bool Kiai { get; private set; }
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
[JsonIgnore]
public IReadOnlyList<HitObject> NestedHitObjects => nestedHitObjects;
/// <summary> /// <summary>
/// Applies default values to this HitObject. /// Applies default values to this HitObject.
/// </summary> /// </summary>
/// <param name="controlPointInfo">The control points.</param> /// <param name="controlPointInfo">The control points.</param>
/// <param name="difficulty">The difficulty settings to use.</param> /// <param name="difficulty">The difficulty settings to use.</param>
public virtual void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
ApplyDefaultsToSelf(controlPointInfo, difficulty);
nestedHitObjects.Clear();
CreateNestedHitObjects();
nestedHitObjects.ForEach(h => h.ApplyDefaults(controlPointInfo, difficulty));
}
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime); SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime);
EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime);
@ -53,5 +70,11 @@ namespace osu.Game.Rulesets.Objects
Kiai = effectPoint.KiaiMode; Kiai = effectPoint.KiaiMode;
SoundControlPoint = soundPoint; SoundControlPoint = soundPoint;
} }
protected virtual void CreateNestedHitObjects()
{
}
protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);
} }
} }

View File

@ -46,9 +46,9 @@ namespace osu.Game.Rulesets.Objects.Legacy
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaults(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);