优化ui,谱面替换,以及科研模糊

This commit is contained in:
2026-02-25 03:44:41 +08:00
parent 332307d18c
commit 0b75e93f71
114 changed files with 160279 additions and 290 deletions
+96 -2
View File
@@ -94,6 +94,7 @@ public class SongData : ScriptableObject
public Dictionary<int, int> personalRecordMap = new Dictionary<int, int>();
public Dictionary<int, int> idolRecordMap = new Dictionary<int, int>();
public Dictionary<int, int> chartScoreMap = new Dictionary<int, int>();
public Dictionary<int, float> levelProgressMap = new Dictionary<int, float>();
public Dictionary<int, TextAsset> chartFileMap = new Dictionary<int, TextAsset>();
public List<ChartFileEntry> chartFiles = new List<ChartFileEntry>();
@@ -286,6 +287,7 @@ public class SongData : ScriptableObject
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
if (chartFileMap == null) chartFileMap = new Dictionary<int, TextAsset>();
if (chartFiles == null) chartFiles = new List<ChartFileEntry>();
@@ -365,6 +367,7 @@ public class SongData : ScriptableObject
if (serializable != null)
{
serializable.ApplyTo(this);
SyncEntriesFromMaps();
// Debug.Log($"[SongData] {songName} data restored.");
}
}
@@ -375,6 +378,46 @@ public class SongData : ScriptableObject
}
}
public void ClearSaveDataAndReload()
{
game_enterTimes = 0;
time_totalPlayingTime = 0f;
current_levelProgress = 0f;
_if_level_is_EASE = false;
max_comboRecord = 0;
personalRecord = 0;
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
else personalRecordMap.Clear();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
else idolRecordMap.Clear();
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
else chartScoreMap.Clear();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
else levelProgressMap.Clear();
if (chartFiles != null)
{
for (int i = 0; i < chartFiles.Count; i++)
{
ChartFileEntry entry = chartFiles[i];
if (entry == null) continue;
entry.lastScoreForThisDifficulty = 0;
entry.chartPersonalRecordForThisDifficulty = 0;
entry.idolPersonalRecordForThisDifficulty = 0;
entry.totalPersonalRecordForThisDifficulty = 0;
entry.levelProgressForThisDifficulty = 0f;
}
}
UpdateOverallRecordsFromEntries();
SavePersistent();
LoadPersistent();
}
/// <summary>
/// 当检测到篡改或文件损坏时,重置所有动态记录并立即重新保存文件以恢复合法性。
/// </summary>
@@ -400,6 +443,9 @@ public class SongData : ScriptableObject
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
else chartScoreMap.Clear();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
else levelProgressMap.Clear();
// 3. 立即调用保存方法,生成一个新的、带有正确哈希值的合法文件
SavePersistent();
@@ -480,6 +526,7 @@ public class SongData : ScriptableObject
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
int total = pmScore + idolScore;
int currentBestTotal = GetPersonalRecord(difficulty) + GetIdolRecord(difficulty);
@@ -501,12 +548,17 @@ public class SongData : ScriptableObject
entry.totalPersonalRecordForThisDifficulty = total;
}
float newProgress = maxScoreSum > 0 ? Mathf.Clamp01((float)total / (float)maxScoreSum) : 0f;
float newProgress = maxScoreSum > 0 ? (float)total / (float)maxScoreSum : 0f;
if (newProgress > entry.levelProgressForThisDifficulty)
{
entry.levelProgressForThisDifficulty = newProgress;
}
if (!levelProgressMap.ContainsKey(difficulty) || newProgress > levelProgressMap[difficulty])
{
levelProgressMap[difficulty] = newProgress;
}
entry.lastScoreForThisDifficulty = total;
}
@@ -517,6 +569,40 @@ public class SongData : ScriptableObject
SavePersistent();
}
/// <summary>
/// 将 Dictionary 中的数据同步回 ChartFileEntry 列表,确保 SO 内存数据与持久化数据一致。
/// </summary>
public void SyncEntriesFromMaps()
{
if (chartFiles == null) return;
foreach (var entry in chartFiles)
{
if (entry == null) continue;
int diff = entry.difficulty;
if (personalRecordMap != null && personalRecordMap.ContainsKey(diff))
entry.chartPersonalRecordForThisDifficulty = personalRecordMap[diff];
if (idolRecordMap != null && idolRecordMap.ContainsKey(diff))
entry.idolPersonalRecordForThisDifficulty = idolRecordMap[diff];
if (personalRecordMap != null && personalRecordMap.ContainsKey(diff) && idolRecordMap != null && idolRecordMap.ContainsKey(diff))
entry.totalPersonalRecordForThisDifficulty = personalRecordMap[diff] + idolRecordMap[diff];
else if (personalRecordMap != null && personalRecordMap.ContainsKey(diff))
entry.totalPersonalRecordForThisDifficulty = personalRecordMap[diff];
if (levelProgressMap != null && levelProgressMap.ContainsKey(diff))
entry.levelProgressForThisDifficulty = levelProgressMap[diff];
if (chartScoreMap != null && chartScoreMap.ContainsKey(diff))
entry.lastScoreForThisDifficulty = chartScoreMap[diff];
}
UpdateOverallRecordsFromEntries();
}
public void GetAbsoluteHighestScore(out int highestScore, out int bestDifficulty, out string bestDifficultyName)
{
highestScore = 0;
@@ -641,7 +727,11 @@ public class SongData : ScriptableObject
SongDataSerializable serializable = new SongDataSerializable(this);
string json = JsonUtility.ToJson(serializable);
SongDataSerializable roundTrip = JsonUtility.FromJson<SongDataSerializable>(json);
if (roundTrip != null) roundTrip.ApplyTo(this);
if (roundTrip != null)
{
roundTrip.ApplyTo(this);
SyncEntriesFromMaps();
}
}
public void UpdateIdolRecord(int difficulty, int newIdolScore)
@@ -726,6 +816,7 @@ public class SongData : ScriptableObject
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
if (chartFiles == null) return;
@@ -746,6 +837,9 @@ public class SongData : ScriptableObject
if (!chartScoreMap.ContainsKey(entry.difficulty) || entry.lastScoreForThisDifficulty > chartScoreMap[entry.difficulty])
chartScoreMap[entry.difficulty] = entry.lastScoreForThisDifficulty;
if (!levelProgressMap.ContainsKey(entry.difficulty) || entry.levelProgressForThisDifficulty > levelProgressMap[entry.difficulty])
levelProgressMap[entry.difficulty] = entry.levelProgressForThisDifficulty;
int p = personalRecordMap.ContainsKey(entry.difficulty) ? personalRecordMap[entry.difficulty] : 0;
int idol = idolRecordMap.ContainsKey(entry.difficulty) ? idolRecordMap[entry.difficulty] : 0;
entry.totalPersonalRecordForThisDifficulty = p + idol;
@@ -408,25 +408,7 @@ MonoBehaviour:
song_songSerialID: 0
selected_boarder: {fileID: 4758992877847013954}
fade_image: {fileID: 8405752277710552670}
easePercent: 1
ssPercent: 0.95
sPercent: 0.9
aPercent: 0.8
bPercent: 0.7
cPercent: 0.6
dPercent: 0.5
ePercent: 0.4
fPercent: 0.3
easeSprite: {fileID: 21300000, guid: 1b7d3065f66d15b45b170444124b57ca, type: 3}
ssSprite: {fileID: 21300000, guid: c218e48d1b0d49541bee4a99fffc738c, type: 3}
sSprite: {fileID: 21300000, guid: 8f6b0c65c13b1ed478dd3f37e989f2c5, type: 3}
aSprite: {fileID: 21300000, guid: 61dd84e2a30a06a4b913933e34767f4b, type: 3}
bSprite: {fileID: 21300000, guid: ff77da93eaa5bdd44966dad03e35f56b, type: 3}
cSprite: {fileID: 21300000, guid: a919404cd6477be4c878442426de1d13, type: 3}
dSprite: {fileID: 21300000, guid: a3a60d742fbaa4b4081c9b4b73da8b96, type: 3}
eSprite: {fileID: 21300000, guid: 698d2276a92e5754d9064e9e0c3494bf, type: 3}
fSprite: {fileID: 21300000, guid: 37afeb5a99b12ff4995ab22436f2c8c5, type: 3}
ufSprite: {fileID: 21300000, guid: dc19bff00a17ee14ebbb6bbedf411046, type: 3}
rankConfig: {fileID: 11400000, guid: 951debb97a9b89f48885c82bb601533a, type: 2}
minAlpha: 0
maxAlpha: 0.25
blinkDuration: 2
@@ -26,27 +26,8 @@ public class SongButton : MonoBehaviour
public Image selected_boarder;
public Image fade_image;
[Header("Inspector")]
public float easePercent = 1f;
public float ssPercent = 0.95f;
public float sPercent = 0.9f;
public float aPercent = 0.8f;
public float bPercent = 0.7f;
public float cPercent = 0.6f;
public float dPercent = 0.5f;
public float ePercent = 0.4f;
public float fPercent = 0.3f;
[Header("Inspector")]
public Sprite easeSprite;
public Sprite ssSprite;
public Sprite sSprite;
public Sprite aSprite;
public Sprite bSprite;
public Sprite cSprite;
public Sprite dSprite;
public Sprite eSprite;
public Sprite fSprite;
public Sprite ufSprite;
[Header("Rank Configuration")]
public RankConfig rankConfig;
[Header("Fade Image Settings")]
public float minAlpha = 0f;
@@ -111,38 +92,14 @@ public class SongButton : MonoBehaviour
if (scoreLevelImage != null)
{
Sprite chosenSprite;
float baseScore = 2000000f;
if (bestTotal <= 0)
if (rankConfig != null)
{
chosenSprite = ufSprite;
scoreLevelImage.sprite = rankConfig.GetRankSprite(bestTotal);
}
else
{
if (bestTotal >= baseScore * easePercent && easeSprite != null)
chosenSprite = easeSprite;
else if (bestTotal >= baseScore * ssPercent && ssSprite != null)
chosenSprite = ssSprite;
else if (bestTotal >= baseScore * sPercent && sSprite != null)
chosenSprite = sSprite;
else if (bestTotal >= baseScore * aPercent && aSprite != null)
chosenSprite = aSprite;
else if (bestTotal >= baseScore * bPercent && bSprite != null)
chosenSprite = bSprite;
else if (bestTotal >= baseScore * cPercent && cSprite != null)
chosenSprite = cSprite;
else if (bestTotal >= baseScore * dPercent && dSprite != null)
chosenSprite = dSprite;
else if (bestTotal >= baseScore * ePercent && eSprite != null)
chosenSprite = eSprite;
else if (bestTotal >= baseScore * fPercent && fSprite != null)
chosenSprite = fSprite;
else
chosenSprite = ufSprite;
Debug.LogWarning("SongButton: rankConfig is not assigned!");
}
scoreLevelImage.sprite = chosenSprite;
}
// Determine displayed difficulty: show the highest difficultyLEVEL present in chartFiles (if any)
+34 -1
View File
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using UnityEngine;
@@ -28,6 +28,14 @@ public class SongDataSerializable
public List<IntIntEntry> idolRecordList = new List<IntIntEntry>();
public List<IntIntEntry> chartScoreList = new List<IntIntEntry>();
[System.Serializable]
public struct IntFloatEntry
{
public int key;
public float value;
}
public List<IntFloatEntry> levelProgressList = new List<IntFloatEntry>();
public SongDataSerializable() { }
public SongDataSerializable(SongData source)
@@ -48,6 +56,7 @@ public class SongDataSerializable
this.personalRecordList = DictToList(source.personalRecordMap);
this.idolRecordList = DictToList(source.idolRecordMap);
this.chartScoreList = DictToList(source.chartScoreMap);
this.levelProgressList = DictToListFloat(source.levelProgressMap);
}
/// <summary>
@@ -70,6 +79,7 @@ public class SongDataSerializable
ListToDict(this.personalRecordList, target.personalRecordMap);
ListToDict(this.idolRecordList, target.idolRecordMap);
ListToDict(this.chartScoreList, target.chartScoreMap);
ListToDictFloat(this.levelProgressList, target.levelProgressMap);
}
private List<IntIntEntry> DictToList(Dictionary<int, int> dict)
@@ -94,4 +104,27 @@ public class SongDataSerializable
dict[entry.key] = entry.value;
}
}
private List<IntFloatEntry> DictToListFloat(Dictionary<int, float> dict)
{
List<IntFloatEntry> list = new List<IntFloatEntry>();
if (dict != null)
{
foreach (var kvp in dict)
{
list.Add(new IntFloatEntry { key = kvp.Key, value = kvp.Value });
}
}
return list;
}
private void ListToDictFloat(List<IntFloatEntry> list, Dictionary<int, float> dict)
{
if (list == null || dict == null) return;
dict.Clear();
foreach (var entry in list)
{
dict[entry.key] = entry.value;
}
}
}
+63 -1
View File
@@ -1,5 +1,6 @@
using UnityEngine;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class SongDetailsUI : MonoBehaviour
{
@@ -26,6 +27,15 @@ public class SongDetailsUI : MonoBehaviour
public Text thisSong_progressText;
public Text thisSong_lastScoreText; // will show last run total score if available
public Text idolRecordText;
public TextMeshProUGUI timeSpentText;
public TextMeshProUGUI enterTimeText;
public Text difficultyIdText;
public Image progressImage;
public GameObject progressNumberObject;
public TextMeshProUGUI progressPercentText;
public Image rankLevel_img;
public RankConfig rc;
//public Image songImage;
public int id_of_thisSong;
@@ -63,6 +73,9 @@ public class SongDetailsUI : MonoBehaviour
bpmText.text = "BPM : " + currentSong.bpm.ToString();
profound_image.sprite = currentSong.fullscreen_songPicture;
if (timeSpentText != null) timeSpentText.text = "PlayTime: " + currentSong.time_totalPlayingTime.ToString("F0") + "s";
if (enterTimeText != null) enterTimeText.text = "PlayCount: " + currentSong.game_enterTimes.ToString();
id_of_thisSong = currentSong.songID;
detail_informations_text.text =
$"{currentSong.artistName}" + " - " +
@@ -127,6 +140,14 @@ public class SongDetailsUI : MonoBehaviour
difficultyText.text = entry.difficultyLEVEL.ToString();
difficultyDesciptionText.text = entry.difficultyDescription;
if (difficultyIdText != null)
difficultyIdText.text = entry.difficultyLEVEL.ToString();
if (progressImage != null)
progressImage.fillAmount = entry.levelProgressForThisDifficulty;
UpdateProgressUI(entry.levelProgressForThisDifficulty);
// read values from SongData (SO)
int chartPersonal = currentSong.GetPersonalRecord(difficulty); // Documentation text normalized.
int idol = currentSong.GetIdolRecord(difficulty); // Documentation text normalized.
@@ -158,6 +179,9 @@ public class SongDetailsUI : MonoBehaviour
thisSong_lastScoreText.text = lastRun.ToString();
}
if (rankLevel_img != null && rc != null)
rankLevel_img.sprite = rc.GetRankSprite(total);
// also keep per-entry convenience fields in sync for inspector visibility
entry.chartPersonalRecordForThisDifficulty = chartPersonal;
entry.idolPersonalRecordForThisDifficulty = idol;
@@ -166,6 +190,11 @@ public class SongDetailsUI : MonoBehaviour
else
{
difficultyText.text = difficulty.ToString();
if (difficultyIdText != null)
difficultyIdText.text = difficulty.ToString();
if (progressImage != null)
progressImage.fillAmount = 0f;
UpdateProgressUI(0f);
difficultyDesciptionText.text = "";
personalRecordText.text = "0";
if (idolRecordText != null)
@@ -174,6 +203,39 @@ public class SongDetailsUI : MonoBehaviour
chartScoreText.text = "0";
if (thisSong_lastScoreText != null)
thisSong_lastScoreText.text = "0";
if (rankLevel_img != null && rc != null)
rankLevel_img.sprite = rc.defaultSprite;
}
}
private void UpdateProgressUI(float progress)
{
// 1. Update Text (can exceed 100%)
if (progressPercentText != null)
{
progressPercentText.text = Mathf.FloorToInt(progress * 100f).ToString() + "%";
}
// 2. Clamp for visual elements (fillAmount and Object position)
float clampedProgress = Mathf.Clamp01(progress);
// Update fillAmount again just in case, though handled in caller
if (progressImage != null)
{
progressImage.fillAmount = clampedProgress;
}
// 3. Update Object Position (Linear transformation: 0% -> -785, 100% -> -195)
if (progressNumberObject != null)
{
RectTransform rect = progressNumberObject.GetComponent<RectTransform>();
if (rect != null)
{
float targetX = Mathf.Lerp(-785f, -195f, clampedProgress);
Vector2 anchoredPos = rect.anchoredPosition;
anchoredPos.x = targetX;
rect.anchoredPosition = anchoredPos;
}
}
}
+3 -1
View File
@@ -1,10 +1,11 @@
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections;
using System;
using DG.Tweening;
using Bansonic;
public class selected_songInfo : MonoBehaviour
{
@@ -954,6 +955,7 @@ public class selected_songInfo : MonoBehaviour
if (chart == null)
{
Debug.LogError($"QuickEnter aborted: Song '{sd.songName}' has no chart file for difficulty {sd.thisLevel_selectedDifficultyID}.");
gNotice.error.display("未找到此难度的关卡");
return;
}