Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Data/DrawingOrderDef.cs

296 lines
10 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using UnityEngine;
namespace Data
{
public enum Orientation
{
Down,
Left,
Right,
Up
}
public enum EntityState
{
Idle,
Walking,
MeleeAttack,
RangedAttack,
}
public class DrawingOrderDef : Define
{
public DrawNodeDef idle_down;
public DrawNodeDef idle_up;
public DrawNodeDef idle_left;
public DrawNodeDef idle_right;
public DrawNodeDef walk_down;
public DrawNodeDef walk_up;
public DrawNodeDef walk_left;
public DrawNodeDef walk_right;
public DrawNodeDef meleeAttack_down;
public DrawNodeDef meleeAttack_up;
public DrawNodeDef meleeAttack_left;
public DrawNodeDef meleeAttack_right;
public DrawNodeDef rangedAttack_down;
public DrawNodeDef rangedAttack_up;
public DrawNodeDef rangedAttack_left;
public DrawNodeDef rangedAttack_right;
public DrawNodeDef GetDrawNodeDef(EntityState state, Orientation orientation,
out Orientation? fallbackOrientation)
{
fallbackOrientation = null;
// 根据状态和方向获取对应的DrawNodeDef
var result = GetDrawNodeDefInternal(state, orientation);
if (result != null)
{
return result;
}
// 如果找不到,按照规则查找替补
switch (orientation)
{
case Orientation.Up:
// 上方向优先找下方向
result = GetDrawNodeDefInternal(state, Orientation.Down);
if (result != null)
{
fallbackOrientation = Orientation.Down;
return result;
}
// 其次找左右方向
result = GetDrawNodeDefInternal(state, Orientation.Left);
if (result != null)
{
fallbackOrientation = Orientation.Left;
return result;
}
result = GetDrawNodeDefInternal(state, Orientation.Right);
if (result != null)
{
fallbackOrientation = Orientation.Right;
return result;
}
break;
case Orientation.Down:
// 下方向优先找上方向
result = GetDrawNodeDefInternal(state, Orientation.Up);
if (result != null)
{
fallbackOrientation = Orientation.Up;
return result;
}
// 其次找左右方向
result = GetDrawNodeDefInternal(state, Orientation.Left);
if (result != null)
{
fallbackOrientation = Orientation.Left;
return result;
}
result = GetDrawNodeDefInternal(state, Orientation.Right);
if (result != null)
{
fallbackOrientation = Orientation.Right;
return result;
}
break;
case Orientation.Left:
// 左方向优先找右方向
result = GetDrawNodeDefInternal(state, Orientation.Right);
if (result != null)
{
fallbackOrientation = Orientation.Right;
return result;
}
// 其次找上下方向
result = GetDrawNodeDefInternal(state, Orientation.Up);
if (result != null)
{
fallbackOrientation = Orientation.Up;
return result;
}
result = GetDrawNodeDefInternal(state, Orientation.Down);
if (result != null)
{
fallbackOrientation = Orientation.Down;
return result;
}
break;
case Orientation.Right:
// 右方向优先找左方向
result = GetDrawNodeDefInternal(state, Orientation.Left);
if (result != null)
{
fallbackOrientation = Orientation.Left;
return result;
}
// 其次找上下方向
result = GetDrawNodeDefInternal(state, Orientation.Up);
if (result != null)
{
fallbackOrientation = Orientation.Up;
return result;
}
result = GetDrawNodeDefInternal(state, Orientation.Down);
if (result != null)
{
fallbackOrientation = Orientation.Down;
return result;
}
break;
default:
throw new ArgumentOutOfRangeException(nameof(orientation), orientation, null);
}
// 如果所有替补都找不到返回null
return null;
}
private DrawNodeDef GetDrawNodeDefInternal(EntityState state, Orientation orientation)
{
// 根据状态和方向获取对应的DrawNodeDef
switch (state)
{
case EntityState.Idle:
switch (orientation)
{
case Orientation.Down: return idle_down;
case Orientation.Up: return idle_up;
case Orientation.Left: return idle_left;
case Orientation.Right: return idle_right;
}
break;
case EntityState.Walking:
switch (orientation)
{
case Orientation.Down: return walk_down;
case Orientation.Up: return walk_up;
case Orientation.Left: return walk_left;
case Orientation.Right: return walk_right;
}
break;
case EntityState.MeleeAttack:
switch (orientation)
{
case Orientation.Down: return meleeAttack_down;
case Orientation.Up: return meleeAttack_up;
case Orientation.Left: return meleeAttack_left;
case Orientation.Right: return meleeAttack_right;
}
break;
case EntityState.RangedAttack:
switch (orientation)
{
case Orientation.Down: return rangedAttack_down;
case Orientation.Up: return rangedAttack_up;
case Orientation.Left: return rangedAttack_left;
case Orientation.Right: return rangedAttack_right;
}
break;
}
return null;
}
}
public class DrawNodeDef : Define
{
public List<string> textures = new();
public List<DrawNodeDef> nodes = new();
public string nodeName;
public Vector2 position = new(0, 0);
public float FPS = 0.5f;
public override bool Init(XElement xmlDef)
{
base.Init(xmlDef);
nodeName = xmlDef.Attribute("name")?.Value??"noName";
position = StringToVector(xmlDef.Attribute("position")?.Value ?? "(0 0)");
FPS = float.TryParse(xmlDef.Attribute("FPS")?.Value, out var result) ? result : 1.0f;
return false;
}
public Vector2 StringToVector(string vectorDef)
{
// 去掉可能存在的括号和多余的空格
var cleanedInput = vectorDef.Replace("(", "").Replace(")", "").Trim();
// 使用正则表达式匹配两个浮点数
var match = Regex.Match(cleanedInput, @"\s*(-?\d+(\.\d*)?)\s*[, ]\s*(-?\d+(\.\d*)?)\s*");
if (match.Success)
{
// 提取匹配到的两个浮点数
var x = float.Parse(match.Groups[1].Value);
var y = float.Parse(match.Groups[3].Value);
// 返回 Vector2 对象
return new Vector2(x, y);
}
return Vector2.zero;
}
/// <summary>
/// 计算动画执行一个周期的总时间(包括子对象)。
/// 如果自身没有纹理自身动画时间为0。
/// 总周期取自身动画时间和所有子动画周期中的最大值。
/// </summary>
/// <returns>动画执行一个周期的总时间(秒)。</returns>
public float GetAnimationCycleDuration()
{
if (FPS < 0.01)
{
return 1;
}
float ownDuration = 0f;
// 计算当前节点自身的动画周期时间
// 由于 Init 方法已经处理了 FPS 的校验FPS 保证大于 0
if (textures.Count > 0)
{
ownDuration = textures.Count / FPS;
}
// 递归计算所有子节点的动画周期,并取其中最长的
float maxChildDuration = 0f;
foreach (var childNode in nodes)
{
float childDuration = childNode.GetAnimationCycleDuration();
maxChildDuration = Math.Max(maxChildDuration, childDuration);
}
// 整个 DrawNodeDef 的动画周期是自身动画周期和所有子动画周期中的最大值
return Math.Max(ownDuration, maxChildDuration);
}
}
2025-07-14 15:00:56 +08:00
}