(client) feat:添加消息定义,添加故事定义及其运算,武器动画可用,装备UI可用以及切换武器 fix:修复快速攻击导致协程释放出错卡死,重构为计时器,修复类型转换错误导致报错

This commit is contained in:
m0_75251201
2025-09-08 00:13:12 +08:00
parent 15cdd2b244
commit 379ed07773
39 changed files with 8353 additions and 937 deletions

View File

@ -18,9 +18,6 @@ namespace Managers
[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()
{
@ -89,6 +86,15 @@ namespace Managers
}
/// <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>
public void GenerateTemporaryAnimation(string str, Vector3 position, float lifeTime = 3, float fps = 3,
Func<float, float> xShift = null,
Func<float, float> yShift = null)
@ -99,13 +105,42 @@ namespace Managers
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;
textObj.gameObject.SetActive(true);
}
/// <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>
public void GenerateTemporaryAnimation(string str, Vector3 position, Transform parent, float lifeTime = 3, float fps = 3,
Func<float, float> xShift = null,
Func<float, float> yShift = null)
{
Transform actualParent = parent ?? _temporaryAnimationLevel?.transform;
if (actualParent == null)
{
Debug.LogError("TemporaryAnimationLevel or specified parent is not initialized. Cannot generate non-UI animation.");
return;
}
var textObj = Instantiate(temporaryAnimatorTextPrefab, actualParent);
textObj.transform.position = position; // 外部传入的position应视为世界坐标
textObj.Init(str, fps);
textObj.SetAnimationFunctions(xShift, yShift);
textObj.lifeTime = lifeTime;
textObj.gameObject.SetActive(true);
}
/// <summary>
@ -113,32 +148,64 @@ namespace Managers
/// </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>
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)
if (!_temporaryAnimationLevel)
{
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;
obj.gameObject.SetActive(true);
}
/// <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>
public void GenerateTemporaryAnimation(Sprite[] sprites, Vector3 position, Transform parent, float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
Func<float, float> yShift = null)
{
Transform actualParent = parent ?? _temporaryAnimationLevel?.transform;
if (actualParent == null)
{
Debug.LogError("TemporaryAnimationLevel or specified parent is not initialized. Cannot generate non-UI animation.");
return;
}
var obj = Instantiate(temporaryAnimatorSpritePrefab, actualParent);
obj.transform.position = position; // 外部传入的position应视为世界坐标
obj.Init(sprites, fps);
obj.SetAnimationFunctions(xShift, yShift);
obj.lifeTime = lifeTime;
obj.gameObject.SetActive(true);
}
/// <summary>
/// 生成一个UI文本临时动画。
/// 此重载将传入的 <paramref name="position"/> 视为屏幕坐标 (如鼠标位置)并将其自动转换为Canvas局部坐标。
/// </summary>
/// <param name="str">动画的文本内容。</param>
/// <param name="position">动画在UI坐标系(RectTransform.anchoredPosition)中的初始位置。</param>
/// <param name="position">动画在屏幕坐标系中的初始位置(如鼠标位置)。</param>
/// <param name="lifeTime">动画的生命周期(秒)。</param>
/// <param name="fps">动画帧率。</param>
/// <param name="xShift">X轴位移函数。</param>
/// <param name="yShift">Y轴位移函数。</param>
@ -150,22 +217,86 @@ namespace Managers
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;
RectTransform canvasRectTransform = _temporaryAnimationUILevel.transform as RectTransform;
if (canvasRectTransform != null)
{
// 获取Canvas组件特别是RenderMode为ScreenSpaceCamera时需要worldCamera
Canvas rootCanvas = canvasRectTransform.root.GetComponent<Canvas>();
Camera eventCamera = null;
if (rootCanvas.renderMode == RenderMode.ScreenSpaceCamera || rootCanvas.renderMode == RenderMode.WorldSpace)
{
eventCamera = rootCanvas.worldCamera; // 使用Canvas指定的相机
if (eventCamera == null) // 如果Canvas没有指定相机尝试主相机
{
eventCamera = Camera.main;
}
}
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, position, eventCamera, out var localPoint))
{
textObj.rectTransform.anchoredPosition = localPoint;
}
else
{
textObj.rectTransform.anchoredPosition = position;
Debug.LogWarning("Failed to convert screen point to local point for UI text animation. Using raw position.");
}
}
else
{
textObj.rectTransform.anchoredPosition = position;
Debug.LogWarning("TemporaryAnimationUILevel is not a RectTransform. Unable to convert screen point. Using raw position.");
}
textObj.Init(str, fps);
textObj.SetAnimationFunctions(xShift, yShift);
textObj.lifeTime = lifeTime;
textObj.gameObject.SetActive(true);
}
/// <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>
public void GenerateTemporaryAnimationUI(string str, Vector2 position, RectTransform parent, float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
Func<float, float> yShift = null)
{
RectTransform actualParent = parent ?? (_temporaryAnimationUILevel?.transform as RectTransform);
if (actualParent == null)
{
Debug.LogError("TemporaryAnimationUILevel or specified parent is not initialized or not a RectTransform. Cannot generate UI animation.");
return;
}
var textObj = Instantiate(temporaryAnimatorUITextPrefab);
textObj.rectTransform.SetParent(actualParent, false); // SetParent with worldPositionStay: false
textObj.rectTransform.anchoredPosition = position;
textObj.Init(str, fps);
textObj.SetAnimationFunctions(xShift, yShift);
textObj.lifeTime = lifeTime;
textObj.gameObject.SetActive(true);
}
/// <summary>
/// 生成一个UI精灵临时动画。
/// 此重载将传入的 <paramref name="position"/> 视为屏幕坐标 (如鼠标位置)并将其自动转换为Canvas局部坐标。
/// </summary>
/// <param name="sprites">动画的精灵帧数组。</param>
/// <param name="position">动画在UI坐标系(RectTransform.anchoredPosition)中的初始位置。</param>
/// <param name="position">动画在屏幕坐标系中的初始位置(如鼠标位置)。</param>
/// <param name="lifeTime">动画的生命周期(秒)。</param>
/// <param name="fps">动画帧率。</param>
/// <param name="xShift">X轴位移函数。</param>
/// <param name="yShift">Y轴位移函数。</param>
@ -178,13 +309,76 @@ namespace Managers
return;
}
xShift ??= defaultXoffset;
yShift ??= defaultYoffset;
var obj = Instantiate(temporaryAnimatorImageUIPrefab, _temporaryAnimationUILevel.transform);
obj.transform.position = position;
RectTransform canvasRectTransform = _temporaryAnimationUILevel.transform as RectTransform;
if (canvasRectTransform != null)
{
// 获取Canvas组件特别是RenderMode为ScreenSpaceCamera时需要worldCamera
Canvas rootCanvas = canvasRectTransform.root.GetComponent<Canvas>();
Camera eventCamera = null;
if (rootCanvas.renderMode == RenderMode.ScreenSpaceCamera || rootCanvas.renderMode == RenderMode.WorldSpace)
{
eventCamera = rootCanvas.worldCamera; // 使用Canvas指定的相机
if (eventCamera == null) // 如果Canvas没有指定相机尝试主相机
{
eventCamera = Camera.main;
}
}
Vector2 localPoint;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, position, eventCamera, out localPoint))
{
obj.rectTransform.anchoredPosition = localPoint;
}
else
{
obj.rectTransform.anchoredPosition = position;
Debug.LogWarning("Failed to convert screen point to local point for UI sprite animation. Using raw position.");
}
}
else
{
obj.rectTransform.anchoredPosition = position;
Debug.LogWarning("TemporaryAnimationUILevel is not a RectTransform. Unable to convert screen point. Using raw position.");
}
obj.Init(sprites, fps);
obj.SetAnimationFunctions(xShift, yShift);
obj.lifeTime = lifeTime;
obj.gameObject.SetActive(true);
}
/// <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>
public void GenerateTemporaryAnimationUI(Sprite[] sprites, Vector2 position, RectTransform parent, float lifeTime = 3, float fps = 3, Func<float, float> xShift = null,
Func<float, float> yShift = null)
{
RectTransform actualParent = parent ?? (_temporaryAnimationUILevel?.transform as RectTransform);
if (actualParent == null)
{
Debug.LogError("TemporaryAnimationUILevel or specified parent is not initialized or not a RectTransform. Cannot generate UI animation.");
return;
}
var obj = Instantiate(temporaryAnimatorImageUIPrefab);
obj.rectTransform.SetParent(actualParent, false); // SetParent with worldPositionStay: false
obj.rectTransform.anchoredPosition = position;
obj.Init(sprites, fps);
obj.SetAnimationFunctions(xShift, yShift);
obj.lifeTime = lifeTime;
obj.gameObject.SetActive(true);
}
@ -198,20 +392,23 @@ namespace Managers
var existingCanvas = FindFirstObjectByType<Canvas>();
if (existingCanvas != null)
{
EnsureEventSystemExists(); // 即使Canvas已存在也要确保EventSystem存在
EnsureEventSystemExists();
return existingCanvas;
}
// 创建 Canvas GameObject
var canvasGO = new GameObject("Canvas");
canvasGO.layer = LayerMask.NameToLayer("UI"); // 建议将UI设置为UI层
// 添加 Canvas 组件
canvasGO.layer = LayerMask.NameToLayer("UI");
var newCanvas = canvasGO.AddComponent<Canvas>();
newCanvas.renderMode = RenderMode.ScreenSpaceOverlay; // 最常见的UI渲染模式
// 添加其他必要的UI组件
newCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
// 确保有相机以便RectTransformUtility.ScreenPointToLocalPointInRectangle可以工作
// 对于ScreenSpaceOverlayworldCamera可以为null但为了通用性和健壮性这里设置为Camera.main
// 以防Canvas.renderMode将来调整为ScreenSpaceCamera或WorldSpace
newCanvas.worldCamera = Camera.main;
canvasGO.AddComponent<CanvasScaler>();
canvasGO.AddComponent<GraphicRaycaster>();
// 确保场景中存在 EventSystem以便UI交互按钮点击等能正常工作
EnsureEventSystemExists();
return newCanvas;
}