(client) feat:实现热重载,实现多维度,实现武器,实现掉落物,实现状态UI,实现攻击AI (#44)
Co-authored-by: zzdxxz <2079238449@qq.com> Co-committed-by: zzdxxz <2079238449@qq.com>
This commit is contained in:
@ -14,84 +14,221 @@ namespace Data
|
||||
Up
|
||||
}
|
||||
|
||||
public enum DrawNodeType
|
||||
public enum EntityState
|
||||
{
|
||||
Image,
|
||||
Animation
|
||||
Idle,
|
||||
Walking,
|
||||
MeleeAttack,
|
||||
RangedAttack,
|
||||
}
|
||||
|
||||
public class DrawingOrderDef : Define
|
||||
{
|
||||
public DrawNodeDef drawingOrder_down;
|
||||
public DrawNodeDef drawingOrder_up;
|
||||
public DrawNodeDef drawingOrder_left;
|
||||
public DrawNodeDef drawingOrder_right;
|
||||
public string texturePath;
|
||||
public float pixelsPerUnit = 16;
|
||||
|
||||
public DrawNodeDef GetDrawingOrder(Orientation orientation, out Orientation sourceOrientation)
|
||||
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)
|
||||
{
|
||||
// 定义一个临时变量用于存储结果
|
||||
DrawNodeDef result = null;
|
||||
fallbackOrientation = null;
|
||||
|
||||
// 初始化 sourceOrientation 为默认值
|
||||
sourceOrientation = Orientation.Down;
|
||||
// 根据状态和方向获取对应的DrawNodeDef
|
||||
var result = GetDrawNodeDefInternal(state, orientation);
|
||||
|
||||
// 根据传入的 Orientation 获取对应的 DrawingOrderDef
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// 如果找不到,按照规则查找替补
|
||||
switch (orientation)
|
||||
{
|
||||
case Orientation.Down:
|
||||
result = drawingOrder_down;
|
||||
sourceOrientation = Orientation.Down;
|
||||
break;
|
||||
case Orientation.Up:
|
||||
result = drawingOrder_up;
|
||||
sourceOrientation = 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 = drawingOrder_left;
|
||||
sourceOrientation = 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 = drawingOrder_right;
|
||||
sourceOrientation = 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 ArgumentException("Invalid orientation value.");
|
||||
throw new ArgumentOutOfRangeException(nameof(orientation), orientation, null);
|
||||
}
|
||||
|
||||
// 如果当前方向的结果为空,则尝试用 drawingOrder_down 填充
|
||||
if (result == null)
|
||||
// 如果所有替补都找不到,返回null
|
||||
return null;
|
||||
}
|
||||
|
||||
private DrawNodeDef GetDrawNodeDefInternal(EntityState state, Orientation orientation)
|
||||
{
|
||||
// 根据状态和方向获取对应的DrawNodeDef
|
||||
switch (state)
|
||||
{
|
||||
result = drawingOrder_down;
|
||||
sourceOrientation = Orientation.Down; // 更新 sourceOrientation
|
||||
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;
|
||||
}
|
||||
|
||||
// 如果 drawingOrder_down 仍然为空,则尝试用其他非空方向填充
|
||||
if (result != null) return result;
|
||||
if (drawingOrder_up != null)
|
||||
{
|
||||
result = drawingOrder_up;
|
||||
sourceOrientation = Orientation.Up; // 更新 sourceOrientation
|
||||
}
|
||||
else if (drawingOrder_left != null)
|
||||
{
|
||||
result = drawingOrder_left;
|
||||
sourceOrientation = Orientation.Left; // 更新 sourceOrientation
|
||||
}
|
||||
else if (drawingOrder_right != null)
|
||||
{
|
||||
result = drawingOrder_right;
|
||||
sourceOrientation = Orientation.Right; // 更新 sourceOrientation
|
||||
}
|
||||
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class DrawNodeDef : Define
|
||||
{
|
||||
public List<DrawNodeDef> children = new();
|
||||
public DrawNodeType drawNodeType = DrawNodeType.Image;
|
||||
public List<string> textures = new();
|
||||
public List<DrawNodeDef> nodes = new();
|
||||
public string nodeName;
|
||||
public Vector2 position = new(0, 0);
|
||||
public float FPS = 0.5f;
|
||||
@ -101,19 +238,9 @@ namespace Data
|
||||
base.Init(xmlDef);
|
||||
|
||||
nodeName = xmlDef.Attribute("name")?.Value??"noName";
|
||||
drawNodeType = Enum.TryParse(xmlDef.Attribute("type")?.Value, true, out DrawNodeType typeResult)
|
||||
? typeResult
|
||||
: DrawNodeType.Image;
|
||||
|
||||
position = StringToVector(xmlDef.Attribute("position")?.Value ?? "(0 0)");
|
||||
FPS = float.TryParse(xmlDef.Attribute("FPS")?.Value, out float result) ? result : 1.0f;
|
||||
foreach (var childNode in xmlDef.Elements())
|
||||
{
|
||||
var child = new DrawNodeDef();
|
||||
child.Init(childNode);
|
||||
children.Add(child);
|
||||
}
|
||||
return true;
|
||||
FPS = float.TryParse(xmlDef.Attribute("FPS")?.Value, out var result) ? result : 1.0f;
|
||||
return false;
|
||||
}
|
||||
public Vector2 StringToVector(string vectorDef)
|
||||
{
|
||||
@ -132,34 +259,37 @@ namespace Data
|
||||
// 返回 Vector2 对象
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Vector2.zero;
|
||||
}
|
||||
}
|
||||
|
||||
// 判断两个 DrawNodeDef 是否相等
|
||||
public static bool AreEqual(DrawNodeDef a, DrawNodeDef b)
|
||||
{
|
||||
if (ReferenceEquals(a, b)) return true; // 如果是同一个对象,直接返回 true
|
||||
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false; // 如果其中一个为 null,返回 false
|
||||
// 比较基本属性
|
||||
if (a.drawNodeType != b.drawNodeType ||
|
||||
a.nodeName != b.nodeName ||
|
||||
a.position != b.position ||
|
||||
Math.Abs(a.FPS - b.FPS) > 0.001f) // 浮点数比较需要考虑精度
|
||||
return false;
|
||||
// 比较 children 的数量
|
||||
if (a.children.Count != b.children.Count)
|
||||
return false;
|
||||
// 递归比较每个子节点
|
||||
for (var i = 0; i < a.children.Count; i++)
|
||||
{
|
||||
if (!AreEqual(a.children[i], b.children[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user