优化ui,谱面替换,以及科研模糊
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user