using UnityEngine; /// /// 谱面修饰符:Mirror(镜像)/ Random(随机打乱轨道)。 /// 纯视觉重映射 trackIndex,对判定/计分完全等效(业务逻辑不变)。 /// PlayerPrefs 持久化,默认全部关闭。 /// 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; /// /// Mirror 开关(默认 false)。镜像 5 轨:0↔4, 1↔3, 2 不变。 /// public static bool MirrorEnabled { get => PlayerPrefs.GetInt(PREF_MIRROR, 0) == 1; set { PlayerPrefs.SetInt(PREF_MIRROR, value ? 1 : 0); PlayerPrefs.Save(); cachedMappingDirty = true; } } /// /// Random 开关(默认 false)。将 5 轨随机打乱(每次加载谱面时重新洗牌一次)。 /// public static bool RandomEnabled { get => PlayerPrefs.GetInt(PREF_RANDOM, 0) == 1; set { PlayerPrefs.SetInt(PREF_RANDOM, value ? 1 : 0); PlayerPrefs.Save(); cachedMappingDirty = true; } } /// /// 标记映射表需要重建(谱面重新加载时调用)。 /// public static void InvalidateMapping() { cachedMappingDirty = true; } /// /// 获取当前生效的 trackIndex 映射表。输入原始 trackIndex,返回重映射后的 trackIndex。 /// 优先级:Random > Mirror > 原值。Random 会在首次调用时固定洗牌结果(整局不变)。 /// 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; } } /// /// 反向映射:输入重映射后的 trackIndex,返回原始 trackIndex(用于输入事件还原)。 /// 当前项目输入事件已经按 trackIndex 匹配,通常无需反向映射。 /// 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; } }