修复无法点击按钮问题

This commit is contained in:
JA
2026-07-06 00:56:32 +08:00
parent 390fb99602
commit 34cf55155c
5 changed files with 88 additions and 114 deletions
+1 -1
View File
@@ -371,7 +371,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
darknessMaterial: {fileID: 2100000, guid: 6dd18d2379aff3040813ab8005b1898a, type: 2} darknessMaterial: {fileID: 2100000, guid: 6dd18d2379aff3040813ab8005b1898a, type: 2}
debugShowAll: 1 debugShowAll: 0
minBrightness: 0 minBrightness: 0
darknessColor: {r: 0.01, g: 0.01, b: 0.02, a: 1} darknessColor: {r: 0.01, g: 0.01, b: 0.02, a: 1}
lightSoftness: 1 lightSoftness: 1
+10 -14
View File
@@ -885,8 +885,7 @@ Transform:
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children: []
- {fileID: 897692926}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &574406657 --- !u!114 &574406657
@@ -1355,20 +1354,20 @@ RectTransform:
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 897692925} m_GameObject: {fileID: 897692925}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 1022684515} - {fileID: 1022684515}
- {fileID: 1048541269} - {fileID: 1048541269}
m_Father: {fileID: 574406656} m_Father: {fileID: 1036666439}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 960, y: 540}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 1920, y: 1080}
m_Pivot: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &897692927 --- !u!114 &897692927
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -1918,10 +1917,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: dfb474cbd721479419d2ce88a2701448, type: 3} m_Script: {fileID: 11500000, guid: dfb474cbd721479419d2ce88a2701448, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
titleText: {fileID: 0}
titleImage: {fileID: 63499461}
startButton: {fileID: 1036827528} startButton: {fileID: 1036827528}
storyReplayButton: {fileID: 977847656} settingsButton: {fileID: 0}
creditsButton: {fileID: 995992462} creditsButton: {fileID: 995992462}
quitButton: {fileID: 0} quitButton: {fileID: 0}
settingsPanel: {fileID: 0} settingsPanel: {fileID: 0}
@@ -2006,6 +2003,7 @@ RectTransform:
- {fileID: 1535145891} - {fileID: 1535145891}
- {fileID: 63499463} - {fileID: 63499463}
- {fileID: 1440709690} - {fileID: 1440709690}
- {fileID: 897692926}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
@@ -2344,10 +2342,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: dfb474cbd721479419d2ce88a2701448, type: 3} m_Script: {fileID: 11500000, guid: dfb474cbd721479419d2ce88a2701448, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
titleText: {fileID: 0}
titleImage: {fileID: 0}
startButton: {fileID: 0} startButton: {fileID: 0}
storyReplayButton: {fileID: 0} settingsButton: {fileID: 0}
creditsButton: {fileID: 0} creditsButton: {fileID: 0}
quitButton: {fileID: 0} quitButton: {fileID: 0}
settingsPanel: {fileID: 2013394273} settingsPanel: {fileID: 2013394273}
+55 -41
View File
@@ -4,22 +4,19 @@ using UnityEngine.UI;
namespace GameFramework namespace GameFramework
{ {
/// <summary> /// <summary>
/// 主菜单 UI 控制器(游戏封面) /// 主菜单 UI 控制器。
/// 包含游戏标题 + 开始游戏/剧情回放/制作人员按钮 /// 支持开始游戏、设置、制作人员、退出游戏
/// 修复:场景重载后自动重新查找 UI 引用,避免 DontDestroyOnLoad 导致的空引用问题。
/// </summary> /// </summary>
public class MainMenuUIController : MonoBehaviour public class MainMenuUIController : MonoBehaviour
{ {
[Header("标题")]
[SerializeField] Text titleText;
[SerializeField] Image titleImage;
[Header("Buttons")] [Header("Buttons")]
[SerializeField] Button startButton; [SerializeField] Button startButton;
[SerializeField] Button storyReplayButton; [SerializeField] Button settingsButton;
[SerializeField] Button creditsButton; [SerializeField] Button creditsButton;
[SerializeField] Button quitButton; [SerializeField] Button quitButton;
[Header("Settings Panel (placeholder)")] [Header("Settings Panel")]
[SerializeField] GameObject settingsPanel; [SerializeField] GameObject settingsPanel;
[SerializeField] Button settingsBackButton; [SerializeField] Button settingsBackButton;
@@ -29,23 +26,38 @@ namespace GameFramework
void Start() void Start()
{ {
Debug.Log("[MainMenu] creditsButton=" + (creditsButton != null ? creditsButton.name : "NULL") + " creditsPanel=" + (creditsPanel != null ? creditsPanel.name : "NULL")); // 自动查找(解决场景重载后引用失效问题)
if (startButton == null)
startButton = FindButton("StartButton");
if (settingsButton == null)
settingsButton = FindButton("SettingsButton");
if (creditsButton == null)
creditsButton = FindButton("CreditsButton");
if (quitButton == null)
quitButton = FindButton("QuitButton");
if (settingsPanel == null)
settingsPanel = GameObject.Find("SettingsPanel");
if (settingsBackButton == null && settingsPanel != null)
settingsBackButton = settingsPanel.GetComponentInChildren<Button>();
if (creditsPanel == null)
creditsPanel = GameObject.Find("CreditsPanel");
if (creditsCloseButton == null && creditsPanel != null)
creditsCloseButton = creditsPanel.GetComponentInChildren<Button>();
// 绑定按钮事件 // 绑定按钮事件
if (startButton != null) if (startButton != null)
startButton.onClick.AddListener(OnStartClick); startButton.onClick.AddListener(OnStartClick);
if (settingsButton != null)
if (storyReplayButton != null) settingsButton.onClick.AddListener(OnSettingsClick);
storyReplayButton.onClick.AddListener(OnStoryReplayClick);
if (creditsButton != null) if (creditsButton != null)
creditsButton.onClick.AddListener(OnCreditsClick); creditsButton.onClick.AddListener(OnCreditsClick);
if (quitButton != null) if (quitButton != null)
quitButton.onClick.AddListener(OnQuitClick); quitButton.onClick.AddListener(OnQuitClick);
if (settingsBackButton != null) if (settingsBackButton != null)
settingsBackButton.onClick.AddListener(OnSettingsBackClick); settingsBackButton.onClick.AddListener(OnSettingsBackClick);
if (creditsCloseButton != null) if (creditsCloseButton != null)
creditsCloseButton.onClick.AddListener(OnCreditsCloseClick); creditsCloseButton.onClick.AddListener(OnCreditsCloseClick);
@@ -56,29 +68,22 @@ namespace GameFramework
creditsPanel.SetActive(false); creditsPanel.SetActive(false);
} }
Button FindButton(string name)
{
var btn = GameObject.Find(name);
return btn != null ? btn.GetComponent<Button>() : null;
}
void OnStartClick() void OnStartClick()
{ {
if (SceneLoader.Instance != null) if (SceneLoader.Instance != null)
SceneLoader.Instance.LoadGameplayScene(); SceneLoader.Instance.LoadGameplayScene();
} }
void OnStoryReplayClick() void OnSettingsClick()
{ {
// TODO: 实现剧情回放功能 if (settingsPanel != null)
Debug.Log("[MainMenu] 剧情回放 - 待实现"); settingsPanel.SetActive(true);
}
void OnCreditsClick()
{
Debug.Log("[MainMenu] OnCreditsClick called! creditsPanel=" + (creditsPanel != null ? creditsPanel.name : "NULL"));
if (creditsPanel != null)
creditsPanel.SetActive(true);
}
void OnCreditsCloseClick()
{
if (creditsPanel != null)
creditsPanel.SetActive(false);
} }
void OnSettingsBackClick() void OnSettingsBackClick()
@@ -87,6 +92,25 @@ namespace GameFramework
settingsPanel.SetActive(false); settingsPanel.SetActive(false);
} }
void OnCreditsClick()
{
if (creditsPanel != null)
{
creditsPanel.SetActive(true);
Debug.Log($"[MainMenu] Showing credits panel: {creditsPanel.name}");
}
else
{
Debug.LogWarning("[MainMenu] creditsPanel not found! Make sure a GameObject named 'CreditsPanel' exists in the scene.");
}
}
void OnCreditsCloseClick()
{
if (creditsPanel != null)
creditsPanel.SetActive(false);
}
void OnQuitClick() void OnQuitClick()
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
@@ -95,15 +119,5 @@ namespace GameFramework
Application.Quit(); Application.Quit();
#endif #endif
} }
void OnDestroy()
{
if (startButton != null) startButton.onClick.RemoveAllListeners();
if (storyReplayButton != null) storyReplayButton.onClick.RemoveAllListeners();
if (creditsButton != null) creditsButton.onClick.RemoveAllListeners();
if (quitButton != null) quitButton.onClick.RemoveAllListeners();
if (settingsBackButton != null) settingsBackButton.onClick.RemoveAllListeners();
if (creditsCloseButton != null) creditsCloseButton.onClick.RemoveAllListeners();
}
} }
} }
+16 -21
View File
@@ -1,6 +1,5 @@
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
namespace GameFramework namespace GameFramework
{ {
@@ -9,33 +8,29 @@ namespace GameFramework
/// 让 EventSystem 通过 DontDestroyOnLoad 跨场景存活。 /// 让 EventSystem 通过 DontDestroyOnLoad 跨场景存活。
/// 这样 Gameplay、Scoring 等场景的按钮都能正常响应点击。 /// 这样 Gameplay、Scoring 等场景的按钮都能正常响应点击。
/// ///
/// 场景切换时如果新场景自带 EventSystem,会自动销毁重复的那个 /// 修复:当场景重复加载时(如从 Scoring 回到 MainMenu
/// 始终保证场景中只有一个 EventSystem。 /// 销毁多余的 EventSystem,保证全局只有一个
/// </summary> /// </summary>
public class PersistentEventSystem : MonoBehaviour public class PersistentEventSystem : MonoBehaviour
{ {
void Awake() void Awake()
{ {
// 让 EventSystem 跨场景存活 var allSystems = FindObjectsOfType<EventSystem>();
DontDestroyOnLoad(gameObject);
// 监听场景加载,清理重复的 EventSystem if (allSystems.Length == 0)
SceneManager.sceneLoaded += OnSceneLoaded;
}
void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// 新场景加载后,找到所有 EventSystem,保留自己所在的,销毁其余的
var allES = FindObjectsOfType<EventSystem>();
foreach (var es in allES)
{ {
if (es.gameObject != gameObject) // 场景里没有 EventSystem —— 创建一个
Destroy(es.gameObject); var go = new GameObject("EventSystem");
go.AddComponent<EventSystem>();
go.AddComponent<StandaloneInputModule>();
DontDestroyOnLoad(go);
}
else
{
// 保留第一个 EventSystem,销毁重复的
DontDestroyOnLoad(allSystems[0].gameObject);
for (int i = 1; i < allSystems.Length; i++)
Destroy(allSystems[i].gameObject);
} }
} }
} }
+6 -37
View File
@@ -9,9 +9,7 @@ namespace GameFramework
/// 场景异步加载器(持久化单例)。带黑色淡入淡出过渡。 /// 场景异步加载器(持久化单例)。带黑色淡入淡出过渡。
/// 场景名可在 Inspector 配置,默认 MainMenu / Gameplay / Scoring。 /// 场景名可在 Inspector 配置,默认 MainMenu / Gameplay / Scoring。
/// ///
/// 搭建:把 SceneLoader 挂到一个空物体上(放第一个场景 MainMenu 里), /// 修复:协程结束后将 isLoading 重置为 false,允许后续加载。
/// 它会 DontDestroyOnLoad。transitionImage 是它子物体 Canvas 上的 Image(全屏黑),
/// Canvas 设为 Screen Space - Overlay、sortingOrder 设很高(如 9999)。
/// </summary> /// </summary>
public class SceneLoader : PersistentSingleton<SceneLoader> public class SceneLoader : PersistentSingleton<SceneLoader>
{ {
@@ -19,7 +17,7 @@ namespace GameFramework
[SerializeField] private Image transitionImage; [SerializeField] private Image transitionImage;
[SerializeField] private float fadeTime = 1.5f; [SerializeField] private float fadeTime = 1.5f;
[Header("场景名(按你工程的实际名称填)")] [Header("场景名(按你工程的实际名称填)")]
[SerializeField] private string mainMenuScene = "MainMenu"; [SerializeField] private string mainMenuScene = "MainMenu";
[SerializeField] private string gameplayScene = "Gameplay"; [SerializeField] private string gameplayScene = "Gameplay";
[SerializeField] private string scoringScene = "Scoring"; [SerializeField] private string scoringScene = "Scoring";
@@ -27,34 +25,14 @@ namespace GameFramework
private Color color; private Color color;
private bool isLoading = false; private bool isLoading = false;
public void LoadGameplayScene() public void LoadGameplayScene() => Load(gameplayScene);
{
// 重置 GameManager 状态
if (GameManager.Instance != null)
{
GameManager.GameState = GameState.Playing;
GameManager.onGameOver = null;
GameManager.onGameWin = null;
}
// 重置 ScoreManager
if (ScoreManager.Instance != null)
ScoreManager.Instance.ResetScore();
// 清理静态事件残留订阅
IndianOceanAssets.Engine2_5D.HealthSystem.onPlayerDamaged = null;
Load(gameplayScene);
}
public void LoadMainMenuScene() => Load(mainMenuScene); public void LoadMainMenuScene() => Load(mainMenuScene);
public void LoadScoringScene() => Load(scoringScene); public void LoadScoringScene() => Load(scoringScene);
public void Load(string sceneName) public void Load(string sceneName)
{ {
if (isLoading) if (isLoading) return;
{
Debug.LogWarning($"[SceneLoader] 上次加载未完成,强制重置并加载: {sceneName}");
StopAllCoroutines();
isLoading = false;
}
isLoading = true; isLoading = true;
StopAllCoroutines();
StartCoroutine(LoadingCoroutine(sceneName)); StartCoroutine(LoadingCoroutine(sceneName));
} }
@@ -67,16 +45,7 @@ namespace GameFramework
"拖到 SceneLoader 的 transitionImage 字段。"); "拖到 SceneLoader 的 transitionImage 字段。");
} }
Debug.Log($"[SceneLoader] 开始加载场景: {sceneName}");
var loadingOperation = SceneManager.LoadSceneAsync(sceneName); var loadingOperation = SceneManager.LoadSceneAsync(sceneName);
if (loadingOperation == null)
{
Debug.LogError($"[SceneLoader] 场景 '{sceneName}' 加载失败!请检查 Build Settings 中是否包含该场景。");
isLoading = false;
yield break;
}
loadingOperation.allowSceneActivation = false; loadingOperation.allowSceneActivation = false;
if (transitionImage != null) if (transitionImage != null)
@@ -123,7 +92,7 @@ namespace GameFramework
transitionImage.gameObject.SetActive(false); transitionImage.gameObject.SetActive(false);
} }
Debug.Log($"[SceneLoader] 场景加载完成: {sceneName}"); // 加载完成,重置标志,允许下一次加载
isLoading = false; isLoading = false;
} }
} }