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

589 lines
29 KiB
C#
Raw Permalink 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 Data;
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;
private GameObject _temporaryAnimationLevel; // 非UI临时动画的父级GameObject
private GameObject _temporaryAnimationUILevel; // UI临时动画的父级GameObject
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
// 管理器销毁时,销毁所有创建的动画层级。
Destroy(_temporaryAnimationLevel);
Destroy(_temporaryAnimationUILevel);
}
protected override void OnStart()
{
SceneManager.sceneLoaded += OnSceneLoaded;
// 首次启动时为当前场景创建动画层级,确保动画容器在首次使用前存在。
CreateAnimationLayersForCurrentScene(SceneManager.GetActiveScene());
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// 在新场景加载时重新创建动画层级。
CreateAnimationLayersForCurrentScene(scene);
}
/// <summary>
/// 为当前活动场景创建或重新创建临时动画的父级层级。
/// </summary>
/// <param name="scene">当前加载的场景。</param>
private void CreateAnimationLayersForCurrentScene(Scene scene)
{
// 销毁场景切换时可能存在的旧动画层级。
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)
{
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)
{
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)
{
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)
{
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) + StringUtils.StringToVector2(
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) +
StringUtils.StringToVector2(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)StringUtils.StringToVector2(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) +
StringUtils.StringToVector2(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)StringUtils.StringToVector2(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)
{
}
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, 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)
{
}
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, 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());
}
}
}