207 lines
9.7 KiB
C#
207 lines
9.7 KiB
C#
![]() |
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<MessageManager>
|
|||
|
{
|
|||
|
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<RectTransform>();
|
|||
|
|
|||
|
// 如果temporaryAnimatorText有ContentSizeFitter,这里可能不需要设置sizeDelta,但为了LayoutGroup能识别,可以添加LayoutElement
|
|||
|
var layoutElement = hintTextInstance.GetComponent<LayoutElement>();
|
|||
|
if (layoutElement == null) layoutElement = hintTextInstance.gameObject.AddComponent<LayoutElement>();
|
|||
|
layoutElement.minHeight = 30; // 最小高度
|
|||
|
layoutElement.preferredWidth = _passiveHintContainer.sizeDelta.x; // 适应容器的宽度
|
|||
|
|
|||
|
// 设置字体样式
|
|||
|
var hintTmpText = hintTextInstance.GetComponent<TMP_Text>();
|
|||
|
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<RectTransform>();
|
|||
|
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<TMP_Text>();
|
|||
|
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<TemporaryAnimatorText>("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);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 场景加载完成回调,用于查找并设置Canvas和PassiveHint容器
|
|||
|
/// </summary>
|
|||
|
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|||
|
{
|
|||
|
// 尝试查找Canvas
|
|||
|
var mainCanvas = FindAnyObjectByType<Canvas>(); // 查找场景中的第一个Canvas
|
|||
|
if (mainCanvas != null)
|
|||
|
{
|
|||
|
_canvas = mainCanvas.GetComponent<RectTransform>();
|
|||
|
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.");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 创建并初始化PassiveHint的UI容器
|
|||
|
/// </summary>
|
|||
|
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<RectTransform>();
|
|||
|
_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<VerticalLayoutGroup>();
|
|||
|
layoutGroup.childAlignment = TextAnchor.UpperLeft; // 子元素靠左上排布
|
|||
|
layoutGroup.spacing = 10; // 消息之间的间距
|
|||
|
layoutGroup.padding = new RectOffset(10, 10, 10, 10); // 容器内边距
|
|||
|
|
|||
|
// 添加ContentSizeFitter,以便容器根据内容调整大小 (可选,根据实际需求)
|
|||
|
// fitter 会自动调整自身大小以适应子内容
|
|||
|
var fitter = containerGO.AddComponent<ContentSizeFitter>();
|
|||
|
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|||
|
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|