修复一堆bug 加入粒子系统代替原击打特效 焕新长音符逻辑 修复多重计分 更新判定管理和音符生成器 搞了一个免费包

This commit is contained in:
FloatGaming
2025-12-18 03:26:52 +08:00
parent 1dd6c95ec9
commit a7d8d71d10
1572 changed files with 1658779 additions and 527 deletions
+156 -182
View File
@@ -4,14 +4,13 @@ using UnityEngine.UI;
using System.Collections.Generic;
public class BeatmapManager : MonoBehaviour
{
public Beatmap beatmap; // 当前谱面数据
// 音符生成器引用
public NoteSpawner noteSpawner;
// 新增:teamUIController 引用,直接拖拽赋值
// teamUIController 引用,直接拖拽赋值
public teamUIController uiController;
// Extra fields from beatmap JSON (stored temporarily)
@@ -40,15 +39,23 @@ public class BeatmapManager : MonoBehaviour
[HideInInspector] public TrackStates parsedTrackStates;
// Multipliers for difficulty levels
[Header("Difficulty Multipliers")]
public float ezMultiplier = 1f;
public float hdMultiplier = 1.5f;
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;
// Total chart score and per-note score fields
public int totalChartScore = 1000000; // Default total score for a chart
public int perNoteScore;
public int leftoverScore;
public int totalChartScore = 1000000; // Default total score for a chart
public int perNoteScore;
public int leftoverScore;
// 从 JSON 文件加载谱面数据
public void LoadBeatmap(string fileName)
@@ -66,7 +73,7 @@ public class BeatmapManager : MonoBehaviour
}
}
// 新增:从原始 JSON 字符串加载谱面(允许任意磁盘路径先读取后传入)
// 从原始 JSON 字符串加载谱面(允许任意磁盘路径先读取后传入)
public void LoadBeatmapFromJsonString(string json)
{
if (string.IsNullOrEmpty(json))
@@ -77,7 +84,7 @@ public class BeatmapManager : MonoBehaviour
ProcessJsonAndLoad(json);
}
// 新增:解析 JSON 但不启动 NoteSpawner(用于 test mode 的延迟开始)
// 解析 JSON 但不启动 NoteSpawner(用于 test mode 的延迟开始)
public bool ParseJsonOnly(string json)
{
if (string.IsNullOrEmpty(json))
@@ -168,67 +175,8 @@ public class BeatmapManager : MonoBehaviour
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.Log($"Failed to parse enemyID '{segment.enemyID}' to int");
continue;
}
Debug.Log($"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.LogWarning($"Assigned enemySlotIds to teamUIController: {string.Join(",", enemyIds)}");
uiController.PopulateEnemySOsFromIds();
}
else
{
Debug.LogError("teamUIController not assigned in the Inspector");
}
}
// 调用统一的敌人处理逻辑(包含 HP 计算和设置)
SetupEnemiesAndHP();
return true;
}
@@ -270,73 +218,90 @@ public class BeatmapManager : MonoBehaviour
// 加载默认谱面
LoadBeatmap("Emilia_demo.json"); // 加载并实例化音符
}
}
// Helper class used to parse extra fields from JSON that Beatmap doesn't define
[System.Serializable]
private class BeatmapExtra
// 获取当前难度乘数
private float GetCurrentDifficultyMultiplier()
{
public string title;
public string composer;
public string illustrator;
public string charter;
public string beatmapId;
public int duration; // as int per request
public int bpm; // as int per request
public int difficulty;
public string difficultyName;
public string createdDate;
public string lastSavedTime;
public string musicFile;
public string backgroundFile;
public int noteAmount;
public float globalDelaySeconds;
// New fields
public bool enemyList_isEmpty;
public ColorSegment[] colorSegments;
public NoteStatistic[] noteStatistics;
public TrackStates trackStates;
// 假设 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; // 默认值
}
// New serializable classes for the extra fields
[System.Serializable]
public class ColorSegment
// 统一处理敌人 ID 提取、发送给 UI 以及 HP 计算的逻辑
private void SetupEnemiesAndHP()
{
public string enemyID;
public float percentage;
}
if (uiController == null)
{
Debug.LogError("teamUIController not assigned in BeatmapManager Inspector");
return;
}
[System.Serializable]
public class NoteStatistic
{
public string colorType;
public int count;
}
if (!parsedEnemyListIsEmpty && parsedColorSegments != null && parsedColorSegments.Length > 0)
{
// 1. 提取敌人 IDs
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;
}
enemyIds.Add(enemyId);
}
[System.Serializable]
public class TrackStates
{
public bool trackFading_active;
public TrackState red;
public TrackState green;
public TrackState yellow;
public TrackState purple;
public TrackState blue;
}
// 2. 补齐 5 个槽位
while (enemyIds.Count < 5)
{
enemyIds.Add(0);
}
[System.Serializable]
public class TrackState
{
public bool isOn;
public float fadeTime;
// 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; // 防止除零
// 计算单个敌人 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();
}
}
// 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");
@@ -433,69 +398,18 @@ public class BeatmapManager : MonoBehaviour
// 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)
if (noteSpawner != null)
{
// 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");
}
noteSpawner.LoadBeatmap(beatmap);
}
else
{
Debug.LogError("NoteSpawner is null in BeatmapManager.");
}
// 调用统一的敌人处理逻辑(包含 HP 计算和设置)
SetupEnemiesAndHP();
}
// Calculate per-note and leftover scores based on parsedNoteAmount
@@ -514,4 +428,64 @@ public class BeatmapManager : MonoBehaviour
Debug.LogWarning("parsedNoteAmount is zero or less; perNoteScore and leftoverScore set to 0.");
}
}
}
// Helper class used to parse extra fields from JSON that Beatmap doesn't define
[System.Serializable]
private class BeatmapExtra
{
public string title;
public string composer;
public string illustrator;
public string charter;
public string beatmapId;
public int duration; // as int per request
public int bpm; // as int per request
public int difficulty;
public string difficultyName;
public string createdDate;
public string lastSavedTime;
public string musicFile;
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;
}
}