Replace BeatDivisorFinder with GetClosestBeatDivisor

This commit is contained in:
Justus Franklin Tumacder 2021-05-01 11:57:47 +08:00
parent ecb053b0de
commit fdf8c12947
4 changed files with 12 additions and 178 deletions

View File

@ -6,10 +6,10 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Skinning.Default;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Screens.Edit;
@ -27,7 +27,7 @@ public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<Man
private OsuColour colours { get; set; }
[Resolved(canBeNull: true)]
private BeatDivisorFinder beatDivisorFinder { get; set; }
private IBeatmap beatmap { get; set; }
private readonly Bindable<bool> configTimingBasedNoteColouring = new Bindable<bool>();
@ -58,9 +58,14 @@ private void load(ManiaRulesetConfigManager rulesetConfig)
protected override void LoadComplete()
{
if (beatDivisorFinder != null)
if (beatmap != null)
{
HitObject.StartTimeBindable.BindValueChanged(_ => snap.Value = beatDivisorFinder.FindDivisor(HitObject), true);
HitObject.StartTimeBindable.BindValueChanged(startTime =>
{
snap.Value = beatmap.ControlPointInfo.GetClosestBeatDivisor(startTime.NewValue);
},
true
);
}
snap.BindValueChanged(_ => updateSnapColour());

View File

@ -45,8 +45,8 @@ public class DrawableManiaRuleset : DrawableScrollingRuleset<ManiaHitObject>
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
[Cached]
private BeatDivisorFinder beatDivisorFinder { get; set; }
[Cached(typeof(IBeatmap))]
private ManiaBeatmap cachedBeatmap { get; set; }
public IEnumerable<BarLine> BarLines;
@ -80,7 +80,7 @@ public DrawableManiaRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod
: base(ruleset, beatmap, mods)
{
BarLines = new BarLineGenerator<BarLine>(Beatmap).BarLines;
beatDivisorFinder = new BeatDivisorFinder(Beatmap);
cachedBeatmap = Beatmap;
}
[BackgroundDependencyLoader]

View File

@ -1,116 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Tests.NonVisual
{
public class BeatDivisorFinderTest
{
[Test]
public void TestFindDivisor()
{
const double beat_length = 1000;
var beatmap = new Beatmap
{
HitObjects = new List<HitObject>
{
new HitObject { StartTime = -beat_length / 3 },
new HitObject { StartTime = 0 },
new HitObject { StartTime = beat_length / 16 },
new HitObject { StartTime = beat_length / 12 },
new HitObject { StartTime = beat_length / 8 },
new HitObject { StartTime = beat_length / 6 },
new HitObject { StartTime = beat_length / 4 },
new HitObject { StartTime = beat_length / 3 },
new HitObject { StartTime = beat_length / 2 },
new HitObject { StartTime = beat_length },
new HitObject { StartTime = beat_length + beat_length / 7 }
},
ControlPointInfo = new ControlPointInfo()
};
beatmap.ControlPointInfo.Add(0, new TimingControlPoint
{
TimeSignature = Game.Beatmaps.Timing.TimeSignatures.SimpleQuadruple,
BeatLength = beat_length
});
var beatDivisorFinder = new BeatDivisorFinder(beatmap);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[0]), 3);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[1]), 1);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[2]), 16);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[3]), 12);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[4]), 8);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[5]), 6);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[6]), 4);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[7]), 3);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[8]), 2);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[9]), 1);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[10]), 0);
}
[Test]
public void TestFindDivisorWithTempoChanges()
{
const double first_beat_length = 1000;
const double second_beat_length = 700;
const double third_beat_length = 200;
const double first_beat_length_start = 0;
const double second_beat_length_start = 1000;
const double third_beat_length_start = 2000;
var beatmap = new Beatmap
{
HitObjects = new List<HitObject>
{
new HitObject { StartTime = first_beat_length_start },
new HitObject { StartTime = first_beat_length_start + first_beat_length / 2 },
new HitObject { StartTime = second_beat_length_start },
new HitObject { StartTime = second_beat_length_start + second_beat_length / 2 },
new HitObject { StartTime = third_beat_length_start },
new HitObject { StartTime = third_beat_length_start + third_beat_length / 2 },
},
ControlPointInfo = new ControlPointInfo()
};
var firstTimingControlPoint = new TimingControlPoint
{
TimeSignature = Game.Beatmaps.Timing.TimeSignatures.SimpleQuadruple,
BeatLength = first_beat_length
};
var secondTimingControlPoint = new TimingControlPoint
{
TimeSignature = Game.Beatmaps.Timing.TimeSignatures.SimpleQuadruple,
BeatLength = second_beat_length
};
var thirdTimingControlPoint = new TimingControlPoint
{
TimeSignature = Game.Beatmaps.Timing.TimeSignatures.SimpleQuadruple,
BeatLength = third_beat_length
};
beatmap.ControlPointInfo.Add(first_beat_length_start, firstTimingControlPoint);
beatmap.ControlPointInfo.Add(second_beat_length_start, secondTimingControlPoint);
beatmap.ControlPointInfo.Add(third_beat_length_start, thirdTimingControlPoint);
var beatDivisorFinder = new BeatDivisorFinder(beatmap);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[0]), 1);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[1]), 2);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[2]), 1);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[3]), 2);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[4]), 1);
Assert.AreEqual(beatDivisorFinder.FindDivisor(beatmap.HitObjects[5]), 2);
}
}
}

View File

@ -1,55 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Screens.Edit;
namespace osu.Game.Rulesets.Objects
{
/// <summary>
/// Used to find the lowest beat divisor that a <see cref="HitObject"/> aligns to in an <see cref="IBeatmap"/>.
/// </summary>
public class BeatDivisorFinder
{
private readonly IBeatmap beatmap;
/// <summary>
/// Creates a new <see cref="BeatDivisorFinder"/> instance.
/// </summary>
/// <param name="beatmap">The beatmap to use when calculating beat divisor alignment.</param>
public BeatDivisorFinder(IBeatmap beatmap)
{
this.beatmap = beatmap;
}
/// <summary>
/// Finds the lowest beat divisor that the given <see cref="HitObject"/> aligns to.
/// Returns 0 if it does not align to any divisor.
/// </summary>
/// <param name="hitObject">The <see cref="HitObject"/> to evaluate.</param>
public int FindDivisor(HitObject hitObject)
{
TimingControlPoint currentTimingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
double snapResult = hitObject.StartTime - currentTimingPoint.Time;
foreach (var divisor in BindableBeatDivisor.VALID_DIVISORS)
{
if (almostDivisibleBy(snapResult, currentTimingPoint.BeatLength / divisor))
return divisor;
}
return 0;
}
private const double leniency_ms = 1.0;
private static bool almostDivisibleBy(double dividend, double divisor)
{
double remainder = Math.Abs(dividend) % divisor;
return Precision.AlmostEquals(remainder, 0, leniency_ms) || Precision.AlmostEquals(remainder - divisor, 0, leniency_ms);
}
}
}