using System; using System.Xml.Linq; using UnityEngine; namespace Data { public enum Orientation { Down, Left, Right, Up } public enum EntityState { Idle, Walking, MeleeAttack, RangedAttack, Death, } 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 death_down; public DrawNodeDef death_up; public DrawNodeDef death_left; public DrawNodeDef death_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; case EntityState.Death: switch (orientation) { case Orientation.Down: return death_down; case Orientation.Up: return death_up; case Orientation.Left: return death_left; case Orientation.Right: return death_right; } break; } return null; } } public class DrawNodeDef : Define { public string[] textures; public DrawNodeDef[] nodes; public string nodeName; public Vector2 position = new(0, 0); public float FPS = 5f; public override bool Init(XElement xmlDef) { base.Init(xmlDef); nodeName = xmlDef.Attribute("name")?.Value ?? "noName"; position = Utils.StringUtils.StringToVector2(xmlDef.Attribute("position")?.Value ?? "0,0"); FPS = float.TryParse(xmlDef.Attribute("FPS")?.Value, out var result) ? result : 5.0f; return false; } /// /// 获取播放一遍动画所需的最小时间(取当前节点动画与所有子集动画的最大值)。 /// /// 播放一遍动画所需的最小时间(秒),如果无动画则为0。 public float GetMinAnimationDuration() { var maxDuration = 0f; // 计算当前节点自身的动画时间 if (textures != null && textures.Length > 0) { // 只有当FPS大于0时,才计算有效的动画时间。 // 如果FPS <= 0,表示该部分动画无法播放,其时长贡献为0,不参与最大值计算。 if (FPS > 0) { maxDuration = Math.Max(maxDuration, textures.Length / FPS); } } // 递归计算子节点的动画时间,并更新最大值 if (nodes != null && nodes.Length > 0) { foreach (var node in nodes) { if (node != null) { maxDuration = Math.Max(maxDuration, node.GetMinAnimationDuration()); } } } return maxDuration; } } }