Files
Gen_Hack-and-Slash-Roguelit…/Client/Assets/Scripts/Managers/TemporaryAnimationManager.cs

231 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using Prefab;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Utils;
namespace Managers
{
public class TemporaryAnimationManager : MonoSingleton<TemporaryAnimationManager>
{
// 将包装图层改为由代码动态创建和管理
private GameObject _temporaryAnimationLevel;
private GameObject _temporaryAnimationUILevel;
[SerializeField] private TemporaryAnimatorImageUI temporaryAnimatorImageUIPrefab;
[SerializeField] private TemporaryAnimatorSprite temporaryAnimatorSpritePrefab;
[SerializeField] private TemporaryAnimatorText temporaryAnimatorTextPrefab;
[SerializeField] private TemporaryAnimatorText temporaryAnimatorUITextPrefab;
private Func<float, float> defaultXoffset = f => Mathf.Sin(f * 3);
private Func<float, float> 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);
}
/// <summary>
/// 为当前活动场景创建或重新创建临时动画的父级图层。
/// </summary>
/// <param name="scene">当前加载的场景。</param>
/// <param name="mode">场景加载模式。</param>
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<float, float> xShift = null,
Func<float, float> 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;
}
/// <summary>
/// 生成一个非UI精灵临时动画。
/// </summary>
/// <param name="sprites">动画的精灵帧数组。</param>
/// <param name="position">动画在世界坐标系中的初始位置。</param>
/// <param name="fps">动画帧率。</param>
/// <param name="xShift">X轴位移函数。</param>
/// <param name="yShift">Y轴位移函数。</param>
public void GenerateTemporaryAnimation(Sprite[] sprites, Vector3 position,float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
Func<float, float> 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;
}
/// <summary>
/// 生成一个UI文本临时动画。
/// </summary>
/// <param name="str">动画的文本内容。</param>
/// <param name="position">动画在UI坐标系(RectTransform.anchoredPosition)中的初始位置。</param>
/// <param name="fps">动画帧率。</param>
/// <param name="xShift">X轴位移函数。</param>
/// <param name="yShift">Y轴位移函数。</param>
public void GenerateTemporaryAnimationUI(string str, Vector2 position,float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
Func<float, float> 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;
}
/// <summary>
/// 生成一个UI精灵临时动画。
/// </summary>
/// <param name="sprites">动画的精灵帧数组。</param>
/// <param name="position">动画在UI坐标系(RectTransform.anchoredPosition)中的初始位置。</param>
/// <param name="fps">动画帧率。</param>
/// <param name="xShift">X轴位移函数。</param>
/// <param name="yShift">Y轴位移函数。</param>
public void GenerateTemporaryAnimationUI(Sprite[] sprites, Vector2 position,float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
Func<float, float> 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;
}
/// <summary>
/// 寻找场景中现有的 Canvas如果不存在则创建一个新的。
/// 同时确保场景中存在 EventSystem。
/// </summary>
/// <returns>返回场景中的 Canvas 组件。</returns>
private static Canvas GetOrCreateMainCanvas()
{
var existingCanvas = FindFirstObjectByType<Canvas>();
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<Canvas>();
newCanvas.renderMode = RenderMode.ScreenSpaceOverlay; // 最常见的UI渲染模式
// 添加其他必要的UI组件
canvasGO.AddComponent<CanvasScaler>();
canvasGO.AddComponent<GraphicRaycaster>();
// 确保场景中存在 EventSystem以便UI交互按钮点击等能正常工作
EnsureEventSystemExists();
return newCanvas;
}
/// <summary>
/// 检查场景中是否存在 EventSystem如果不存在则创建一个。
/// </summary>
private static void EnsureEventSystemExists()
{
var existingEventSystem = FindFirstObjectByType<EventSystem>();
if (existingEventSystem != null) return;
var eventSystemGO = new GameObject("EventSystem");
eventSystemGO.AddComponent<EventSystem>();
eventSystemGO.AddComponent<StandaloneInputModule>(); // 最常见的输入模块
}
}
}