长音符再修复 加入了关卡连接 优化了一些默认加载
This commit is contained in:
@@ -5,6 +5,37 @@ using System.Collections.Generic;
|
||||
|
||||
public class BeatmapManager : MonoBehaviour
|
||||
{
|
||||
// static holder to accept SongData passed from previous scene before this manager exists
|
||||
public static SongData pendingSongData = null;
|
||||
public static int pendingDifficulty = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Called by previous scene to hand over a SongData SO and difficulty to this manager after scene load.
|
||||
/// This stores the pair in static fields so BeatmapManager.Start can pick them up.
|
||||
/// </summary>
|
||||
public static void SetPendingSong(SongData song, int difficulty)
|
||||
{
|
||||
pendingSongData = song;
|
||||
pendingDifficulty = difficulty;
|
||||
Debug.LogWarning($"BeatmapManager.SetPendingSong called: song={(song==null?"NULL":song.songName)}, difficulty={difficulty}");
|
||||
}
|
||||
|
||||
[Header("Assigned SongData (set at runtime from previous scene or via Inspector)")]
|
||||
public SongData assignedSongData; // visible in Inspector so you can see the SO passed from previous scene
|
||||
[Header("Assigned difficulty (for inspector visibility)")]
|
||||
public int assignedDifficulty = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Public API to accept a SongData at runtime (can be called by other scripts after scene load)
|
||||
/// Also sets inspector-exposed fields so you can visually confirm in Editor during play.
|
||||
/// </summary>
|
||||
public void AcceptSongData(SongData song, int difficulty)
|
||||
{
|
||||
assignedSongData = song;
|
||||
assignedDifficulty = difficulty;
|
||||
Debug.LogWarning($"BeatmapManager.AcceptSongData: accepted song={(song==null?"NULL":song.songName)}, difficulty={difficulty}");
|
||||
}
|
||||
|
||||
public Beatmap beatmap; // 当前谱面数据
|
||||
|
||||
// 音符生成器引用
|
||||
@@ -45,9 +76,6 @@ public class BeatmapManager : MonoBehaviour
|
||||
public float inMultiplier = 2f;
|
||||
public float imMultiplier = 3f;
|
||||
|
||||
// 新增:基础生命值缩放因子(Base HP Unit Scale)
|
||||
// 用于将 Note 数量(例如 709)缩放到 40000 左右的范围。
|
||||
// 计算公式:NoteAmount * DifficultyMult * BaseScale ≈ TotalHP
|
||||
[Header("HP Calculation Settings")]
|
||||
[Tooltip("Scales the note amount to enemy HP. Example: NoteAmount * MaxMultiplier * BaseScale ≈ TotalHP")]
|
||||
public float baseHpUnitScale = 1f;
|
||||
@@ -205,9 +233,119 @@ public class BeatmapManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:从 TextAsset 解析并根据 parseOnly 决定是否只是解析或直接加载
|
||||
public bool LoadBeatmapFromTextAsset(TextAsset chartAsset, bool parseOnly = false)
|
||||
{
|
||||
if (chartAsset == null)
|
||||
{
|
||||
Debug.LogWarning("LoadBeatmapFromTextAsset: chartAsset is null");
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(chartAsset.text))
|
||||
{
|
||||
Debug.LogWarning("LoadBeatmapFromTextAsset: chartAsset.text is null or empty");
|
||||
return false;
|
||||
}
|
||||
if (parseOnly)
|
||||
{
|
||||
return ParseJsonOnly(chartAsset.text);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessJsonAndLoad(chartAsset.text);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:从 SongData 的 chart TextAsset 加载谱面
|
||||
public bool LoadBeatmapFromSongData(SongData song, int difficulty, bool parseOnly = false)
|
||||
{
|
||||
if (song == null)
|
||||
{
|
||||
Debug.LogWarning("LoadBeatmapFromSongData: song is null");
|
||||
return false;
|
||||
}
|
||||
TextAsset ta = song.GetChartFile(difficulty);
|
||||
if (ta == null)
|
||||
{
|
||||
Debug.LogWarning($"LoadBeatmapFromSongData: chart TextAsset for difficulty {difficulty} is null on song {song.songName}");
|
||||
return false;
|
||||
}
|
||||
Debug.LogWarning($"LoadBeatmapFromSongData: loading chart for song {song.songName}, difficulty {difficulty}, parseOnly={parseOnly}, chartSize={(ta.text != null ? ta.text.Length : 0)}");
|
||||
return LoadBeatmapFromTextAsset(ta, parseOnly);
|
||||
}
|
||||
|
||||
// 在 Start() 方法中初始化
|
||||
void Start()
|
||||
{
|
||||
// 被动接收上一个场景传递过来的 SongData(通过 BeatmapManager.pendingSongData)
|
||||
if (pendingSongData != null)
|
||||
{
|
||||
Debug.LogWarning($"BeatmapManager.Start: pendingSongData detected: {pendingSongData.songName}, difficulty={pendingDifficulty}");
|
||||
// 将 pending 显示到 Inspector 字段,便于检查
|
||||
assignedSongData = pendingSongData;
|
||||
assignedDifficulty = pendingDifficulty;
|
||||
|
||||
// 尝试解析(只解析,不立即生成音符)
|
||||
bool ok = LoadBeatmapFromSongData(assignedSongData, assignedDifficulty, true);
|
||||
if (!ok) Debug.LogWarning("BeatmapManager.Start: LoadBeatmapFromSongData failed");
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("BeatmapManager.Start: chart parsed from SongData, attempting to assign audio and pause system");
|
||||
|
||||
// try to assign audio to GameManager.musicSource
|
||||
var gm = FindObjectOfType<GameManager>();
|
||||
if (gm != null && gm.musicSource != null)
|
||||
{
|
||||
if (assignedSongData != null && assignedSongData.audioFile != null)
|
||||
{
|
||||
gm.musicSource.clip = assignedSongData.audioFile;
|
||||
gm.musicSource.loop = false;
|
||||
Debug.LogWarning("Assigned SongData.audioFile to GameManager.musicSource.clip (from SO)");
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(parsedMusicFile))
|
||||
{
|
||||
Debug.LogWarning($"Attempting Resources.Load for audio: {parsedMusicFile}");
|
||||
var ac = Resources.Load<AudioClip>(parsedMusicFile);
|
||||
if (ac != null)
|
||||
{
|
||||
gm.musicSource.clip = ac;
|
||||
gm.musicSource.loop = false;
|
||||
Debug.LogWarning("Assigned audio via Resources.Load(parsedMusicFile)");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Resources.Load failed for '{parsedMusicFile}'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("No audio available on SongData and parsedMusicFile empty");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("GameManager or its musicSource not found; audio not assigned");
|
||||
}
|
||||
|
||||
// Pause the system to show pause overlay (PauseManager will enable overlayRoot)
|
||||
var pauseMgr = PauseManager.Instance ?? FindObjectOfType<PauseManager>();
|
||||
if (pauseMgr != null)
|
||||
{
|
||||
pauseMgr.Pause(true);
|
||||
Debug.LogWarning("System paused after loading chart and audio to allow player to start");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("PauseManager not found in scene; cannot pause system automatically");
|
||||
}
|
||||
}
|
||||
|
||||
// clear pending so it doesn't run again
|
||||
pendingSongData = null;
|
||||
pendingDifficulty = -1;
|
||||
}
|
||||
|
||||
// 如果处于测试模式,则跳过自动加载谱面
|
||||
if (GameConfig.testMode)
|
||||
{
|
||||
@@ -215,20 +353,20 @@ public class BeatmapManager : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
// 加载默认谱面
|
||||
LoadBeatmap("Emilia_demo.json"); // 加载并实例化音符
|
||||
// 原先默认加载的调试谱面已注释,改为仅在需要时手动恢复
|
||||
// LoadBeatmap("Emilia_demo.json"); // 加载并实例化音符
|
||||
Debug.LogWarning("Default automatic demo beatmap load is commented out to prioritize SO-provided charts.");
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前难度乘数
|
||||
private float GetCurrentDifficultyMultiplier()
|
||||
{
|
||||
// 假设 1=EZ, 2=HD, 3=IN, 4=IM
|
||||
if (parsedDifficulty == 1) return ezMultiplier;
|
||||
if (parsedDifficulty == 2) return hdMultiplier;
|
||||
if (parsedDifficulty == 3) return inMultiplier;
|
||||
if (parsedDifficulty == 4) return imMultiplier;
|
||||
return 1f; // 默认值
|
||||
return 1f;
|
||||
}
|
||||
|
||||
// 统一处理敌人 ID 提取、发送给 UI 以及 HP 计算的逻辑
|
||||
@@ -242,7 +380,6 @@ public class BeatmapManager : MonoBehaviour
|
||||
|
||||
if (!parsedEnemyListIsEmpty && parsedColorSegments != null && parsedColorSegments.Length > 0)
|
||||
{
|
||||
// 1. 提取敌人 IDs
|
||||
List<int> enemyIds = new List<int>();
|
||||
foreach (var segment in parsedColorSegments)
|
||||
{
|
||||
@@ -256,43 +393,29 @@ public class BeatmapManager : MonoBehaviour
|
||||
enemyIds.Add(enemyId);
|
||||
}
|
||||
|
||||
// 2. 补齐 5 个槽位
|
||||
while (enemyIds.Count < 5)
|
||||
{
|
||||
enemyIds.Add(0);
|
||||
}
|
||||
while (enemyIds.Count < 5) enemyIds.Add(0);
|
||||
|
||||
// A. 传递 ID 列表给 uiController
|
||||
Debug.Log($"Assigning enemySlotIds to teamUIController: {string.Join(",", enemyIds)}");
|
||||
uiController.enemySlotIds = enemyIds;
|
||||
|
||||
// B. 让 UI 控制器加载 SO (此时 SO 的 HP 仍是默认值)
|
||||
uiController.PopulateEnemySOsFromIds();
|
||||
|
||||
// C. 计算并应用 HP 逻辑
|
||||
if (parsedNoteAmount > 0)
|
||||
{
|
||||
float currentMultiplier = GetCurrentDifficultyMultiplier();
|
||||
|
||||
// 计算总 HP:音符数 * 难度乘数 * 基础缩放
|
||||
float totalCalculatedHP = parsedNoteAmount * currentMultiplier * baseHpUnitScale;
|
||||
|
||||
// 计算活跃敌人数量(非0 ID)
|
||||
int activeEnemyCount = enemyIds.FindAll(id => id != 0).Count;
|
||||
if (activeEnemyCount == 0) activeEnemyCount = 1; // 防止除零
|
||||
if (activeEnemyCount == 0) activeEnemyCount = 1;
|
||||
|
||||
// 计算单个敌人 HP (总血量 / 敌人数量,均匀分配)
|
||||
int individualMaxHP = Mathf.RoundToInt(totalCalculatedHP / activeEnemyCount);
|
||||
|
||||
Debug.Log($"[BeatmapManager] HP Calc -> Notes: {parsedNoteAmount}, Multiplier: {currentMultiplier}, Total: {totalCalculatedHP:F0}, ActiveEnemies: {activeEnemyCount}, Per Enemy: {individualMaxHP}");
|
||||
|
||||
// D. 【关键调用】将计算出的 HP 回填到 teamUIController 中的 SO 中
|
||||
uiController.ApplyCalculatedEnemyHP(individualMaxHP);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果没有敌人,也要通知 UI 控制器清空列表
|
||||
Debug.Log("Parsed enemy list is empty, clearing UI.");
|
||||
uiController.enemySlotIds = new List<int> { 0, 0, 0, 0, 0 };
|
||||
uiController.PopulateEnemySOsFromIds();
|
||||
@@ -308,7 +431,6 @@ public class BeatmapManager : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse main beatmap
|
||||
Beatmap parsed = null;
|
||||
try
|
||||
{
|
||||
@@ -326,17 +448,11 @@ public class BeatmapManager : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse extras using BeatmapExtra which contains the requested fields and types
|
||||
BeatmapExtra extra = null;
|
||||
try
|
||||
{
|
||||
extra = JsonUtility.FromJson<BeatmapExtra>(json);
|
||||
}
|
||||
catch { extra = null; }
|
||||
try { extra = JsonUtility.FromJson<BeatmapExtra>(json); } catch { extra = null; }
|
||||
|
||||
if (extra != null)
|
||||
{
|
||||
// store into manager fields
|
||||
parsedTitle = extra.title;
|
||||
parsedComposer = extra.composer;
|
||||
parsedIllustrator = extra.illustrator;
|
||||
@@ -354,24 +470,16 @@ public class BeatmapManager : MonoBehaviour
|
||||
parsedNoteAmount = extra.noteAmount;
|
||||
globalDelaySeconds = extra.globalDelaySeconds;
|
||||
|
||||
// If JSON contains absolute paths for music/background, copy into parsed object for later use
|
||||
if (!string.IsNullOrEmpty(extra.musicFile)) parsed.musicFile = extra.musicFile;
|
||||
if (!string.IsNullOrEmpty(extra.backgroundFile)) parsed.backgroundFile = extra.backgroundFile;
|
||||
|
||||
Debug.Log($"Beatmap extras parsed: title={parsedTitle}, composer={parsedComposer}, duration={parsedDuration}, bpm={parsedBpm}, difficulty={parsedDifficulty}, noteAmount={parsedNoteAmount}, globalDelaySeconds={globalDelaySeconds}");
|
||||
|
||||
// New fields
|
||||
parsedEnemyListIsEmpty = extra.enemyList_isEmpty;
|
||||
if (!parsedEnemyListIsEmpty)
|
||||
{
|
||||
parsedColorSegments = extra.colorSegments;
|
||||
}
|
||||
if (!parsedEnemyListIsEmpty) parsedColorSegments = extra.colorSegments;
|
||||
parsedNoteStatistics = extra.noteStatistics;
|
||||
parsedTrackStates = extra.trackStates;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback to populate from parsed Beatmap where possible
|
||||
parsedTitle = parsed.title;
|
||||
parsedComposer = parsed.composer;
|
||||
parsedIllustrator = parsed.illustrator;
|
||||
@@ -382,7 +490,6 @@ public class BeatmapManager : MonoBehaviour
|
||||
parsedMusicFile = parsed.musicFile;
|
||||
parsedBackgroundFile = parsed.backgroundFile;
|
||||
|
||||
// convert types
|
||||
parsedDuration = Mathf.RoundToInt(parsed.duration);
|
||||
parsedBpm = Mathf.RoundToInt(parsed.bpm);
|
||||
parsedDifficulty = parsed.difficulty;
|
||||
@@ -390,29 +497,17 @@ public class BeatmapManager : MonoBehaviour
|
||||
Debug.LogWarning("BeatmapExtra not found in JSON; populated limited fields from Beatmap.");
|
||||
}
|
||||
|
||||
// Calculate per-note and leftover scores
|
||||
CalculateNoteScores();
|
||||
|
||||
// NOTE: Do NOT modify parsed.notes here. globalDelaySeconds will be applied to audio playback instead.
|
||||
|
||||
// assign and hand off to spawner
|
||||
beatmap = parsed;
|
||||
Debug.Log("谱面已加载:" + beatmap.title);
|
||||
|
||||
if (noteSpawner != null)
|
||||
{
|
||||
noteSpawner.LoadBeatmap(beatmap);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("NoteSpawner is null in BeatmapManager.");
|
||||
}
|
||||
if (noteSpawner != null) noteSpawner.LoadBeatmap(beatmap);
|
||||
else Debug.LogError("NoteSpawner is null in BeatmapManager.");
|
||||
|
||||
// 调用统一的敌人处理逻辑(包含 HP 计算和设置)
|
||||
SetupEnemiesAndHP();
|
||||
}
|
||||
|
||||
// Calculate per-note and leftover scores based on parsedNoteAmount
|
||||
private void CalculateNoteScores()
|
||||
{
|
||||
if (parsedNoteAmount > 0)
|
||||
@@ -429,7 +524,6 @@ public class BeatmapManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class used to parse extra fields from JSON that Beatmap doesn't define
|
||||
[System.Serializable]
|
||||
private class BeatmapExtra
|
||||
{
|
||||
@@ -449,43 +543,18 @@ public class BeatmapManager : MonoBehaviour
|
||||
public int noteAmount;
|
||||
public float globalDelaySeconds;
|
||||
|
||||
// New fields
|
||||
public bool enemyList_isEmpty;
|
||||
public ColorSegment[] colorSegments;
|
||||
public NoteStatistic[] noteStatistics;
|
||||
public TrackStates trackStates;
|
||||
}
|
||||
|
||||
// New serializable classes for the extra fields
|
||||
[System.Serializable]
|
||||
public class ColorSegment
|
||||
{
|
||||
public string enemyID;
|
||||
public float percentage;
|
||||
}
|
||||
|
||||
public class ColorSegment { public string enemyID; public float percentage; }
|
||||
[System.Serializable]
|
||||
public class NoteStatistic
|
||||
{
|
||||
public string colorType;
|
||||
public int count;
|
||||
}
|
||||
|
||||
public class NoteStatistic { public string colorType; public int count; }
|
||||
[System.Serializable]
|
||||
public class TrackStates
|
||||
{
|
||||
public bool trackFading_active;
|
||||
public TrackState red;
|
||||
public TrackState green;
|
||||
public TrackState yellow;
|
||||
public TrackState purple;
|
||||
public TrackState blue;
|
||||
}
|
||||
|
||||
public class TrackStates { public bool trackFading_active; public TrackState red; public TrackState green; public TrackState yellow; public TrackState purple; public TrackState blue; }
|
||||
[System.Serializable]
|
||||
public class TrackState
|
||||
{
|
||||
public bool isOn;
|
||||
public float fadeTime;
|
||||
}
|
||||
public class TrackState { public bool isOn; public float fadeTime; }
|
||||
}
|
||||
Reference in New Issue
Block a user