修复
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
namespace GameFramework
|
namespace GameFramework
|
||||||
{
|
{
|
||||||
@@ -7,6 +8,7 @@ namespace GameFramework
|
|||||||
/// 主菜单 UI 控制器。
|
/// 主菜单 UI 控制器。
|
||||||
/// 支持开始游戏、设置、制作人员、退出游戏。
|
/// 支持开始游戏、设置、制作人员、退出游戏。
|
||||||
/// 修复:场景重载后自动重新查找 UI 引用,避免 DontDestroyOnLoad 导致的空引用问题。
|
/// 修复:场景重载后自动重新查找 UI 引用,避免 DontDestroyOnLoad 导致的空引用问题。
|
||||||
|
/// 修复:返回主菜单后按钮全部失效(EventSystem/InputModule 状态异常)时主动兜底。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MainMenuUIController : MonoBehaviour
|
public class MainMenuUIController : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -34,6 +36,8 @@ namespace GameFramework
|
|||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
EnsureEventSystem();
|
||||||
|
|
||||||
// 自动查找(解决场景重载后引用失效问题)
|
// 自动查找(解决场景重载后引用失效问题)
|
||||||
if (startButton == null)
|
if (startButton == null)
|
||||||
startButton = FindButton("StartButton");
|
startButton = FindButton("StartButton");
|
||||||
@@ -74,18 +78,47 @@ namespace GameFramework
|
|||||||
|
|
||||||
// 绑定按钮事件
|
// 绑定按钮事件
|
||||||
if (startButton != null)
|
if (startButton != null)
|
||||||
|
{
|
||||||
startButton.onClick.AddListener(OnStartClick);
|
startButton.onClick.AddListener(OnStartClick);
|
||||||
|
Debug.Log($"[MainMenu] 已绑定 startButton = {startButton.name}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[MainMenu] startButton 未找到!开始游戏按钮将不可点。");
|
||||||
|
}
|
||||||
|
|
||||||
if (settingsButton != null)
|
if (settingsButton != null)
|
||||||
|
{
|
||||||
settingsButton.onClick.AddListener(OnSettingsClick);
|
settingsButton.onClick.AddListener(OnSettingsClick);
|
||||||
|
Debug.Log($"[MainMenu] 已绑定 settingsButton = {settingsButton.name}");
|
||||||
|
}
|
||||||
|
|
||||||
if (creditsButton != null)
|
if (creditsButton != null)
|
||||||
|
{
|
||||||
creditsButton.onClick.AddListener(OnCreditsClick);
|
creditsButton.onClick.AddListener(OnCreditsClick);
|
||||||
|
Debug.Log($"[MainMenu] 已绑定 creditsButton = {creditsButton.name}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[MainMenu] creditsButton 未找到!制作人员按钮将不可点。");
|
||||||
|
}
|
||||||
|
|
||||||
if (quitButton != null)
|
if (quitButton != null)
|
||||||
|
{
|
||||||
quitButton.onClick.AddListener(OnQuitClick);
|
quitButton.onClick.AddListener(OnQuitClick);
|
||||||
|
Debug.Log($"[MainMenu] 已绑定 quitButton = {quitButton.name}");
|
||||||
|
}
|
||||||
|
|
||||||
if (storyReplayButton != null)
|
if (storyReplayButton != null)
|
||||||
{
|
{
|
||||||
// 避免 Inspector 中已绑定的事件导致重复触发
|
// 避免 Inspector 中已绑定的事件导致重复触发
|
||||||
storyReplayButton.onClick.RemoveAllListeners();
|
storyReplayButton.onClick.RemoveAllListeners();
|
||||||
storyReplayButton.onClick.AddListener(OnStoryReplayClick);
|
storyReplayButton.onClick.AddListener(OnStoryReplayClick);
|
||||||
|
Debug.Log($"[MainMenu] 已绑定 storyReplayButton = {storyReplayButton.name}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[MainMenu] storyReplayButton 未找到!剧情播放按钮将不可点。");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsBackButton != null)
|
if (settingsBackButton != null)
|
||||||
@@ -111,8 +144,56 @@ namespace GameFramework
|
|||||||
return btn != null ? btn.GetComponent<Button>() : null;
|
return btn != null ? btn.GetComponent<Button>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 兜底:确保场景里有一个可用的 EventSystem + StandaloneInputModule。
|
||||||
|
/// 当 activeInputHandler 配置错误(比如选了未安装的 Input System 包)或
|
||||||
|
/// EventSystem 上挂了丢失脚本的组件时,重载后所有按钮会同时失效。
|
||||||
|
/// 这里主动清理缺失脚本并补齐 InputModule。
|
||||||
|
/// </summary>
|
||||||
|
private void EnsureEventSystem()
|
||||||
|
{
|
||||||
|
var es = EventSystem.current;
|
||||||
|
if (es == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[MainMenu] EventSystem.current 为空!主动创建一个兜底。");
|
||||||
|
var go = new GameObject("EventSystem");
|
||||||
|
es = go.AddComponent<EventSystem>();
|
||||||
|
go.AddComponent<StandaloneInputModule>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除 EventSystem 上所有"脚本丢失"的组件(Missing Script),
|
||||||
|
// 避免它们被 Unity 当作 InputSystemUIInputModule 处理而导致按钮不响应
|
||||||
|
var components = es.GetComponents<Component>();
|
||||||
|
foreach (var c in components)
|
||||||
|
{
|
||||||
|
if (c == null)
|
||||||
|
{
|
||||||
|
// c == null 说明是 missing script,需要通过序列化接口删除
|
||||||
|
// 这里只能用 DestroyImmediate(编辑器/启动阶段调用安全)
|
||||||
|
// 由于无法从 null 引用直接 Destroy,采用遍历 SerializedObject 的方式太重,
|
||||||
|
// 改为:如果发现任何 missing,直接重建一个干净的 EventSystem
|
||||||
|
Debug.LogWarning("[MainMenu] 发现 EventSystem 上有丢失脚本的组件,重建 EventSystem 以保证按钮可点。");
|
||||||
|
var old = es.gameObject;
|
||||||
|
var go = new GameObject("EventSystem_Fallback");
|
||||||
|
var newEs = go.AddComponent<EventSystem>();
|
||||||
|
go.AddComponent<StandaloneInputModule>();
|
||||||
|
Destroy(old);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保有 StandaloneInputModule(如果误用 InputSystemUIInputModule 但包未装,也会点不动)
|
||||||
|
if (es.GetComponent<StandaloneInputModule>() == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[MainMenu] EventSystem 缺少 StandaloneInputModule,已自动添加。");
|
||||||
|
es.gameObject.AddComponent<StandaloneInputModule>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OnStartClick()
|
void OnStartClick()
|
||||||
{
|
{
|
||||||
|
Debug.Log("[MainMenu] OnStartClick 触发");
|
||||||
// 显示新手引导页,而非直接进入游戏
|
// 显示新手引导页,而非直接进入游戏
|
||||||
if (guidePanel != null)
|
if (guidePanel != null)
|
||||||
{
|
{
|
||||||
@@ -149,6 +230,7 @@ namespace GameFramework
|
|||||||
|
|
||||||
void OnCreditsClick()
|
void OnCreditsClick()
|
||||||
{
|
{
|
||||||
|
Debug.Log($"[MainMenu] OnCreditsClick 触发, creditsPanel={(creditsPanel != null ? creditsPanel.name : "null")}");
|
||||||
if (creditsPanel != null)
|
if (creditsPanel != null)
|
||||||
{
|
{
|
||||||
creditsPanel.SetActive(true);
|
creditsPanel.SetActive(true);
|
||||||
@@ -177,6 +259,7 @@ namespace GameFramework
|
|||||||
|
|
||||||
void OnStoryReplayClick()
|
void OnStoryReplayClick()
|
||||||
{
|
{
|
||||||
|
Debug.Log($"[MainMenu] OnStoryReplayClick 触发, storyPVPlayer={(storyPVPlayer != null ? storyPVPlayer.gameObject.name : "null")}");
|
||||||
if (storyPVPlayer != null)
|
if (storyPVPlayer != null)
|
||||||
{
|
{
|
||||||
Debug.Log($"[MainMenu] 播放 PV, StoryPVPlayer on: {storyPVPlayer.gameObject.name}");
|
Debug.Log($"[MainMenu] 播放 PV, StoryPVPlayer on: {storyPVPlayer.gameObject.name}");
|
||||||
|
|||||||
@@ -66,6 +66,14 @@ namespace IndianOceanAssets.Engine2_5D
|
|||||||
[Tooltip("红圈扩散速度(世界单位/秒),独立于波纹扩散速度")]
|
[Tooltip("红圈扩散速度(世界单位/秒),独立于波纹扩散速度")]
|
||||||
[SerializeField] private float ringExpandSpeed = 15f;
|
[SerializeField] private float ringExpandSpeed = 15f;
|
||||||
|
|
||||||
|
[Header("Shader 引用")]
|
||||||
|
[Tooltip("直接拖入 Assets/Light/shaders/EchoRing.shader。\n"
|
||||||
|
+ "用序列化字段引用而不是 Shader.Find,确保打包时构建管线能静态识别,"
|
||||||
|
+ "不会被 shader stripping 剔除(否则运行时会 fallback 成粉色错误着色器)。\n"
|
||||||
|
+ "留空时仍会尝试 Shader.Find 兜底,但需要把该 shader 加入 "
|
||||||
|
+ "GraphicsSettings 的 Always Included Shaders 列表。")]
|
||||||
|
[SerializeField] private Shader ringShader;
|
||||||
|
|
||||||
[Header("冷却")]
|
[Header("冷却")]
|
||||||
[Tooltip("回声冷却时间(秒)")]
|
[Tooltip("回声冷却时间(秒)")]
|
||||||
[SerializeField] private float cooldown = 3f;
|
[SerializeField] private float cooldown = 3f;
|
||||||
@@ -128,7 +136,10 @@ namespace IndianOceanAssets.Engine2_5D
|
|||||||
// 不挂载到玩家下——回声中心固定,不跟随玩家移动
|
// 不挂载到玩家下——回声中心固定,不跟随玩家移动
|
||||||
|
|
||||||
// 创建材质(运行时)
|
// 创建材质(运行时)
|
||||||
var shader = Shader.Find("IndianOcean/EchoRing");
|
// 优先使用序列化字段引用的 shader(构建管线可静态识别,不会被剔除);
|
||||||
|
// 字段为空时再尝试 Shader.Find 兜底(必须同时把 shader 加入 GraphicsSettings
|
||||||
|
// 的 Always Included Shaders,否则打包后 Find 会返回 null → 粉色错误着色器)。
|
||||||
|
var shader = ringShader != null ? ringShader : Shader.Find("IndianOcean/EchoRing");
|
||||||
if (shader != null)
|
if (shader != null)
|
||||||
{
|
{
|
||||||
_ringMaterial = new Material(shader);
|
_ringMaterial = new Material(shader);
|
||||||
@@ -142,7 +153,12 @@ namespace IndianOceanAssets.Engine2_5D
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError("[EchoSystem] 找不到 IndianOcean/EchoRing shader!");
|
Debug.LogError(
|
||||||
|
"[EchoSystem] 找不到 IndianOcean/EchoRing shader!红圈将不会渲染。\n"
|
||||||
|
+ "修复方法(二选一):\n"
|
||||||
|
+ " 1) 把 Assets/Light/shaders/EchoRing.shader 拖到本组件的 Ring Shader 字段;\n"
|
||||||
|
+ " 2) Edit → Project Settings → Graphics → Always Included Shaders "
|
||||||
|
+ "里添加该 shader,然后重新打包。");
|
||||||
}
|
}
|
||||||
|
|
||||||
_ringVisual.SetActive(false);
|
_ringVisual.SetActive(false);
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: CXkZ4S2lVHyohUFSvtGvZhelAh5YZD1t21cOxId/XueCt0dvcSw2LVI=
|
guid: DChM5in+AnMAik4AhwKqEXsekneiyAEI0sMwHSFq5ysZ8jVnomxLhFQ=
|
||||||
TextureImporter:
|
TextureImporter:
|
||||||
internalIDToNameTable: []
|
internalIDToNameTable: []
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -112,6 +112,48 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: Android
|
||||||
|
maxTextureSize: 2048
|
||||||
|
maxPlaceholderSize: 32
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: HMIAndroid
|
||||||
|
maxTextureSize: 2048
|
||||||
|
maxPlaceholderSize: 32
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: OpenHarmony
|
||||||
|
maxTextureSize: 2048
|
||||||
|
maxPlaceholderSize: 32
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
Reference in New Issue
Block a user