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

590 lines
29 KiB
C#
Raw Normal View History

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