2025-09-19 08:26:54 +08:00
|
|
|
|
using System;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
using Data;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
using Prefab;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.EventSystems;
|
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
using Utils;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Managers
|
|
|
|
|
|
{
|
|
|
|
|
|
public class TemporaryAnimationManager : MonoSingleton<TemporaryAnimationManager>
|
|
|
|
|
|
{
|
|
|
|
|
|
[SerializeField] private TemporaryAnimatorImageUI temporaryAnimatorImageUIPrefab;
|
|
|
|
|
|
[SerializeField] private TemporaryAnimatorSprite temporaryAnimatorSpritePrefab;
|
|
|
|
|
|
[SerializeField] private TemporaryAnimatorText temporaryAnimatorTextPrefab;
|
|
|
|
|
|
[SerializeField] private TemporaryAnimatorText temporaryAnimatorUITextPrefab;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
private GameObject _temporaryAnimationLevel; // 非UI临时动画的父级GameObject
|
|
|
|
|
|
private GameObject _temporaryAnimationUILevel; // UI临时动画的父级GameObject
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
SceneManager.sceneLoaded -= OnSceneLoaded;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 管理器销毁时,销毁所有创建的动画层级。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Destroy(_temporaryAnimationLevel);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Destroy(_temporaryAnimationUILevel);
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
protected override void OnStart()
|
|
|
|
|
|
{
|
|
|
|
|
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
|
|
|
|
// 首次启动时为当前场景创建动画层级,确保动画容器在首次使用前存在。
|
|
|
|
|
|
CreateAnimationLayersForCurrentScene(SceneManager.GetActiveScene());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 在新场景加载时重新创建动画层级。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
CreateAnimationLayersForCurrentScene(scene);
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 为当前活动场景创建或重新创建临时动画的父级层级。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="scene">当前加载的场景。</param>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
private void CreateAnimationLayersForCurrentScene(Scene scene)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 销毁场景切换时可能存在的旧动画层级。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (_temporaryAnimationLevel != null) Destroy(_temporaryAnimationLevel);
|
|
|
|
|
|
if (_temporaryAnimationUILevel != null) Destroy(_temporaryAnimationUILevel);
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 创建非UI临时动画的根GameObject。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
_temporaryAnimationLevel = new GameObject("TemporaryAnimations");
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 将非UI动画根GameObject移动到当前场景。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
SceneManager.MoveGameObjectToScene(_temporaryAnimationLevel, scene);
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 获取场景主Canvas,如果不存在则创建。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var mainCanvas = GetOrCreateMainCanvas();
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 创建UI临时动画的根GameObject。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
_temporaryAnimationUILevel = new GameObject("TemporaryUIAnimations");
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 将UI动画根GameObject设为主Canvas的子对象。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
_temporaryAnimationUILevel.transform.SetParent(mainCanvas.transform, false);
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
_temporaryAnimationUILevel.transform.localPosition = Vector3.zero;
|
|
|
|
|
|
_temporaryAnimationUILevel.transform.localScale = Vector3.one;
|
|
|
|
|
|
_temporaryAnimationUILevel.transform.localRotation = Quaternion.identity;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个非UI文本临时动画。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="str">文本内容。</param>
|
|
|
|
|
|
/// <param name="position">世界坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorText 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorText GenerateTemporaryAnimation(string str, Vector3 position, float lifeTime = 3,
|
|
|
|
|
|
float fps = 3,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> xShift = null,
|
|
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (!_temporaryAnimationLevel)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var textObj = Instantiate(temporaryAnimatorTextPrefab, _temporaryAnimationLevel.transform);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
textObj.transform.position = new Vector3(position.x, position.y);
|
2025-09-19 08:26:54 +08:00
|
|
|
|
textObj.Init(str, fps);
|
|
|
|
|
|
textObj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
textObj.lifeTime = lifeTime;
|
|
|
|
|
|
textObj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return textObj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个非UI文本临时动画,可指定父级Transform。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="str">文本内容。</param>
|
|
|
|
|
|
/// <param name="position">世界坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="parent">父级Transform。如果为null,则使用默认非UI动画层。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorText 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorText GenerateTemporaryAnimation(string str, Vector3 position, Transform parent,
|
|
|
|
|
|
float lifeTime = 3, float fps = 3,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> xShift = null,
|
|
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (!_temporaryAnimationLevel)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 优先使用传入的父级,否则使用默认的非UI动画层。
|
|
|
|
|
|
var actualParent = parent ?? _temporaryAnimationLevel.transform;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
|
|
|
|
|
var textObj = Instantiate(temporaryAnimatorTextPrefab, actualParent);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
textObj.transform.position = position;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
textObj.Init(str, fps);
|
|
|
|
|
|
textObj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
textObj.lifeTime = lifeTime;
|
|
|
|
|
|
textObj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return textObj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个非UI精灵临时动画。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="sprites">精灵帧数组。</param>
|
|
|
|
|
|
/// <param name="position">世界坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorSprite 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorSprite GenerateTemporaryAnimation(Sprite[] sprites, Vector3 position,
|
|
|
|
|
|
float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (!_temporaryAnimationLevel)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var obj = Instantiate(temporaryAnimatorSpritePrefab, _temporaryAnimationLevel.transform);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
obj.transform.position = new Vector3(position.x, position.y);
|
2025-09-19 08:26:54 +08:00
|
|
|
|
obj.Init(sprites, fps);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个非UI精灵临时动画,可指定父级Transform。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="sprites">精灵帧数组。</param>
|
|
|
|
|
|
/// <param name="position">世界坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="parent">父级Transform。如果为null,则使用默认非UI动画层。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorSprite 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorSprite GenerateTemporaryAnimation(Sprite[] sprites, Vector3 position, Transform parent,
|
|
|
|
|
|
float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (!_temporaryAnimationLevel)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 优先使用传入的父级,否则使用默认的非UI动画层。
|
|
|
|
|
|
var actualParent = parent ?? _temporaryAnimationLevel.transform;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
|
|
|
|
|
var obj = Instantiate(temporaryAnimatorSpritePrefab, actualParent);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
obj.transform.position = position;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
obj.Init(sprites, fps);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个非UI DrawNodeDef 临时动画及其子动画。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="drawNode">绘制节点定义。</param>
|
|
|
|
|
|
/// <param name="position">世界坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
|
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
|
|
|
|
|
/// <returns>创建的根 TemporaryAnimatorSprite 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorSprite GenerateTemporaryAnimation(DrawNodeDef drawNode, Vector3 position,
|
|
|
|
|
|
float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_temporaryAnimationLevel == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
var textureSprite = PackagesImageManager.Instance.GetSprites(drawNode.textures);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (textureSprite == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"TemporaryAnimationManager: 无法找到DrawNodeDef纹理 '{drawNode.textures}' 的精灵。跳过动画。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var obj = Instantiate(temporaryAnimatorSpritePrefab, _temporaryAnimationLevel.transform);
|
2025-10-10 14:08:23 +08:00
|
|
|
|
obj.transform.position = new Vector2(position.x, position.y) + StringUtils.StringToVector2(
|
|
|
|
|
|
drawNode.position);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
obj.Init(textureSprite, drawNode.FPS);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
|
|
|
|
|
if (drawNode.nodes == null) return obj;
|
|
|
|
|
|
foreach (var childNode in drawNode.nodes)
|
|
|
|
|
|
// 递归生成子动画,使用默认的非UI动画层。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
GenerateTemporaryAnimation(childNode, position, _temporaryAnimationLevel.transform, lifeTime, fps,
|
|
|
|
|
|
xShift, yShift);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个非UI DrawNodeDef 临时动画及其子动画,可指定父级Transform。
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="drawNode">绘制节点定义。</param>
|
|
|
|
|
|
/// <param name="position">世界坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="parent">父级Transform。如果为null,则使用默认非UI动画层。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
|
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
|
|
|
|
|
/// <returns>创建的根 TemporaryAnimatorSprite 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorSprite GenerateTemporaryAnimation(DrawNodeDef drawNode, Vector3 position,
|
|
|
|
|
|
Transform parent, float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_temporaryAnimationLevel == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 优先使用传入的父级,否则使用默认的非UI动画层。
|
|
|
|
|
|
var actualParent = parent ?? _temporaryAnimationLevel.transform;
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var textureSprite = PackagesImageManager.Instance.GetSprites(drawNode.textures);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (textureSprite == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"TemporaryAnimationManager: 无法找到DrawNodeDef纹理 '{drawNode.textures}' 的精灵。跳过动画。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var obj = Instantiate(temporaryAnimatorSpritePrefab, actualParent);
|
2025-10-10 14:08:23 +08:00
|
|
|
|
obj.transform.position = new Vector2(position.x, position.y) +
|
|
|
|
|
|
StringUtils.StringToVector2(drawNode.position);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
obj.Init(textureSprite, drawNode.FPS);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
|
|
|
|
|
if (drawNode.nodes == null) return obj;
|
|
|
|
|
|
foreach (var childNode in drawNode.nodes)
|
|
|
|
|
|
// 递归生成子动画,子节点位置基于父节点位置加上自身偏移,父级为当前对象。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
GenerateTemporaryAnimation(childNode,
|
|
|
|
|
|
position + (Vector3)StringUtils.StringToVector2(drawNode.position), obj.transform, lifeTime, fps,
|
|
|
|
|
|
xShift, yShift);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
public TemporaryAnimatorImageUI GenerateTemporaryAnimationUI(DrawNodeDef drawNode, Vector3 worldPosition,
|
|
|
|
|
|
Transform parent, float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_temporaryAnimationLevel == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 非UI动画层未初始化。请确保管理器在生成非UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 优先使用传入的父级,否则使用默认的非UI动画层。
|
|
|
|
|
|
var actualParent = parent ?? _temporaryAnimationLevel.transform;
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var textureSprite = PackagesImageManager.Instance.GetSprites(drawNode.textures);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (textureSprite == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"TemporaryAnimationManager: 无法找到DrawNodeDef纹理 '{drawNode.textures}' 的精灵。跳过动画。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var obj = Instantiate(temporaryAnimatorImageUIPrefab, actualParent);
|
2025-10-10 14:08:23 +08:00
|
|
|
|
obj.transform.position = new Vector2(worldPosition.x, worldPosition.y) +
|
|
|
|
|
|
StringUtils.StringToVector2(drawNode.position);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
obj.Init(textureSprite, drawNode.FPS);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
|
|
|
|
|
if (drawNode.nodes == null) return obj;
|
|
|
|
|
|
foreach (var childNode in drawNode.nodes)
|
|
|
|
|
|
// 递归生成子动画,子节点位置基于父节点位置加上自身偏移,父级为当前对象。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
GenerateTemporaryAnimation(childNode,
|
|
|
|
|
|
worldPosition + (Vector3)StringUtils.StringToVector2(drawNode.position), obj.transform,
|
|
|
|
|
|
lifeTime, fps, xShift, yShift);
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个UI文本临时动画。
|
|
|
|
|
|
/// 此重载将传入的 <paramref name="position" /> 视为屏幕坐标 (如鼠标位置),并将其自动转换为Canvas局部坐标。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="str">文本内容。</param>
|
|
|
|
|
|
/// <param name="position">屏幕坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorText 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorText GenerateTemporaryAnimationUI(string str, Vector2 position, float lifeTime = 3,
|
|
|
|
|
|
float fps = 3, Func<float, float> xShift = null,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (_temporaryAnimationUILevel == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: UI动画层未初始化。无法生成UI动画。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var textObj = Instantiate(temporaryAnimatorUITextPrefab, _temporaryAnimationUILevel.transform);
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var canvasRectTransform = _temporaryAnimationUILevel.transform as RectTransform;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
if (canvasRectTransform != null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var rootCanvas = canvasRectTransform.root.GetComponent<Canvas>();
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Camera eventCamera = null;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
|
|
|
|
|
// 根据Canvas的RenderMode确定用于屏幕坐标转换的相机。
|
|
|
|
|
|
if (rootCanvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
else if (rootCanvas.renderMode == RenderMode.ScreenSpaceCamera ||
|
|
|
|
|
|
rootCanvas.renderMode == RenderMode.WorldSpace)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
eventCamera = rootCanvas.worldCamera;
|
|
|
|
|
|
if (eventCamera == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
eventCamera = Camera.main;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (eventCamera == null)
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogWarning(
|
|
|
|
|
|
$"Canvas '{rootCanvas.name}' 处于 {rootCanvas.renderMode} 模式但世界相机为null且未找到主相机。UI动画位置可能不正确。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Vector2 localPoint;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, position, eventCamera,
|
|
|
|
|
|
out localPoint))
|
2025-09-19 08:26:54 +08:00
|
|
|
|
textObj.rectTransform.anchoredPosition = localPoint;
|
|
|
|
|
|
else
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogWarning(
|
|
|
|
|
|
$"未能将屏幕点 {position} 转换为UI动画在Canvas '{rootCanvas.name}' 上的局部点。将使用默认锚点位置 (0,0)。请检查Canvas的RenderMode和世界相机设置。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: UI动画层不是RectTransform。无法转换屏幕点。UI动画无法正确放置。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
textObj.Init(str, fps);
|
|
|
|
|
|
textObj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
textObj.lifeTime = lifeTime;
|
|
|
|
|
|
textObj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return textObj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个UI文本临时动画,可指定父级RectTransform。
|
|
|
|
|
|
/// 此重载将传入的 <paramref name="position" /> 视为相对于父级RectTransform的 anchoredPosition。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="str">文本内容。</param>
|
|
|
|
|
|
/// <param name="position">UI坐标系(RectTransform.anchoredPosition)中的初始位置。</param>
|
|
|
|
|
|
/// <param name="parent">父级RectTransform。如果为null,则使用默认的UI动画层。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorText 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorText GenerateTemporaryAnimationUI(string str, Vector2 position, RectTransform parent,
|
|
|
|
|
|
float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (_temporaryAnimationUILevel == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: UI动画层未初始化。请确保管理器在生成UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var defaultUIParent = _temporaryAnimationUILevel.transform as RectTransform;
|
|
|
|
|
|
if (defaultUIParent == null)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 默认UI动画层不是RectTransform。无法生成UI动画。");
|
|
|
|
|
|
return null;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var actualParent = parent ?? defaultUIParent;
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var textObj = Instantiate(temporaryAnimatorUITextPrefab, actualParent, false);
|
|
|
|
|
|
textObj.rectTransform.anchoredPosition = position;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
textObj.Init(str, fps);
|
|
|
|
|
|
textObj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
textObj.lifeTime = lifeTime;
|
|
|
|
|
|
textObj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return textObj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个UI精灵临时动画。
|
|
|
|
|
|
/// 此重载将传入的 <paramref name="position" /> 视为屏幕坐标 (如鼠标位置),并将其自动转换为Canvas局部坐标。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="sprites">精灵帧数组。</param>
|
|
|
|
|
|
/// <param name="position">屏幕坐标系中的初始位置。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorImageUI 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorImageUI GenerateTemporaryAnimationUI(Sprite[] sprites, Vector2 position,
|
|
|
|
|
|
float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_temporaryAnimationUILevel == null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: UI动画层未初始化。无法生成UI动画。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var obj = Instantiate(temporaryAnimatorImageUIPrefab, _temporaryAnimationUILevel.transform);
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var canvasRectTransform = _temporaryAnimationUILevel.transform as RectTransform;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
if (canvasRectTransform != null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var rootCanvas = canvasRectTransform.root.GetComponent<Canvas>();
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Camera eventCamera = null;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
|
|
|
|
|
// 根据Canvas的RenderMode确定用于屏幕坐标转换的相机。
|
|
|
|
|
|
if (rootCanvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
else if (rootCanvas.renderMode == RenderMode.ScreenSpaceCamera ||
|
|
|
|
|
|
rootCanvas.renderMode == RenderMode.WorldSpace)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
eventCamera = rootCanvas.worldCamera;
|
|
|
|
|
|
if (eventCamera == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
eventCamera = Camera.main;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (eventCamera == null)
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogWarning(
|
|
|
|
|
|
$"Canvas '{rootCanvas.name}' 处于 {rootCanvas.renderMode} 模式但世界相机为null且未找到主相机。UI动画位置可能不正确。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Vector2 localPoint;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, position, eventCamera,
|
|
|
|
|
|
out localPoint))
|
2025-09-19 08:26:54 +08:00
|
|
|
|
obj.rectTransform.anchoredPosition = localPoint;
|
|
|
|
|
|
else
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogWarning(
|
|
|
|
|
|
$"未能将屏幕点 {position} 转换为UI动画在Canvas '{rootCanvas.name}' 上的局部点。将使用默认锚点位置 (0,0)。请检查Canvas的RenderMode和世界相机设置。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: UI动画层不是RectTransform。无法转换屏幕点。UI动画无法正确放置。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
obj.Init(sprites, fps);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 生成一个UI精灵临时动画,可指定父级RectTransform。
|
|
|
|
|
|
/// 此重载将传入的 <paramref name="position" /> 视为相对于父级RectTransform的 anchoredPosition。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="sprites">精灵帧数组。</param>
|
|
|
|
|
|
/// <param name="position">UI坐标系(RectTransform.anchoredPosition)中的初始位置。</param>
|
|
|
|
|
|
/// <param name="parent">父级RectTransform。如果为null,则使用默认的UI动画层。</param>
|
|
|
|
|
|
/// <param name="lifeTime">生命周期(秒)。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="fps">动画帧率。</param>
|
|
|
|
|
|
/// <param name="xShift">X轴位移函数。</param>
|
|
|
|
|
|
/// <param name="yShift">Y轴位移函数。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <returns>创建的 TemporaryAnimatorImageUI 对象。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public TemporaryAnimatorImageUI GenerateTemporaryAnimationUI(Sprite[] sprites, Vector2 position,
|
|
|
|
|
|
RectTransform parent, float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Func<float, float> yShift = null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (_temporaryAnimationUILevel == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: UI动画层未初始化。请确保管理器在生成UI动画前已正确初始化。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var defaultUIParent = _temporaryAnimationUILevel.transform as RectTransform;
|
|
|
|
|
|
if (defaultUIParent == null)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogError("TemporaryAnimationManager: 默认UI动画层不是RectTransform。无法生成UI动画。");
|
|
|
|
|
|
return null;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
var actualParent = parent ?? defaultUIParent;
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var obj = Instantiate(temporaryAnimatorImageUIPrefab, actualParent, false);
|
2025-09-19 08:26:54 +08:00
|
|
|
|
obj.rectTransform.anchoredPosition = position;
|
|
|
|
|
|
obj.Init(sprites, fps);
|
|
|
|
|
|
obj.SetAnimationFunctions(xShift, yShift);
|
|
|
|
|
|
obj.lifeTime = lifeTime;
|
|
|
|
|
|
obj.gameObject.SetActive(true);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
return obj;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 寻找场景中现有的 Canvas,如果不存在则创建一个新的。
|
|
|
|
|
|
/// 同时确保场景中存在 EventSystem。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>返回场景中的 Canvas 组件。</returns>
|
|
|
|
|
|
private static Canvas GetOrCreateMainCanvas()
|
|
|
|
|
|
{
|
|
|
|
|
|
var existingCanvas = FindFirstObjectByType<Canvas>();
|
|
|
|
|
|
if (existingCanvas != null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 如果现有Canvas需要WorldCamera但未设置,尝试赋值Camera.main。
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (existingCanvas.renderMode == RenderMode.ScreenSpaceCamera ||
|
|
|
|
|
|
existingCanvas.renderMode == RenderMode.WorldSpace)
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (existingCanvas.worldCamera == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mainCamera = Camera.main;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (mainCamera == null) Debug.LogWarning("现有Canvas处于屏幕相机/世界空间模式但未设置世界相机,且主相机为空。UI动画可能无法正确渲染。");
|
2025-09-28 15:02:57 +08:00
|
|
|
|
existingCanvas.worldCamera = mainCamera;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
EnsureEventSystemExists();
|
2025-09-19 08:26:54 +08:00
|
|
|
|
return existingCanvas;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 在场景中创建一个新的Canvas GameObject。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var canvasGO = new GameObject("Canvas");
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 将新创建的Canvas移动到当前场景根目录。
|
|
|
|
|
|
SceneManager.MoveGameObjectToScene(canvasGO, SceneManager.GetActiveScene());
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
canvasGO.layer = LayerMask.NameToLayer("UI");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var newCanvas = canvasGO.AddComponent<Canvas>();
|
2025-10-10 14:08:23 +08:00
|
|
|
|
newCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
canvasGO.AddComponent<CanvasScaler>();
|
|
|
|
|
|
canvasGO.AddComponent<GraphicRaycaster>();
|
|
|
|
|
|
EnsureEventSystemExists();
|
|
|
|
|
|
return newCanvas;
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 检查场景中是否存在 EventSystem,如果不存在则创建一个。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static void EnsureEventSystemExists()
|
|
|
|
|
|
{
|
|
|
|
|
|
var existingEventSystem = FindFirstObjectByType<EventSystem>();
|
|
|
|
|
|
if (existingEventSystem != null) return;
|
|
|
|
|
|
var eventSystemGO = new GameObject("EventSystem");
|
|
|
|
|
|
eventSystemGO.AddComponent<EventSystem>();
|
2025-09-28 15:02:57 +08:00
|
|
|
|
eventSystemGO.AddComponent<StandaloneInputModule>();
|
|
|
|
|
|
|
|
|
|
|
|
// 将新的EventSystem移动到当前场景。
|
|
|
|
|
|
SceneManager.MoveGameObjectToScene(eventSystemGO, SceneManager.GetActiveScene());
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
}
|