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 textures = new(); public List 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; } /// /// 计算动画执行一个周期的总时间(包括子对象)。 /// 如果自身没有纹理,自身动画时间为0。 /// 总周期取自身动画时间和所有子动画周期中的最大值。 /// /// 动画执行一个周期的总时间(秒)。 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); } } }