using System; using Prefab; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using UnityEngine.UI; using Utils; namespace Managers { public class TemporaryAnimationManager : MonoSingleton { // 将包装图层改为由代码动态创建和管理 private GameObject _temporaryAnimationLevel; private GameObject _temporaryAnimationUILevel; [SerializeField] private TemporaryAnimatorImageUI temporaryAnimatorImageUIPrefab; [SerializeField] private TemporaryAnimatorSprite temporaryAnimatorSpritePrefab; [SerializeField] private TemporaryAnimatorText temporaryAnimatorTextPrefab; [SerializeField] private TemporaryAnimatorText temporaryAnimatorUITextPrefab; private Func defaultXoffset = f => Mathf.Sin(f * 3); private Func defaultYoffset = f => f; protected override void OnStart() { SceneManager.sceneLoaded += OnSceneLoaded; CreateAnimationLayersForCurrentScene(SceneManager.GetActiveScene(), LoadSceneMode.Single); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; // 在Manager销毁时,也销毁创建的图层,防止残留 if (_temporaryAnimationLevel != null) { Destroy(_temporaryAnimationLevel); } if (_temporaryAnimationUILevel != null) { Destroy(_temporaryAnimationUILevel); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 在新场景加载时,重新创建动画图层 CreateAnimationLayersForCurrentScene(scene, mode); } /// /// 为当前活动场景创建或重新创建临时动画的父级图层。 /// /// 当前加载的场景。 /// 场景加载模式。 private void CreateAnimationLayersForCurrentScene(Scene scene, LoadSceneMode mode) { // 销毁旧的图层(如果存在),确保每个场景都有独立的图层 // 注意:如果TemporaryAnimationManager是DontDestroyOnLoad, // 那么旧的图层可能还在,需要显式销毁。 if (_temporaryAnimationLevel != null) { Destroy(_temporaryAnimationLevel); } if (_temporaryAnimationUILevel != null) { Destroy(_temporaryAnimationUILevel); } // 创建非UI动画的包装图层 _temporaryAnimationLevel = new GameObject("TemporaryAnimations"); // 将其移动到当前加载的场景的根目录,使其成为场景的一部分 SceneManager.MoveGameObjectToScene(_temporaryAnimationLevel, scene); // 1. 获取或创建 Canvas var mainCanvas = GetOrCreateMainCanvas(); // 2. 创建 _temporaryAnimationUILevel GameObject _temporaryAnimationUILevel = new GameObject("TemporaryUIAnimations"); // 3. 将其设置为 Canvas 的子对象 // SetParent(parentTransform, worldPositionStay: false) 会将子对象的局部位置重置为 (0,0,0) // 这对于新的UI元素通常是期望的行为 _temporaryAnimationUILevel.transform.SetParent(mainCanvas.transform, false); // 4. 重置新创建的UI容器的局部变换 // 确保它相对于父级 Canvas 处于一个干净的初始状态 _temporaryAnimationUILevel.transform.localPosition = Vector3.zero; _temporaryAnimationUILevel.transform.localScale = Vector3.one; _temporaryAnimationUILevel.transform.localRotation = Quaternion.identity; } public void GenerateTemporaryAnimation(string str, Vector3 position, float lifeTime = 3, float fps = 3, Func xShift = null, Func yShift = null) { if (!_temporaryAnimationLevel) { Debug.LogError("TemporaryAnimationLevel is not initialized. Cannot generate non-UI animation."); return; } xShift ??= defaultXoffset; yShift ??= defaultYoffset; var textObj = Instantiate(temporaryAnimatorTextPrefab, _temporaryAnimationLevel.transform); textObj.transform.position = new Vector3(position.x,position.y); textObj.Init(str, fps); textObj.SetAnimationFunctions(xShift, yShift); textObj.lifeTime = lifeTime; } /// /// 生成一个非UI精灵临时动画。 /// /// 动画的精灵帧数组。 /// 动画在世界坐标系中的初始位置。 /// 动画帧率。 /// X轴位移函数。 /// Y轴位移函数。 public void GenerateTemporaryAnimation(Sprite[] sprites, Vector3 position,float lifeTime = 3, float fps = 3, Func xShift = null, Func yShift = null) { if (_temporaryAnimationLevel == null) { Debug.LogError("TemporaryAnimationLevel is not initialized. Cannot generate non-UI animation."); return; } xShift ??= defaultXoffset; yShift ??= defaultYoffset; var obj = Instantiate(temporaryAnimatorSpritePrefab, _temporaryAnimationLevel.transform); obj.transform.position = new Vector3(position.x,position.y); obj.Init(sprites, fps); obj.SetAnimationFunctions(xShift, yShift); obj.lifeTime = lifeTime; } /// /// 生成一个UI文本临时动画。 /// /// 动画的文本内容。 /// 动画在UI坐标系(RectTransform.anchoredPosition)中的初始位置。 /// 动画帧率。 /// X轴位移函数。 /// Y轴位移函数。 public void GenerateTemporaryAnimationUI(string str, Vector2 position,float lifeTime = 3, float fps = 3, Func xShift = null, Func yShift = null) { if (!_temporaryAnimationUILevel) { Debug.LogError("TemporaryAnimationUILevel is not initialized. Cannot generate UI animation."); return; } xShift ??= defaultXoffset; yShift ??= defaultYoffset; var textObj = Instantiate(temporaryAnimatorUITextPrefab, _temporaryAnimationUILevel.transform); textObj.transform.position = position; textObj.Init(str, fps); textObj.SetAnimationFunctions(xShift, yShift); textObj.lifeTime = lifeTime; } /// /// 生成一个UI精灵临时动画。 /// /// 动画的精灵帧数组。 /// 动画在UI坐标系(RectTransform.anchoredPosition)中的初始位置。 /// 动画帧率。 /// X轴位移函数。 /// Y轴位移函数。 public void GenerateTemporaryAnimationUI(Sprite[] sprites, Vector2 position,float lifeTime = 3, float fps = 3, Func xShift = null, Func yShift = null) { if (_temporaryAnimationUILevel == null) { Debug.LogError("TemporaryAnimationUILevel is not initialized. Cannot generate UI animation."); return; } xShift ??= defaultXoffset; yShift ??= defaultYoffset; var obj = Instantiate(temporaryAnimatorImageUIPrefab, _temporaryAnimationUILevel.transform); obj.transform.position = position; obj.Init(sprites, fps); obj.SetAnimationFunctions(xShift, yShift); obj.lifeTime = lifeTime; } /// /// 寻找场景中现有的 Canvas,如果不存在则创建一个新的。 /// 同时确保场景中存在 EventSystem。 /// /// 返回场景中的 Canvas 组件。 private static Canvas GetOrCreateMainCanvas() { var existingCanvas = FindFirstObjectByType(); if (existingCanvas != null) { EnsureEventSystemExists(); // 即使Canvas已存在,也要确保EventSystem存在 return existingCanvas; } // 创建 Canvas GameObject var canvasGO = new GameObject("Canvas"); canvasGO.layer = LayerMask.NameToLayer("UI"); // 建议将UI设置为UI层 // 添加 Canvas 组件 var newCanvas = canvasGO.AddComponent(); newCanvas.renderMode = RenderMode.ScreenSpaceOverlay; // 最常见的UI渲染模式 // 添加其他必要的UI组件 canvasGO.AddComponent(); canvasGO.AddComponent(); // 确保场景中存在 EventSystem,以便UI交互(按钮点击等)能正常工作 EnsureEventSystemExists(); return newCanvas; } /// /// 检查场景中是否存在 EventSystem,如果不存在则创建一个。 /// private static void EnsureEventSystemExists() { var existingEventSystem = FindFirstObjectByType(); if (existingEventSystem != null) return; var eventSystemGO = new GameObject("EventSystem"); eventSystemGO.AddComponent(); eventSystemGO.AddComponent(); // 最常见的输入模块 } } }