127 lines
3.9 KiB
C#
127 lines
3.9 KiB
C#
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// 谱面修饰符:Mirror(镜像)/ Random(随机打乱轨道)。
|
|
/// 纯视觉重映射 trackIndex,对判定/计分完全等效(业务逻辑不变)。
|
|
/// PlayerPrefs 持久化,默认全部关闭。
|
|
/// </summary>
|
|
public static class ChartModifiers
|
|
{
|
|
private const string PREF_MIRROR = "ChartModifier_Mirror";
|
|
private const string PREF_RANDOM = "ChartModifier_Random";
|
|
|
|
// 当前会话的映射表缓存(Random 需要在谱面加载时固定一次,整局不变)。
|
|
private static int[] cachedMapping = null;
|
|
private static bool cachedMappingDirty = true;
|
|
|
|
/// <summary>
|
|
/// Mirror 开关(默认 false)。镜像 5 轨:0↔4, 1↔3, 2 不变。
|
|
/// </summary>
|
|
public static bool MirrorEnabled
|
|
{
|
|
get => PlayerPrefs.GetInt(PREF_MIRROR, 0) == 1;
|
|
set
|
|
{
|
|
PlayerPrefs.SetInt(PREF_MIRROR, value ? 1 : 0);
|
|
PlayerPrefs.Save();
|
|
cachedMappingDirty = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Random 开关(默认 false)。将 5 轨随机打乱(每次加载谱面时重新洗牌一次)。
|
|
/// </summary>
|
|
public static bool RandomEnabled
|
|
{
|
|
get => PlayerPrefs.GetInt(PREF_RANDOM, 0) == 1;
|
|
set
|
|
{
|
|
PlayerPrefs.SetInt(PREF_RANDOM, value ? 1 : 0);
|
|
PlayerPrefs.Save();
|
|
cachedMappingDirty = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 标记映射表需要重建(谱面重新加载时调用)。
|
|
/// </summary>
|
|
public static void InvalidateMapping()
|
|
{
|
|
cachedMappingDirty = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前生效的 trackIndex 映射表。输入原始 trackIndex,返回重映射后的 trackIndex。
|
|
/// 优先级:Random > Mirror > 原值。Random 会在首次调用时固定洗牌结果(整局不变)。
|
|
/// </summary>
|
|
public static int RemapTrackIndex(int originalIndex)
|
|
{
|
|
if (originalIndex < 0 || originalIndex >= 5) return originalIndex;
|
|
|
|
if (!MirrorEnabled && !RandomEnabled) return originalIndex;
|
|
|
|
if (cachedMappingDirty)
|
|
{
|
|
RebuildMapping();
|
|
cachedMappingDirty = false;
|
|
}
|
|
|
|
return cachedMapping[originalIndex];
|
|
}
|
|
|
|
private static void RebuildMapping()
|
|
{
|
|
if (cachedMapping == null || cachedMapping.Length != 5)
|
|
cachedMapping = new int[5];
|
|
|
|
// 初始为恒等映射
|
|
for (int i = 0; i < 5; i++) cachedMapping[i] = i;
|
|
|
|
// Random 优先(若开启则整体洗牌,覆盖 Mirror)
|
|
if (RandomEnabled)
|
|
{
|
|
// Fisher-Yates shuffle
|
|
System.Random rng = new System.Random();
|
|
for (int i = 4; i > 0; i--)
|
|
{
|
|
int j = rng.Next(i + 1);
|
|
int temp = cachedMapping[i];
|
|
cachedMapping[i] = cachedMapping[j];
|
|
cachedMapping[j] = temp;
|
|
}
|
|
}
|
|
// Mirror(仅在 Random 关闭时生效)
|
|
else if (MirrorEnabled)
|
|
{
|
|
cachedMapping[0] = 4;
|
|
cachedMapping[1] = 3;
|
|
cachedMapping[2] = 2; // 中轨不变
|
|
cachedMapping[3] = 1;
|
|
cachedMapping[4] = 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 反向映射:输入重映射后的 trackIndex,返回原始 trackIndex(用于输入事件还原)。
|
|
/// 当前项目输入事件已经按 trackIndex 匹配,通常无需反向映射。
|
|
/// </summary>
|
|
public static int UnmapTrackIndex(int remappedIndex)
|
|
{
|
|
if (remappedIndex < 0 || remappedIndex >= 5) return remappedIndex;
|
|
if (!MirrorEnabled && !RandomEnabled) return remappedIndex;
|
|
|
|
if (cachedMappingDirty)
|
|
{
|
|
RebuildMapping();
|
|
cachedMappingDirty = false;
|
|
}
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
if (cachedMapping[i] == remappedIndex) return i;
|
|
}
|
|
|
|
return remappedIndex;
|
|
}
|
|
}
|