diff --git a/RhythmGameUtilities.Tests/UtilitiesTest.cs b/RhythmGameUtilities.Tests/UtilitiesTest.cs index 41fff45..224ae77 100644 --- a/RhythmGameUtilities.Tests/UtilitiesTest.cs +++ b/RhythmGameUtilities.Tests/UtilitiesTest.cs @@ -73,6 +73,38 @@ public void TestCalculateBeatBars() Assert.That(beatBars.Count, Is.EqualTo(440)); } + [Test] + public void TestFindPositionNearGivenTick() + { + var notes = new List + { + new() { Position = 768 }, + new() { Position = 960 }, + new() { Position = 1152 }, + new() { Position = 1536 }, + new() { Position = 1728 }, + new() { Position = 1920 }, + new() { Position = 2304 }, + new() { Position = 2496 }, + new() { Position = 2688 }, + new() { Position = 3072 }, + new() { Position = 3264 }, + }; + + Assert.That(Utilities.FindPositionNearGivenTick(notes, 100), Is.Null); + Assert.That(Utilities.FindPositionNearGivenTick(notes, 750), Is.Not.Null); + Assert.That(Utilities.FindPositionNearGivenTick(notes, 1500), Is.Not.Null); + Assert.That(Utilities.FindPositionNearGivenTick(notes, 3200), Is.Null); + } + + [Test] + public void TestCalculateScore() + { + Assert.That(Utilities.CalculateScore(750, 100), Is.EqualTo(0)); + Assert.That(Utilities.CalculateScore(750, 750), Is.EqualTo(1)); + Assert.That(Utilities.CalculateScore(750, 725), Is.EqualTo(0.5f)); + } + } } diff --git a/RhythmGameUtilities/Scripts/Utilities.cs b/RhythmGameUtilities/Scripts/Utilities.cs index 04cd5e9..d6a7c89 100644 --- a/RhythmGameUtilities/Scripts/Utilities.cs +++ b/RhythmGameUtilities/Scripts/Utilities.cs @@ -46,6 +46,15 @@ public static extern int ConvertSecondsToTicksInternal(float seconds, int resolu #endif public static extern int RoundUpToTheNearestMultiplier(int value, int multiplier); +#if WINDOWS_BUILD || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + [DllImport("libRhythmGameUtilities.dll", CallingConvention = CallingConvention.Cdecl)] +#elif MACOS_BUILD || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX + [DllImport("libRhythmGameUtilities.dylib", CallingConvention = CallingConvention.Cdecl)] +#elif LINUX_BUILD || UNITY_EDITOR_LINUX || UNITY_STANDALONE_LINUX + [DllImport("libRhythmGameUtilities.so", CallingConvention = CallingConvention.Cdecl)] +#endif + public static extern float CalculateScore(int position, int tickOffset, int delta); + #if WINDOWS_BUILD || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN [DllImport("libRhythmGameUtilities.dll", CallingConvention = CallingConvention.Cdecl)] #elif MACOS_BUILD || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX @@ -107,6 +116,39 @@ public static List CalculateBeatBars(Dictionary bpmChanges, i return beatBars; } + public static Note? FindPositionNearGivenTick(List notes, int tick, int delta = 50) + { + var left = 0; + var right = notes.Count - 1; + + while (left <= right) + { + var mid = (left + right) / 2; + + var currentPosition = notes[mid].Position; + + if (currentPosition + delta < tick) + { + left = mid + 1; + } + else if (currentPosition - delta > tick) + { + right = mid - 1; + } + else + { + return notes[mid]; + } + } + + return null; + } + + public static float CalculateScore(int position, int tickOffset, int delta = 50) + { + return UtilitiesInternal.CalculateScore(position, tickOffset, delta); + } + } } diff --git a/UnityPackage/Editor/Tests/UtilitiesTest.cs b/UnityPackage/Editor/Tests/UtilitiesTest.cs index 41fff45..224ae77 100644 --- a/UnityPackage/Editor/Tests/UtilitiesTest.cs +++ b/UnityPackage/Editor/Tests/UtilitiesTest.cs @@ -73,6 +73,38 @@ public void TestCalculateBeatBars() Assert.That(beatBars.Count, Is.EqualTo(440)); } + [Test] + public void TestFindPositionNearGivenTick() + { + var notes = new List + { + new() { Position = 768 }, + new() { Position = 960 }, + new() { Position = 1152 }, + new() { Position = 1536 }, + new() { Position = 1728 }, + new() { Position = 1920 }, + new() { Position = 2304 }, + new() { Position = 2496 }, + new() { Position = 2688 }, + new() { Position = 3072 }, + new() { Position = 3264 }, + }; + + Assert.That(Utilities.FindPositionNearGivenTick(notes, 100), Is.Null); + Assert.That(Utilities.FindPositionNearGivenTick(notes, 750), Is.Not.Null); + Assert.That(Utilities.FindPositionNearGivenTick(notes, 1500), Is.Not.Null); + Assert.That(Utilities.FindPositionNearGivenTick(notes, 3200), Is.Null); + } + + [Test] + public void TestCalculateScore() + { + Assert.That(Utilities.CalculateScore(750, 100), Is.EqualTo(0)); + Assert.That(Utilities.CalculateScore(750, 750), Is.EqualTo(1)); + Assert.That(Utilities.CalculateScore(750, 725), Is.EqualTo(0.5f)); + } + } } diff --git a/UnityPackage/Scripts/Utilities.cs b/UnityPackage/Scripts/Utilities.cs index 04cd5e9..d6a7c89 100644 --- a/UnityPackage/Scripts/Utilities.cs +++ b/UnityPackage/Scripts/Utilities.cs @@ -46,6 +46,15 @@ public static extern int ConvertSecondsToTicksInternal(float seconds, int resolu #endif public static extern int RoundUpToTheNearestMultiplier(int value, int multiplier); +#if WINDOWS_BUILD || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + [DllImport("libRhythmGameUtilities.dll", CallingConvention = CallingConvention.Cdecl)] +#elif MACOS_BUILD || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX + [DllImport("libRhythmGameUtilities.dylib", CallingConvention = CallingConvention.Cdecl)] +#elif LINUX_BUILD || UNITY_EDITOR_LINUX || UNITY_STANDALONE_LINUX + [DllImport("libRhythmGameUtilities.so", CallingConvention = CallingConvention.Cdecl)] +#endif + public static extern float CalculateScore(int position, int tickOffset, int delta); + #if WINDOWS_BUILD || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN [DllImport("libRhythmGameUtilities.dll", CallingConvention = CallingConvention.Cdecl)] #elif MACOS_BUILD || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX @@ -107,6 +116,39 @@ public static List CalculateBeatBars(Dictionary bpmChanges, i return beatBars; } + public static Note? FindPositionNearGivenTick(List notes, int tick, int delta = 50) + { + var left = 0; + var right = notes.Count - 1; + + while (left <= right) + { + var mid = (left + right) / 2; + + var currentPosition = notes[mid].Position; + + if (currentPosition + delta < tick) + { + left = mid + 1; + } + else if (currentPosition - delta > tick) + { + right = mid - 1; + } + else + { + return notes[mid]; + } + } + + return null; + } + + public static float CalculateScore(int position, int tickOffset, int delta = 50) + { + return UtilitiesInternal.CalculateScore(position, tickOffset, delta); + } + } } diff --git a/includes/RhythmGameUtilities/Utilities.hpp b/includes/RhythmGameUtilities/Utilities.hpp index d7281d4..32e2d25 100644 --- a/includes/RhythmGameUtilities/Utilities.hpp +++ b/includes/RhythmGameUtilities/Utilities.hpp @@ -2,8 +2,10 @@ #include #include +#include #include +#include "Common.hpp" #include "Structs/BeatBar.h" #include "Structs/Note.h" @@ -110,6 +112,35 @@ std::vector CalculateBeatBars(std::map bpmChanges, return beatBars; } +std::optional FindPositionNearGivenTick(std::vector notes, int tick, + int delta = 50) +{ + auto left = 0; + auto right = static_cast(notes.size()) - 1; + + while (left <= right) + { + auto mid = (left + right) / 2; + + auto currentPosition = notes[mid].Position; + + if (currentPosition + delta < tick) + { + left = mid + 1; + } + else if (currentPosition - delta > tick) + { + right = mid - 1; + } + else + { + return notes[mid]; + } + } + + return std::nullopt; +} + extern "C" { /** @@ -148,6 +179,16 @@ extern "C" { return (int)std::ceil((float)value / multiplier) * multiplier; } + + PACKAGE_API float CalculateScore(int position, int tickOffset, + int delta = 50) + { + auto diff = position - tickOffset; + + auto ratio = InverseLerp(delta, 0, std::abs(diff)); + + return ratio; + } } } // namespace RhythmGameUtilities diff --git a/tests/RhythmGameUtilities/Utilities.cpp b/tests/RhythmGameUtilities/Utilities.cpp index 1f6adf3..f130afe 100644 --- a/tests/RhythmGameUtilities/Utilities.cpp +++ b/tests/RhythmGameUtilities/Utilities.cpp @@ -34,6 +34,30 @@ void testIsOnTheBeat() std::cout << "."; } +void testFindPositionNearGivenTick() +{ + std::vector notes = {{768, 0, 0}, {960, 0, 0}, {1152, 0, 0}, + {1536, 0, 0}, {1728, 0, 0}, {1920, 0, 0}, + {2304, 0, 0}, {2496, 0, 0}, {2688, 0, 0}, + {3072, 0, 0}, {3264, 0, 0}}; + + assert(std::nullopt == FindPositionNearGivenTick(notes, 100)); + assert(768 == FindPositionNearGivenTick(notes, 750)->Position); + assert(1536 == FindPositionNearGivenTick(notes, 1500)->Position); + assert(std::nullopt == FindPositionNearGivenTick(notes, 3200)); + + std::cout << "."; +} + +void testCalculateScore() +{ + assert(0 == CalculateScore(750, 100)); + assert(1 == CalculateScore(750, 750)); + assert(0.5f == CalculateScore(750, 725)); + + std::cout << "."; +} + void testRoundUpToTheNearestMultiplier() { assert(20 == RoundUpToTheNearestMultiplier(12, 10)); @@ -74,6 +98,8 @@ int main() testConvertTickToPosition(); testConvertSecondsToTicks(); testIsOnTheBeat(); + testFindPositionNearGivenTick(); + testCalculateScore(); testRoundUpToTheNearestMultiplier(); testGenerateAdjacentKeyPairs(); testCalculateBeatBars();