更新结算界面

This commit is contained in:
2026-07-04 14:45:52 +08:00
parent 0b6dc2653f
commit 08dec79a6e
28 changed files with 3022 additions and 5289 deletions
+145 -51
View File
@@ -5,35 +5,69 @@ using UnityEngine.UI;
namespace GameFramework
{
/// <summary>
/// 排行榜场景 UI 控制器。
/// 如果当前得分能进入 Top-10,先显示输入名字面板;
/// 否则直接显示排行榜。
/// 修复了源项目 ScoringUIController 中 ShowScoringScreen() 被调用两次的 bug。
/// 结算界面 UI 控制器 —— 支持胜利/失败双界面
///
/// 胜利:显示"你做到了" + 魂灵数量 + 新记录标识(如有)
/// 失败:显示"你迷失了" + 去色底图
///
/// 通过 GameManager.GameState 判断胜负。
/// </summary>
public class ScoringUIController : MonoBehaviour
{
[Header("Panels")]
[SerializeField] GameObject leaderboardPanel;
[SerializeField] GameObject newHighScorePanel;
[Header("底图")]
[SerializeField] private Image bgImage;
[SerializeField] private Sprite bgSprite; // bg.png(胜利彩色/失败去色共用同一张)
[Header("Leaderboard")]
[SerializeField] Transform leaderboardContainer; // 包含10个条目的父物体
[SerializeField] Text finalScoreText; // 显示当前局最终得分
[Header("胜利面板")]
[SerializeField] private GameObject winPanel;
[SerializeField] private Image winTitleImage; // "你做到了" 图片
[SerializeField] private Sprite winTitleSprite; // nizuodaol.png
[SerializeField] private Text soulCountText; // 魂灵数量
[SerializeField] private Image soulCountBgImage; // 魂灵数量底图
[SerializeField] private Sprite soulCountBgSprite; // bgpoint.png
[SerializeField] private Image newRecordImage; // "新记录" 图片
[SerializeField] private Sprite newRecordSprite; // 新纪录.png
[SerializeField] private Image scoreLabelImage; // "拯救魂灵" 图片
[SerializeField] private Sprite scoreLabelSprite;
[Header("New High Score")]
[SerializeField] InputField nameInputField;
[SerializeField] Button submitButton;
[SerializeField] Button cancelButton;
[Header("失败面板")]
[SerializeField] private GameObject losePanel;
[SerializeField] private Image loseTitleImage; // "你迷失了" 图片
[SerializeField] private Sprite loseTitleSprite; // nizuodaol.png 副本
[Header("Navigation")]
[SerializeField] Button mainMenuButton;
[Header("排行榜")]
[SerializeField] private GameObject leaderboardPanel;
[SerializeField] private Transform leaderboardContainer;
[SerializeField] private Text finalScoreText;
[Header("新纪录输入")]
[SerializeField] private GameObject newHighScorePanel;
[SerializeField] private InputField nameInputField;
[SerializeField] private Button submitButton;
[SerializeField] private Button cancelButton;
[Header("导航")]
[SerializeField] private Button mainMenuButton;
[SerializeField] private Image mainMenuButtonImage; // 主界面.png
[SerializeField] private Sprite mainMenuBtnSprite;
[Header("装饰")]
[SerializeField] private Image lineImage;
[SerializeField] private Sprite lineSprite;
[SerializeField] private Image bgPointImage;
[SerializeField] private Sprite bgPointSprite;
[Header("Audio")]
[SerializeField] AudioData submitSFX;
[SerializeField] AudioData cancelSFX;
[SerializeField] private AudioData submitSFX;
[SerializeField] private AudioData cancelSFX;
private bool _isWin;
void Start()
{
// 判断胜负
_isWin = (GameManager.GameState == GameState.Victory);
// 绑定按钮
if (submitButton != null)
submitButton.onClick.AddListener(OnSubmitClick);
@@ -43,18 +77,74 @@ namespace GameFramework
mainMenuButton.onClick.AddListener(OnMainMenuClick);
// 初始隐藏所有面板
if (leaderboardPanel != null)
leaderboardPanel.SetActive(false);
if (newHighScorePanel != null)
newHighScorePanel.SetActive(false);
SetPanelActive(winPanel, false);
SetPanelActive(losePanel, false);
SetPanelActive(leaderboardPanel, false);
SetPanelActive(newHighScorePanel, false);
// 显示当前最终得分
if (finalScoreText != null && ScoreManager.Instance != null)
finalScoreText.text = ScoreManager.Instance.CurrentScore.ToString();
// 设置底图(共用同一张,失败时去色)
if (bgImage != null && bgSprite != null)
{
bgImage.sprite = bgSprite;
bgImage.color = _isWin ? Color.white : new Color(0.4f, 0.4f, 0.45f, 1f); // 失败去色
}
// 判断是否进入排行榜
// 只调用一次——修复源项目的双重调用 bug
if (ScoreManager.Instance != null && ScoreManager.Instance.HasNewHighScore)
// 设置装饰图片
if (lineImage != null && lineSprite != null)
lineImage.sprite = lineSprite;
if (bgPointImage != null && bgPointSprite != null)
bgPointImage.sprite = bgPointSprite;
// 设置返回主界面按钮图片
if (mainMenuButtonImage != null && mainMenuBtnSprite != null)
mainMenuButtonImage.sprite = mainMenuBtnSprite;
if (_isWin)
{
ShowWinScreen();
}
else
{
ShowLoseScreen();
}
}
/// <summary>
/// 显示胜利界面。
/// </summary>
void ShowWinScreen()
{
SetPanelActive(winPanel, true);
SetPanelActive(losePanel, false);
// 设置“你做到了”图片
if (winTitleImage != null && winTitleSprite != null)
winTitleImage.sprite = winTitleSprite;
// 设置魂灵数量底图
if (soulCountBgImage != null && soulCountBgSprite != null)
soulCountBgImage.sprite = soulCountBgSprite;
// 显示魂灵数量(复用 ScoreManager
int score = ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0;
if (soulCountText != null)
soulCountText.text = score.ToString();
// 设置“拯救魂灵”图片
if (scoreLabelImage != null && scoreLabelSprite != null)
scoreLabelImage.sprite = scoreLabelSprite;
// 判断是否新纪录
bool isNewRecord = ScoreManager.Instance != null && ScoreManager.Instance.HasNewHighScore;
if (newRecordImage != null)
{
newRecordImage.gameObject.SetActive(isNewRecord);
if (isNewRecord && newRecordSprite != null)
newRecordImage.sprite = newRecordSprite;
}
// 新纪录时显示输入面板,否则直接显示排行榜
if (isNewRecord)
{
ShowNewHighScorePanel();
}
@@ -64,17 +154,30 @@ namespace GameFramework
}
}
/// <summary>
/// 显示失败界面。
/// </summary>
void ShowLoseScreen()
{
SetPanelActive(winPanel, false);
SetPanelActive(losePanel, true);
// 设置"你迷失了"图片
if (loseTitleImage != null && loseTitleSprite != null)
loseTitleImage.sprite = loseTitleSprite;
// 失败也显示排行榜
ShowLeaderboard();
}
/// <summary>
/// 显示新纪录输入面板。
/// </summary>
void ShowNewHighScorePanel()
{
if (newHighScorePanel != null)
newHighScorePanel.SetActive(true);
if (leaderboardPanel != null)
leaderboardPanel.SetActive(false);
SetPanelActive(newHighScorePanel, true);
SetPanelActive(leaderboardPanel, false);
// 自动选中输入框
if (nameInputField != null)
{
nameInputField.text = "";
@@ -87,37 +190,28 @@ namespace GameFramework
/// </summary>
void ShowLeaderboard()
{
if (newHighScorePanel != null)
newHighScorePanel.SetActive(false);
if (leaderboardPanel != null)
leaderboardPanel.SetActive(true);
SetPanelActive(newHighScorePanel, false);
SetPanelActive(leaderboardPanel, true);
UpdateLeaderboardDisplay();
// 选中主菜单按钮(键盘导航用)
if (mainMenuButton != null)
mainMenuButton.Select();
}
/// <summary>
/// 更新排行榜显示。
/// 遍历 leaderboardContainer 下的子物体,设置排名/得分/名字。
/// 每个条目子物体需要有三个 Text 组件,分别在 Rank/Score/Name 子物体上。
/// </summary>
void UpdateLeaderboardDisplay()
{
if (ScoreManager.Instance == null) return;
if (leaderboardContainer == null) return;
if (ScoreManager.Instance == null || leaderboardContainer == null) return;
var data = ScoreManager.Instance.LoadPlayerScoreData();
int count = Mathf.Min(data.list.Count, leaderboardContainer.childCount);
for (int i = 0; i < leaderboardContainer.childCount; i++)
{
Transform entry = leaderboardContainer.GetChild(i);
bool hasData = i < data.list.Count;
// 查找条目下的三个 Text
Text rankText = FindTextByName(entry, "Rank");
Text scoreText = FindTextByName(entry, "Score");
Text nameText = FindTextByName(entry, "Name");
@@ -140,25 +234,26 @@ namespace GameFramework
}
}
/// <summary>
/// 在子物体中按名称查找 Text 组件。
/// </summary>
Text FindTextByName(Transform parent, string name)
{
Transform t = parent.Find(name);
if (t != null)
return t.GetComponent<Text>();
// 如果条目本身就是单个 Text(没有子结构),返回自身
return parent.GetComponent<Text>();
}
void SetPanelActive(GameObject panel, bool active)
{
if (panel != null)
panel.SetActive(active);
}
#region Button Handlers
void OnSubmitClick()
{
string playerName = "";
if (nameInputField != null)
playerName = nameInputField.text;
if (string.IsNullOrEmpty(playerName))
playerName = "Player";
@@ -173,7 +268,6 @@ namespace GameFramework
void OnCancelClick()
{
// 取消 = 用默认名保存后显示排行榜
if (ScoreManager.Instance != null)
ScoreManager.Instance.SavePlayerScore("Player");