ui基本完毕,修了一大把的bug

This commit is contained in:
FloatGaming
2026-07-13 02:28:39 +08:00
parent 1e20d73e90
commit fd22501f71
958 changed files with 378289 additions and 41038 deletions
@@ -813,7 +813,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 312.3, y: 0}
m_AnchoredPosition: {x: 312.3, y: 4}
m_SizeDelta: {x: 200, y: 200}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3397289974922444082
@@ -1039,7 +1039,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: -44.5}
m_AnchoredPosition: {x: 0, y: -47}
m_SizeDelta: {x: 116.5648, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4000680467974343741
+184 -24
View File
@@ -12,6 +12,8 @@ using UnityEngine.SceneManagement;
public class SongDetailsUI : MonoBehaviour
{
private const string BackSceneName = "selectYourSongFirst";
private const float ProgressNumberMinX = -370f;
private const float ProgressNumberMaxX = 362f;
[Header("this_song_SO")]
public ScriptableObject this_song_SO;
@@ -53,6 +55,7 @@ public class SongDetailsUI : MonoBehaviour
public Image progressImage;
public GameObject progressNumberObject;
public TextMeshProUGUI progressPercentText;
public Text progressPercentText2;
public Image rankLevel_img;
public RankConfig rc;
@@ -83,6 +86,21 @@ public class SongDetailsUI : MonoBehaviour
private UnityAction difficultyHdAction;
private UnityAction difficultyInAction;
private UnityAction difficultyImAction;
private RectTransform progressImageRect;
private RectTransform progressNumberRect;
private float progressImageFullWidth = -1f;
private float progressImageLeftEdgeX;
private float progressImageScaleX = 1f;
private bool progressUsesMaskWidthMode;
[SerializeField] private float progressTweenDuration = 0.35f;
[SerializeField] private Ease progressTweenEase = Ease.OutCubic;
private Tween progressBarTween;
private Tween progressNumberTween;
private Tween progressTextTween;
private float currentProgressVisual;
private float currentProgressTextValue;
private bool hasStarted;
private SongData ResolveCurrentSong()
{
@@ -109,6 +127,7 @@ public class SongDetailsUI : MonoBehaviour
private void OnEnable()
{
currentSong = ResolveCurrentSong();
CacheProgressUiGeometry(forceRefresh: false);
ArenaRoomService roomService = ArenaRoomService.Instance;
if (roomService != null)
@@ -143,7 +162,12 @@ public class SongDetailsUI : MonoBehaviour
BindDifficultyButtons();
PrepareDifficultyButtons();
SyncSongDisplay(true);
if (hasStarted)
{
ResetProgressVisualState();
SyncSongDisplay(true);
}
}
private void Update()
@@ -153,6 +177,8 @@ public class SongDetailsUI : MonoBehaviour
private void OnDisable()
{
KillProgressTweens();
ArenaRoomService roomService = ArenaRoomService.Instance;
if (roomService != null)
{
@@ -328,9 +354,12 @@ public class SongDetailsUI : MonoBehaviour
void Start()
{
hasStarted = true;
picDetail.SetActive(false);
CacheProgressUiGeometry(forceRefresh: false);
BindDifficultyButtons();
PrepareDifficultyButtons();
ResetProgressVisualState();
SyncSongDisplay(true);
}
@@ -757,9 +786,6 @@ public class SongDetailsUI : MonoBehaviour
if (difficultyIdText != null)
difficultyIdText.text = entry.difficultyLEVEL.ToString("0.0");
if (progressImage != null)
progressImage.fillAmount = entry.levelProgressForThisDifficulty;
UpdateProgressUI(entry.levelProgressForThisDifficulty);
// read values from SongData (SO)
@@ -807,8 +833,6 @@ public class SongDetailsUI : MonoBehaviour
difficultyText.text = difficulty.ToString();
if (difficultyIdText != null)
difficultyIdText.text = difficulty.ToString();
if (progressImage != null)
progressImage.fillAmount = 0f;
UpdateProgressUI(0f);
if (difficultyDesciptionText != null)
difficultyDesciptionText.text = "";
@@ -827,33 +851,169 @@ public class SongDetailsUI : MonoBehaviour
private void UpdateProgressUI(float progress)
{
// 1. Update Text (can exceed 100%)
if (progressPercentText != null)
{
progressPercentText.text = Mathf.FloorToInt(progress * 100f).ToString() + "%";
}
CacheProgressUiGeometry(forceRefresh: false);
// 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)
AnimateProgressVisual(clampedProgress);
AnimateProgressText(progress);
}
private void CacheProgressUiGeometry(bool forceRefresh)
{
if (progressImage != null && (forceRefresh || progressImageRect == null))
{
progressImage.fillAmount = clampedProgress;
progressImageRect = progressImage.rectTransform;
}
// 3. Update Object Position (Linear transformation: 0% -> -785, 100% -> -195)
if (progressNumberObject != null)
if (progressNumberObject != null && (forceRefresh || progressNumberRect == 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;
}
progressNumberRect = progressNumberObject.GetComponent<RectTransform>();
}
if (progressImageRect == null)
{
return;
}
if (forceRefresh || progressImageFullWidth <= 0f)
{
progressImageFullWidth = progressImageRect.sizeDelta.x;
progressImageScaleX = Mathf.Abs(progressImageRect.localScale.x);
progressImageLeftEdgeX = progressImageRect.anchoredPosition.x - (progressImageFullWidth * progressImageScaleX * 0.5f);
}
progressUsesMaskWidthMode = progressImage != null
&& progressImage.GetComponent<Mask>() != null
&& progressImage.transform.childCount > 0;
}
private void ResetProgressVisualState()
{
CacheProgressUiGeometry(forceRefresh: false);
KillProgressTweens();
currentProgressVisual = 0f;
currentProgressTextValue = 0f;
ApplyProgressBarVisual(0f);
ApplyProgressNumberPosition(0f);
ApplyProgressTextValue(0f);
}
private void KillProgressTweens()
{
if (progressBarTween != null && progressBarTween.IsActive())
{
progressBarTween.Kill();
}
if (progressNumberTween != null && progressNumberTween.IsActive())
{
progressNumberTween.Kill();
}
if (progressTextTween != null && progressTextTween.IsActive())
{
progressTextTween.Kill();
}
}
private void AnimateProgressVisual(float clampedProgress)
{
KillProgressTweens();
progressBarTween = DOTween.To(
() => currentProgressVisual,
value =>
{
currentProgressVisual = value;
ApplyProgressBarVisual(value);
},
clampedProgress,
progressTweenDuration)
.SetEase(progressTweenEase)
.OnComplete(() =>
{
currentProgressVisual = clampedProgress;
ApplyProgressBarVisual(clampedProgress);
});
if (progressNumberRect != null)
{
progressNumberTween = progressNumberRect
.DOAnchorPosX(Mathf.Lerp(ProgressNumberMinX, ProgressNumberMaxX, clampedProgress), progressTweenDuration)
.SetEase(progressTweenEase);
}
}
private void AnimateProgressText(float targetProgressValue)
{
float safeTargetValue = Mathf.Max(0f, targetProgressValue);
progressTextTween = DOTween.To(
() => currentProgressTextValue,
value =>
{
currentProgressTextValue = value;
ApplyProgressTextValue(value);
},
safeTargetValue,
progressTweenDuration)
.SetEase(progressTweenEase)
.OnComplete(() =>
{
currentProgressTextValue = safeTargetValue;
ApplyProgressTextValue(safeTargetValue);
});
}
private void ApplyProgressNumberPosition(float clampedProgress)
{
if (progressNumberRect == null)
{
return;
}
Vector2 anchoredPos = progressNumberRect.anchoredPosition;
anchoredPos.x = Mathf.Lerp(ProgressNumberMinX, ProgressNumberMaxX, clampedProgress);
progressNumberRect.anchoredPosition = anchoredPos;
}
private void ApplyProgressTextValue(float progressValue)
{
int percentValue = Mathf.FloorToInt(Mathf.Max(0f, progressValue) * 100f);
string textValue = percentValue.ToString() + "%";
if (progressPercentText != null)
{
progressPercentText.text = textValue;
}
if (progressPercentText2 != null)
{
progressPercentText2.text = textValue;
}
}
private void ApplyProgressBarVisual(float clampedProgress)
{
if (progressImage == null)
{
return;
}
if (progressUsesMaskWidthMode && progressImageRect != null && progressImageFullWidth > 0f)
{
float newWidth = progressImageFullWidth * clampedProgress;
progressImageRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newWidth);
Vector2 anchoredPos = progressImageRect.anchoredPosition;
anchoredPos.x = progressImageLeftEdgeX + (newWidth * progressImageScaleX * 0.5f);
progressImageRect.anchoredPosition = anchoredPos;
return;
}
progressImage.fillAmount = clampedProgress;
}
private ChartFileEntry GetChartEntry(int difficulty)
+32
View File
@@ -42,6 +42,11 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
private static List<dlcButton> allButtons = new List<dlcButton>();
private static int selectedIndex = -1;
private const string PlayerPrefsKey = "dlc_selected_index";
private const string SelectedDlcIdPrefsKey = "dlc_selected_id";
// When true, Select() applies visual selection but does NOT persist to
// PlayerPrefs. Used during restore so re-selecting (including fallback)
// never overwrites the user's genuine last choice.
public static bool SuppressSelectionPersist = false;
private int instanceIndex = -1;
private Coroutine hoverCoroutine;
@@ -202,11 +207,38 @@ public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandle
{
ApplySelectionToAll(instanceIndex);
selectedIndex = instanceIndex;
if (SuppressSelectionPersist)
{
if (VerboseLogs) Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) without persisting (restore in progress)");
return;
}
PlayerPrefs.SetInt(PlayerPrefsKey, selectedIndex);
int dlcId = ResolveOwnDlcId();
if (dlcId > 0)
{
PlayerPrefs.SetInt(SelectedDlcIdPrefsKey, dlcId);
}
PlayerPrefs.Save();
if (VerboseLogs) Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) and saved to PlayerPrefs");
}
public static string SelectedDlcIdKey => SelectedDlcIdPrefsKey;
public int ResolveOwnDlcId()
{
if (dlcDataSO != null && dlcDataSO.dlcID > 0)
{
return dlcDataSO.dlcID;
}
if (dlcID != null && int.TryParse(dlcID.text, out int parsedId))
{
return parsedId;
}
return 0;
}
private static void ApplySelectionToAll(int selectIdx)
{
for (int i = 0; i < allButtons.Count; i++)
+35 -25
View File
@@ -7,7 +7,7 @@ public class loadDlcListPrefab : MonoBehaviour
{
private static readonly bool VerboseLogs = false;
private const string RuntimeInstalledColumnName = "Installed DLC";
private const int DefaultFallbackDlcId = 66001;
private const int DefaultFallbackDlcId = 66002;
private const string DlcSelectedIndexPrefsKey = "dlc_selected_index";
[System.Serializable]
public class Column
@@ -145,7 +145,19 @@ public class loadDlcListPrefab : MonoBehaviour
}
SongSelectUI.ForceFirstSongOnNextRestore = forceFirstSong;
targetButton.OnButtonClicked_ShowSongs();
// Restore is read-only: applying the selection here (including the
// fallback DLC) must not overwrite the user's genuine last choice.
// Select() runs synchronously inside OnButtonClicked_ShowSongs, so the
// suppression window only needs to span this call.
dlcButton.SuppressSelectionPersist = true;
try
{
targetButton.OnButtonClicked_ShowSongs();
}
finally
{
dlcButton.SuppressSelectionPersist = false;
}
if (VerboseLogs)
{
@@ -164,6 +176,20 @@ public class loadDlcListPrefab : MonoBehaviour
return null;
}
// Prefer restoring by the saved DLC id, which is stable across
// session-to-session ordering changes (e.g. runtime-installed DLCs).
int savedDlcId = PlayerPrefs.GetInt(dlcButton.SelectedDlcIdKey, 0);
if (savedDlcId > 0)
{
dlcButton savedById = FindButtonByDlcId(allButtons, savedDlcId);
if (savedById != null && HasSavedSongSelection(savedById))
{
forceFirstSong = false;
return savedById;
}
}
// Fall back to the saved positional index for legacy saves.
int savedIndex = PlayerPrefs.GetInt(DlcSelectedIndexPrefsKey, 0);
if (savedIndex >= 0 && savedIndex < allButtons.Length)
{
@@ -221,14 +247,12 @@ public class loadDlcListPrefab : MonoBehaviour
return false;
}
// Only the songID key proves a genuine user click: SongButton.OnSongButtonClick
// always writes it alongside the index. The index key alone is unreliable because
// RestoreSelectedSongForCurrentDlc auto-writes it to 0 on mere display, so relying
// on it would treat any browsed-but-not-selected DLC as "user selected".
string songIdKey = SongButton.BuildSongSelectedIdPrefsKey(dlcKey);
if (PlayerPrefs.HasKey(songIdKey) && PlayerPrefs.GetInt(songIdKey, 0) > 0)
{
return true;
}
string songIndexKey = SongButton.BuildSongSelectedIndexPrefsKey(dlcKey);
return PlayerPrefs.HasKey(songIndexKey);
return PlayerPrefs.HasKey(songIdKey) && PlayerPrefs.GetInt(songIdKey, 0) > 0;
}
private string BuildDlcKey(dlcButton button)
@@ -244,22 +268,8 @@ public class loadDlcListPrefab : MonoBehaviour
private int GetDlcId(dlcButton button)
{
if (button == null)
{
return 0;
}
if (button.dlcDataSO != null && button.dlcDataSO.dlcID > 0)
{
return button.dlcDataSO.dlcID;
}
if (button.dlcID != null && int.TryParse(button.dlcID.text, out int parsedId))
{
return parsedId;
}
return 0;
// Delegate to the button's own resolver to keep id resolution in one place.
return button != null ? button.ResolveOwnDlcId() : 0;
}
private List<Column> BuildDisplayColumns()