using System; using Base; using Data; using Prefab; using UnityEngine; using UnityEngine.SceneManagement; // 新增引用 using UnityEngine.UI; // 用于 LayoutGroup 和 RectTransform using TMPro; // 用于 TMP_Text namespace Managers { public class MessageManager:Utils.MonoSingleton { private RectTransform _canvas; private TemporaryAnimatorText _temporaryAnimatorTextPrefab; // 重命名,表示是预制体 private RectTransform _passiveHintContainer; // 用于PassiveHint的容器 // SceneManager.sceneLoaded 注册/取消注册 private void OnEnable() { SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDisable() { SceneManager.sceneLoaded -= OnSceneLoaded; } public void DisplayMessage(string message, Data.PromptDisplayCategory type,Color? color=null) { if (!_canvas) { Debug.LogWarning($"MessageManager: Canvas is not available. Message '{message}' ignored."); return; } switch (type) { case PromptDisplayCategory.FocusedEntityOverheadText: if (Program.Instance.FocusedEntity == null) return; // GenerateTemporaryAnimation的第三个参数是显示时间 TemporaryAnimationManager.Instance.GenerateTemporaryAnimation(message, Program.Instance.FocusedEntity.Position, 5); // 5秒显示时间 break; case PromptDisplayCategory.PassiveHint: if (_passiveHintContainer == null) { Debug.LogWarning("Cannot display PassiveHint: PassiveHintContainer is not available. Please ensure Canvas is present."); return; } // 实例化消息文本作为PassiveHintContainer的子对象 var hintTextInstance = Instantiate(_temporaryAnimatorTextPrefab, _passiveHintContainer.transform); // 确保它在Layout Group中正确显示 var hintTextRect = hintTextInstance.GetComponent(); // 如果temporaryAnimatorText有ContentSizeFitter,这里可能不需要设置sizeDelta,但为了LayoutGroup能识别,可以添加LayoutElement var layoutElement = hintTextInstance.GetComponent(); if (layoutElement == null) layoutElement = hintTextInstance.gameObject.AddComponent(); layoutElement.minHeight = 30; // 最小高度 layoutElement.preferredWidth = _passiveHintContainer.sizeDelta.x; // 适应容器的宽度 // 设置字体样式 var hintTmpText = hintTextInstance.GetComponent(); if (hintTmpText != null) { hintTmpText.fontSize = 24; // 较小的字体 hintTmpText.alignment = TextAlignmentOptions.TopLeft; // 左上对齐 hintTmpText.enableAutoSizing = false; // 关闭自动调整字体,保持统一 hintTmpText.SetText(message); // 先设置文本,确保布局计算正确 if(color.HasValue) hintTmpText.color = color.Value; } hintTextInstance.Init(message); // Init 方法会处理动画和生命周期 // TemporaryAnimatorText 应该在 Init 内部设置好 lifeTime 并自动销毁。 break; case PromptDisplayCategory.ScreenCenterLargeText: var textInstance = GameObject.Instantiate(_temporaryAnimatorTextPrefab, _canvas.transform); // 使用预制体变量 // 设置RectTransform实现全屏 var textRect = textInstance.GetComponent(); textRect.anchorMin = Vector2.zero; // (0,0) textRect.anchorMax = Vector2.one; // (1,1) textRect.offsetMin = Vector2.zero; // 左下角偏移为(0,0) textRect.offsetMax = Vector2.zero; // 右上角偏移为(0,0) // 获取TMP_Text并设置字体等 var tmpText = textInstance.GetComponent(); if (tmpText != null) { tmpText.fontSize = 80; // 设置一个较大的字体大小 tmpText.alignment = TextAlignmentOptions.Center; // 居中对齐 tmpText.enableAutoSizing = true; // 允许自动调整字体大小以适应文本框 (可选) tmpText.SetText(message); // 先设置文本,确保布局计算正确 if(color.HasValue) tmpText.color = color.Value; } textInstance.Init(message); // Init 方法会处理动画和生命周期 // textInstance.lifeTime 可以在 Init 方法内部设置,如果 Init 没有提供参数,这里就无法直接设置。 // 假设 Init 已经处理好生命周期。 break; case PromptDisplayCategory.Default: break; case PromptDisplayCategory.FocusedEntityChatBubble: break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } protected override void OnStart() { // 在单例第一次初始化时加载预制体 _temporaryAnimatorTextPrefab = Resources.Load("Prefab/TemporaryAnimation/UITemporaryAnimationText"); if (_temporaryAnimatorTextPrefab == null) { Debug.LogError("Failed to load TemporaryAnimatorText prefab. Check the path: Prefab/TemporaryAnimation/UITemporaryAnimationText"); } // 首次启动时也尝试查找 Canvas 和创建 PassiveHint 容器 // 这可以处理管理器在 Canvas 和其他 UI 元素之前启动的情况 if (SceneManager.GetActiveScene().isLoaded) { OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single); } } /// /// 场景加载完成回调,用于查找并设置Canvas和PassiveHint容器 /// private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 尝试查找Canvas var mainCanvas = FindAnyObjectByType(); // 查找场景中的第一个Canvas if (mainCanvas != null) { _canvas = mainCanvas.GetComponent(); InitializePassiveHintContainer(); } else { _canvas = null; // 如果没有Canvas,确保容器也被清除,避免引用无效对象 if (_passiveHintContainer != null) { Destroy(_passiveHintContainer.gameObject); _passiveHintContainer = null; } Debug.LogWarning($"MessageManager: No Canvas found in scene '{scene.name}'. UI messages might not display."); } } /// /// 创建并初始化PassiveHint的UI容器 /// private void InitializePassiveHintContainer() { if (_canvas == null) { Debug.LogError("Cannot initialize PassiveHint container: Canvas is null."); return; } // 如果容器已经存在,先销毁旧的,确保每次场景加载都是新的容器 if (_passiveHintContainer != null) { Destroy(_passiveHintContainer.gameObject); _passiveHintContainer = null; } // 创建一个新的GameObject作为容器 var containerGO = new GameObject("PassiveHintContainer"); _passiveHintContainer = containerGO.AddComponent(); _passiveHintContainer.SetParent(_canvas, false); // false表示不保留世界坐标 // 设置容器的位置和大小:左侧中间 _passiveHintContainer.anchorMin = new Vector2(0, 0.5f); _passiveHintContainer.anchorMax = new Vector2(0, 0.5f); _passiveHintContainer.pivot = new Vector2(0, 0.5f); // 锚点和枢轴都在左中 _passiveHintContainer.anchoredPosition = new Vector2(100, 0); // 从左边距100(示例值),Y轴中心 _passiveHintContainer.sizeDelta = new Vector2(400, 600); // 示例宽度和高度 // 添加VerticalLayoutGroup var layoutGroup = containerGO.AddComponent(); layoutGroup.childAlignment = TextAnchor.UpperLeft; // 子元素靠左上排布 layoutGroup.spacing = 10; // 消息之间的间距 layoutGroup.padding = new RectOffset(10, 10, 10, 10); // 容器内边距 // 添加ContentSizeFitter,以便容器根据内容调整大小 (可选,根据实际需求) // fitter 会自动调整自身大小以适应子内容 var fitter = containerGO.AddComponent(); fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; } } }