结算重做部分 谱面分装好 编队UI之bug修复
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class BeatmapManager : MonoBehaviour
|
||||
|
||||
@@ -11,6 +11,9 @@ public class BeatmapManager : MonoBehaviour
|
||||
// 音符生成器引用
|
||||
public NoteSpawner noteSpawner;
|
||||
|
||||
// 新增:teamUIController 引用,直接拖拽赋值
|
||||
public teamUIController uiController;
|
||||
|
||||
// Extra fields from beatmap JSON (stored temporarily)
|
||||
[HideInInspector] public string parsedTitle;
|
||||
[HideInInspector] public string parsedComposer;
|
||||
@@ -30,6 +33,23 @@ public class BeatmapManager : MonoBehaviour
|
||||
|
||||
[HideInInspector] public float globalDelaySeconds = 0f;
|
||||
|
||||
// New parsed fields
|
||||
[HideInInspector] public bool parsedEnemyListIsEmpty;
|
||||
[HideInInspector] public ColorSegment[] parsedColorSegments;
|
||||
[HideInInspector] public NoteStatistic[] parsedNoteStatistics;
|
||||
[HideInInspector] public TrackStates parsedTrackStates;
|
||||
|
||||
// Multipliers for difficulty levels
|
||||
public float ezMultiplier = 1f;
|
||||
public float hdMultiplier = 1.5f;
|
||||
public float inMultiplier = 2f;
|
||||
public float imMultiplier = 3f;
|
||||
|
||||
// Total chart score and per-note score fields
|
||||
public int totalChartScore = 1000000; // Default total score for a chart
|
||||
public int perNoteScore;
|
||||
public int leftoverScore;
|
||||
|
||||
// 从 JSON 文件加载谱面数据
|
||||
public void LoadBeatmap(string fileName)
|
||||
{
|
||||
@@ -113,6 +133,15 @@ public class BeatmapManager : MonoBehaviour
|
||||
|
||||
if (!string.IsNullOrEmpty(extra.musicFile)) parsed.musicFile = extra.musicFile;
|
||||
if (!string.IsNullOrEmpty(extra.backgroundFile)) parsed.backgroundFile = extra.backgroundFile;
|
||||
|
||||
// New fields
|
||||
parsedEnemyListIsEmpty = extra.enemyList_isEmpty;
|
||||
if (!parsedEnemyListIsEmpty)
|
||||
{
|
||||
parsedColorSegments = extra.colorSegments;
|
||||
}
|
||||
parsedNoteStatistics = extra.noteStatistics;
|
||||
parsedTrackStates = extra.trackStates;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -131,10 +160,76 @@ public class BeatmapManager : MonoBehaviour
|
||||
parsedDifficulty = parsed.difficulty;
|
||||
}
|
||||
|
||||
// Calculate per-note and leftover scores
|
||||
CalculateNoteScores();
|
||||
|
||||
// NOTE: Do NOT modify parsed.notes here. globalDelaySeconds will be applied to audio playback instead.
|
||||
|
||||
beatmap = parsed;
|
||||
Debug.Log("ParseJsonOnly: parsed beatmap " + beatmap.title);
|
||||
|
||||
// Process colorSegments if not empty (for both test and normal mode)
|
||||
if (!parsedEnemyListIsEmpty && parsedColorSegments != null && parsedColorSegments.Length > 0)
|
||||
{
|
||||
// Determine multiplier based on difficulty
|
||||
float multiplier = ezMultiplier;
|
||||
if (parsedDifficulty == 1) multiplier = hdMultiplier;
|
||||
else if (parsedDifficulty == 2) multiplier = inMultiplier;
|
||||
else if (parsedDifficulty == 3) multiplier = imMultiplier;
|
||||
|
||||
// Calculate total HP
|
||||
float totalHP = parsedNoteAmount * multiplier;
|
||||
|
||||
// Set enemy slot IDs and calculate HP for each enemy
|
||||
List<int> enemyIds = new List<int>();
|
||||
foreach (var segment in parsedColorSegments)
|
||||
{
|
||||
Debug.Log($"Processing colorSegment: enemyID='{segment.enemyID}', percentage={segment.percentage}");
|
||||
int enemyId;
|
||||
if (!int.TryParse(segment.enemyID, out enemyId))
|
||||
{
|
||||
Debug.LogError($"Failed to parse enemyID '{segment.enemyID}' to int");
|
||||
continue;
|
||||
}
|
||||
Debug.LogError($"Parsed enemyId: {enemyId}");
|
||||
enemyIds.Add(enemyId);
|
||||
|
||||
// Calculate individual enemy HP
|
||||
int enemyHP = Mathf.RoundToInt(totalHP * segment.percentage);
|
||||
|
||||
// Find and update the corresponding EnemyData_SO
|
||||
EnemyData_SO[] allEnemies = Resources.LoadAll<EnemyData_SO>("");
|
||||
foreach (var so in allEnemies)
|
||||
{
|
||||
if (so != null && so.enemyID == enemyId)
|
||||
{
|
||||
so.enemy_maxHP = enemyHP;
|
||||
Debug.Log(string.Format("Set enemy {0} maxHP to {1}", enemyId, enemyHP));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update teamUIController
|
||||
if (uiController != null)
|
||||
{
|
||||
Debug.Log($"enemyIds before padding: {string.Join(",", enemyIds)}");
|
||||
// Ensure enemySlotIds has exactly 5 elements, padding with 0 if necessary
|
||||
while (enemyIds.Count < 5)
|
||||
{
|
||||
enemyIds.Add(0);
|
||||
}
|
||||
Debug.Log($"enemyIds after padding: {string.Join(",", enemyIds)}");
|
||||
uiController.enemySlotIds = enemyIds;
|
||||
Debug.LogError($"Assigned enemySlotIds to teamUIController: {string.Join(",", enemyIds)}");
|
||||
uiController.PopulateEnemySOsFromIds();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("teamUIController not assigned in the Inspector");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -197,11 +292,51 @@ public class BeatmapManager : MonoBehaviour
|
||||
public string backgroundFile;
|
||||
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;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
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;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class TrackState
|
||||
{
|
||||
public bool isOn;
|
||||
public float fadeTime;
|
||||
}
|
||||
|
||||
// Parse JSON string to Beatmap and extras, then pass to NoteSpawner
|
||||
private void ProcessJsonAndLoad(string json)
|
||||
{
|
||||
// Debug.LogError("ProcessJsonAndLoad called");
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
Debug.LogError("ProcessJsonAndLoad: json is empty");
|
||||
@@ -259,6 +394,15 @@ public class BeatmapManager : MonoBehaviour
|
||||
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;
|
||||
}
|
||||
parsedNoteStatistics = extra.noteStatistics;
|
||||
parsedTrackStates = extra.trackStates;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -281,11 +425,93 @@ 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);
|
||||
noteSpawner.LoadBeatmap(beatmap);
|
||||
|
||||
// Process colorSegments if not empty
|
||||
if (!parsedEnemyListIsEmpty && parsedColorSegments != null && parsedColorSegments.Length > 0)
|
||||
{
|
||||
// Determine multiplier based on difficulty
|
||||
float multiplier = ezMultiplier;
|
||||
if (parsedDifficulty == 1) multiplier = hdMultiplier;
|
||||
else if (parsedDifficulty == 2) multiplier = inMultiplier;
|
||||
else if (parsedDifficulty == 3) multiplier = imMultiplier;
|
||||
|
||||
// Calculate total HP
|
||||
float totalHP = parsedNoteAmount * multiplier;
|
||||
|
||||
// Set enemy slot IDs and calculate HP for each enemy
|
||||
List<int> enemyIds = new List<int>();
|
||||
foreach (var segment in parsedColorSegments)
|
||||
{
|
||||
Debug.Log($"Processing colorSegment: enemyID='{segment.enemyID}', percentage={segment.percentage}");
|
||||
int enemyId;
|
||||
if (!int.TryParse(segment.enemyID, out enemyId))
|
||||
{
|
||||
Debug.LogError($"Failed to parse enemyID '{segment.enemyID}' to int");
|
||||
continue;
|
||||
}
|
||||
Debug.LogError($"Parsed enemyId: {enemyId}");
|
||||
enemyIds.Add(enemyId);
|
||||
|
||||
// Calculate individual enemy HP
|
||||
int enemyHP = Mathf.RoundToInt(totalHP * segment.percentage);
|
||||
|
||||
// Find and update the corresponding EnemyData_SO
|
||||
EnemyData_SO[] allEnemies = Resources.LoadAll<EnemyData_SO>("");
|
||||
foreach (var so in allEnemies)
|
||||
{
|
||||
if (so != null && so.enemyID == enemyId)
|
||||
{
|
||||
so.enemy_maxHP = enemyHP;
|
||||
Debug.Log(string.Format("Set enemy {0} maxHP to {1}", enemyId, enemyHP));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update teamUIController
|
||||
if (uiController != null)
|
||||
{
|
||||
Debug.Log($"enemyIds before padding: {string.Join(",", enemyIds)}");
|
||||
// Ensure enemySlotIds has exactly 5 elements, padding with 0 if necessary
|
||||
while (enemyIds.Count < 5)
|
||||
{
|
||||
enemyIds.Add(0);
|
||||
}
|
||||
Debug.Log($"enemyIds after padding: {string.Join(",", enemyIds)}");
|
||||
uiController.enemySlotIds = enemyIds;
|
||||
Debug.LogError($"Assigned enemySlotIds to teamUIController: {string.Join(",", enemyIds)}");
|
||||
uiController.PopulateEnemySOsFromIds();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("teamUIController not assigned in the Inspector");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate per-note and leftover scores based on parsedNoteAmount
|
||||
private void CalculateNoteScores()
|
||||
{
|
||||
if (parsedNoteAmount > 0)
|
||||
{
|
||||
perNoteScore = totalChartScore / parsedNoteAmount;
|
||||
leftoverScore = totalChartScore % parsedNoteAmount;
|
||||
Debug.Log($"Calculated perNoteScore: {perNoteScore}, leftoverScore: {leftoverScore}");
|
||||
}
|
||||
else
|
||||
{
|
||||
perNoteScore = 0;
|
||||
leftoverScore = 0;
|
||||
Debug.LogWarning("parsedNoteAmount is zero or less; perNoteScore and leftoverScore set to 0.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,56 +106,9 @@ public class GameManager : MonoBehaviour
|
||||
StartCoroutine(HandleTestModeStartup());
|
||||
return;
|
||||
}
|
||||
|
||||
// 以下为原有流程(已保留注释,未改写)
|
||||
// 在游戏开始时加载并初始化谱面
|
||||
string beatmapFilePath = Path.Combine(Application.streamingAssetsPath, "Emilia_demo.json");
|
||||
|
||||
if (!File.Exists(beatmapFilePath))
|
||||
{
|
||||
Debug.LogError($"谱面文件不存在: {beatmapFilePath}");
|
||||
return;
|
||||
}
|
||||
|
||||
string json = File.ReadAllText(beatmapFilePath);
|
||||
// 假设 Beatmap 是一个已定义的类
|
||||
Beatmap beatmap = JsonUtility.FromJson<Beatmap>(json); // 解析 JSON 为 Beatmap 对象
|
||||
|
||||
if (beatmap == null)
|
||||
{
|
||||
Debug.LogError("谱面解析失败,JSON 格式可能错误!");
|
||||
return;
|
||||
}
|
||||
|
||||
beatmapManager.LoadBeatmap(beatmap); // 传递给 BeatmapManager
|
||||
noteSpawner.LoadBeatmap(beatmap); // 传递给 NoteSpawner
|
||||
|
||||
// 播放背景音乐(延迟播放由 beatmapManager.globalDelaySeconds 决定)
|
||||
if (!string.IsNullOrEmpty(beatmap.musicFile))
|
||||
{
|
||||
AudioClip musicClip = Resources.Load<AudioClip>(beatmap.musicFile);
|
||||
if (musicClip == null)
|
||||
{
|
||||
Debug.LogError($"音乐文件加载失败: {beatmap.musicFile}");
|
||||
}
|
||||
else
|
||||
{
|
||||
musicSource.clip = musicClip;
|
||||
float delay = beatmapManager != null ? beatmapManager.globalDelaySeconds : 0f;
|
||||
if (delay > 0f)
|
||||
{
|
||||
musicSource.PlayDelayed(delay);
|
||||
Debug.Log($"Scheduled music to play after {delay} seconds.");
|
||||
}
|
||||
else
|
||||
{
|
||||
musicSource.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("谱面中 musicFile 为空!");
|
||||
StartCoroutine(HandleNormalModeStartup());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +299,81 @@ public class GameManager : MonoBehaviour
|
||||
UpdateStatusOnConsole("Playback started");
|
||||
}
|
||||
|
||||
private IEnumerator HandleNormalModeStartup()
|
||||
{
|
||||
// 加载谱面但不生成音符
|
||||
string beatmapFilePath = Path.Combine(Application.streamingAssetsPath, "Emilia_demo.json");
|
||||
|
||||
if (!File.Exists(beatmapFilePath))
|
||||
{
|
||||
Debug.LogError($"谱面文件不存在: {beatmapFilePath}");
|
||||
yield break;
|
||||
}
|
||||
|
||||
string json = File.ReadAllText(beatmapFilePath);
|
||||
bool parsed = beatmapManager.ParseJsonOnly(json);
|
||||
if (!parsed)
|
||||
{
|
||||
Debug.LogError("ParseJsonOnly 失败");
|
||||
yield break;
|
||||
}
|
||||
|
||||
// 暂停系统
|
||||
SubscribeToPauseManager();
|
||||
PauseManager.Instance?.Pause(true);
|
||||
UpdateStatusOnConsole("Paused: press Space to start playback");
|
||||
|
||||
// 等待空格
|
||||
while (!Input.GetKeyDown(KeyCode.Space))
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// 恢复
|
||||
PauseManager.Instance?.Pause(false);
|
||||
|
||||
// 生成音符
|
||||
if (beatmapManager.beatmap != null)
|
||||
{
|
||||
noteSpawner.LoadBeatmap(beatmapManager.beatmap);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("beatmap 未解析");
|
||||
yield break;
|
||||
}
|
||||
|
||||
// 播放背景音乐(延迟播放由 beatmapManager.globalDelaySeconds 决定)
|
||||
if (!string.IsNullOrEmpty(beatmapManager.parsedMusicFile))
|
||||
{
|
||||
AudioClip musicClip = Resources.Load<AudioClip>(beatmapManager.parsedMusicFile);
|
||||
if (musicClip == null)
|
||||
{
|
||||
Debug.LogError($"音乐文件加载失败: {beatmapManager.parsedMusicFile}");
|
||||
}
|
||||
else
|
||||
{
|
||||
musicSource.clip = musicClip;
|
||||
float delay = beatmapManager.globalDelaySeconds;
|
||||
if (delay > 0f)
|
||||
{
|
||||
musicSource.PlayDelayed(delay);
|
||||
Debug.Log($"Scheduled music to play after {delay} seconds.");
|
||||
}
|
||||
else
|
||||
{
|
||||
musicSource.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("谱面中 musicFile 为空!");
|
||||
}
|
||||
|
||||
UpdateStatusOnConsole("Playback started");
|
||||
}
|
||||
|
||||
private void UpdateStatusOnConsole(string message)
|
||||
{
|
||||
Debug.Log(message);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using System;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class InputManager : MonoBehaviour
|
||||
{
|
||||
@@ -12,7 +13,7 @@ public class InputManager : MonoBehaviour
|
||||
public TextMeshProUGUI[] trackJudgeTexts = new TextMeshProUGUI[5];
|
||||
|
||||
[Header("按键指示文本(独立于判定文本,五个分别对应按键:D,F,Space,J,K)")]
|
||||
public TextMeshProUGUI[] trackKeyTexts = new TextMeshProUGUI[5];
|
||||
public Text[] trackKeyTexts = new Text[5];
|
||||
|
||||
[Header("是否显示判定文字")]
|
||||
public bool showJudgeText = true;
|
||||
|
||||
@@ -112,6 +112,26 @@ public class Note : BaseNote
|
||||
InputManager.Instance?.ShowJudgeResult(TrackIndex, judgeResult);
|
||||
JudgeSoundManager.Instance?.PlayJudgeSound(judgeResult);
|
||||
teamUIController.Instance?.OnJudgeResult(judgeResult); // 更新combo计数
|
||||
|
||||
// Calculate score addition via AllyCombatant and add to per-track pm sums
|
||||
try
|
||||
{
|
||||
var allyGo = GameObject.Find($"ally_0{TrackIndex + 1}");
|
||||
if (allyGo != null)
|
||||
{
|
||||
var ally = allyGo.GetComponent<AllyCombatant>();
|
||||
if (ally != null)
|
||||
{
|
||||
int added = ally.AddScoreForJudge(judgeResult);
|
||||
ScoreManager.Instance?.AddPmScoreForTrack(TrackIndex, added);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[Note] Failed to add per-track score: {ex}");
|
||||
}
|
||||
|
||||
// Notify SkillBuilder about this note hit so OnNoteHit skills may trigger (tap notes)
|
||||
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { }
|
||||
}
|
||||
@@ -151,6 +171,26 @@ public class Note : BaseNote
|
||||
InputManager.Instance?.ShowJudgeResult(TrackIndex, "Miss");
|
||||
JudgeSoundManager.Instance?.PlayJudgeSound("Miss");
|
||||
teamUIController.Instance?.OnJudgeResult("Miss");
|
||||
|
||||
// Add score for Miss as well (some systems may give 0)
|
||||
try
|
||||
{
|
||||
var allyGo = GameObject.Find($"ally_0{TrackIndex + 1}");
|
||||
if (allyGo != null)
|
||||
{
|
||||
var ally = allyGo.GetComponent<AllyCombatant>();
|
||||
if (ally != null)
|
||||
{
|
||||
int added = ally.AddScoreForJudge("Miss");
|
||||
ScoreManager.Instance?.AddPmScoreForTrack(TrackIndex, added);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[Note] Failed to add per-track score for Miss: {ex}");
|
||||
}
|
||||
|
||||
// Notify SkillBuilder about Miss so OnNoteHit skills configured for Miss can trigger
|
||||
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, "Miss", SkillDefinition.NoteTypeTrigger.Tap); } catch { }
|
||||
// InputManager.Instance?.ShowJudgeResult(TrackIndex, "Miss"); // 已在HandlePress中调用 for manual presses
|
||||
|
||||
Reference in New Issue
Block a user