mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 08:57:13 +08:00
(client) feat:支持定义实体的碰撞体大小和偏移;建筑支持定义实体建筑和瓦片建筑,建筑支持指定按钮回调;添加存档管理器;Dev支持设置是否暂停;实体允许定义事件组;添加基地界面 (#57)
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/57
This commit is contained in:
@@ -22,7 +22,7 @@ namespace Data
|
||||
var nodes = xmlDef.Elements("Node");
|
||||
var xElements = nodes as XElement[] ?? nodes.ToArray();
|
||||
if (!xElements.Any())
|
||||
return true; // 没有子节点也是有效的
|
||||
return false;
|
||||
|
||||
List<BehaviorTreeDef> children = new();
|
||||
foreach (var node in xElements)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Data
|
||||
{
|
||||
public enum BuildingType
|
||||
@@ -7,8 +9,12 @@ namespace Data
|
||||
}
|
||||
public class BuildingDef : EntityDef
|
||||
{
|
||||
BuildingType buildingType=BuildingType.Static;
|
||||
public BuildingType buildingType=BuildingType.Static;
|
||||
public float slowDown = 0f;
|
||||
public TileDef tile;
|
||||
public KeyCode activateKey = KeyCode.F;
|
||||
public float detectionRadius = 3;
|
||||
public string triggerPosition;
|
||||
public EventDef[] triggerEvents;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -20,6 +18,7 @@ namespace Data
|
||||
Walking,
|
||||
MeleeAttack,
|
||||
RangedAttack,
|
||||
Death,
|
||||
}
|
||||
|
||||
public class DrawingOrderDef : Define
|
||||
@@ -43,6 +42,11 @@ namespace Data
|
||||
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)
|
||||
@@ -218,6 +222,16 @@ namespace Data
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -238,29 +252,42 @@ namespace Data
|
||||
base.Init(xmlDef);
|
||||
|
||||
nodeName = xmlDef.Attribute("name")?.Value ?? "noName";
|
||||
position = StringToVector(xmlDef.Attribute("position")?.Value ?? "(0 0)");
|
||||
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;
|
||||
}
|
||||
public Vector2 StringToVector(string vectorDef)
|
||||
|
||||
/// <summary>
|
||||
/// 获取播放一遍动画所需的最小时间(取当前节点动画与所有子集动画的最大值)。
|
||||
/// </summary>
|
||||
/// <returns>播放一遍动画所需的最小时间(秒),如果无动画则为0。</returns>
|
||||
public float GetMinAnimationDuration()
|
||||
{
|
||||
// 去掉可能存在的括号和多余的空格
|
||||
var cleanedInput = vectorDef.Replace("(", "").Replace(")", "").Trim();
|
||||
|
||||
// 使用正则表达式匹配两个浮点数
|
||||
var match = Regex.Match(cleanedInput, @"\s*(-?\d+(\.\d*)?)\s*[, ]\s*(-?\d+(\.\d*)?)\s*");
|
||||
|
||||
if (match.Success)
|
||||
var maxDuration = 0f;
|
||||
// 计算当前节点自身的动画时间
|
||||
if (textures != null && textures.Length > 0)
|
||||
{
|
||||
// 提取匹配到的两个浮点数
|
||||
var x = float.Parse(match.Groups[1].Value);
|
||||
var y = float.Parse(match.Groups[3].Value);
|
||||
|
||||
// 返回 Vector2 对象
|
||||
return new Vector2(x, y);
|
||||
// 只有当FPS大于0时,才计算有效的动画时间。
|
||||
// 如果FPS <= 0,表示该部分动画无法播放,其时长贡献为0,不参与最大值计算。
|
||||
if (FPS > 0)
|
||||
{
|
||||
maxDuration = Math.Max(maxDuration, textures.Length / FPS);
|
||||
}
|
||||
}
|
||||
|
||||
return Vector2.zero;
|
||||
// 递归计算子节点的动画时间,并更新最大值
|
||||
if (nodes != null && nodes.Length > 0)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
maxDuration = Math.Max(maxDuration, node.GetMinAnimationDuration());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxDuration;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ namespace Data
|
||||
public BehaviorTreeDef behaviorTree;
|
||||
public AffiliationDef affiliation;
|
||||
|
||||
public DrawNodeDef deathAnimation;
|
||||
public EventDef[] deathEffects;
|
||||
public EntityEventDef eventDef;
|
||||
|
||||
public string colliderSize;
|
||||
public string colliderPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
161
Client/Assets/Scripts/Data/EntityEventDef.cs
Normal file
161
Client/Assets/Scripts/Data/EntityEventDef.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Linq; // 用于 LINQ 查询
|
||||
|
||||
namespace Data
|
||||
{
|
||||
public class ConditionalEvent : Define
|
||||
{
|
||||
public string parameter;
|
||||
public EventDef[] eventDefs;
|
||||
}
|
||||
// 实体事件类型枚举
|
||||
public enum EntityEventType
|
||||
{
|
||||
None = 0,
|
||||
OnSpawn,
|
||||
OnMoveForward,
|
||||
OnMoveBackward,
|
||||
OnMoveLeft,
|
||||
OnMoveRight,
|
||||
OnMeleeAttack,
|
||||
OnRangedAttack,
|
||||
OnHit,
|
||||
OnDeath,
|
||||
}
|
||||
|
||||
public class EntityEventDef : Define
|
||||
{
|
||||
public EventDef[] onSpawnEvents; // 生成时触发的事件
|
||||
public EventDef[] onMoveForwardEvents; // 向前移动时触发的事件
|
||||
public EventDef[] onMoveBackwardEvents; // 向后移动时触发的事件
|
||||
public EventDef[] onMoveLeftEvents; // 向左移动时触发的事件
|
||||
public EventDef[] onMoveRightEvents; // 向右移动时触发的事件
|
||||
public EventDef[] onMeleeAttackEvents; // 近战攻击时触发的事件
|
||||
public EventDef[] onRangedAttackEvents; // 远程攻击时触发的事件
|
||||
public EventDef[] onHitEvents; // 受击时触发的事件
|
||||
public EventDef[] onDeathEvents; // 死亡时触发的事件
|
||||
|
||||
public ConditionalEvent[] conditionalEvents; // 由和行为树相同的条件回调
|
||||
|
||||
// =============== 查询函数 ===============
|
||||
|
||||
/// <summary>
|
||||
/// 获取特定事件类型下的所有事件定义。
|
||||
/// </summary>
|
||||
/// <param name="eventType">要查询的实体事件类型。</param>
|
||||
/// <returns>对应事件类型下的 EventDef 数组,如果不存在则返回空数组或 null (取决于设计)。</returns>
|
||||
public EventDef[] GetEventsByType(EntityEventType eventType)
|
||||
{
|
||||
switch (eventType)
|
||||
{
|
||||
case EntityEventType.OnSpawn:
|
||||
return onSpawnEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnMoveForward:
|
||||
return onMoveForwardEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnMoveBackward:
|
||||
return onMoveBackwardEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnMoveLeft:
|
||||
return onMoveLeftEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnMoveRight:
|
||||
return onMoveRightEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnMeleeAttack:
|
||||
return onMeleeAttackEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnRangedAttack:
|
||||
return onRangedAttackEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnHit:
|
||||
return onHitEvents ?? Array.Empty<EventDef>();
|
||||
case EntityEventType.OnDeath:
|
||||
return onDeathEvents ?? Array.Empty<EventDef>();
|
||||
default:
|
||||
return Array.Empty<EventDef>(); // 或者抛出异常,或者返回 null
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有条件事件定义。
|
||||
/// </summary>
|
||||
/// <returns>ConditionalEvent 数组,如果不存在则返回空数组。</returns>
|
||||
public ConditionalEvent[] GetAllConditionalEvents()
|
||||
{
|
||||
return conditionalEvents ?? Array.Empty<ConditionalEvent>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据条件参数获取特定的 ConditionalEvent。
|
||||
/// </summary>
|
||||
/// <param name="parameterName">条件参数的字符串名称。</param>
|
||||
/// <returns>匹配的 ConditionalEvent,如果未找到则返回 null。</returns>
|
||||
public ConditionalEvent GetConditionalEventByParameter(string parameterName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(parameterName) || conditionalEvents == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return conditionalEvents.FirstOrDefault(ce => ce.parameter == parameterName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询所有事件中(包括通用和条件事件)是否存在特定 EventId 的事件。
|
||||
/// 这个查询可能比较耗时,取决于事件数量。
|
||||
/// </summary>
|
||||
/// <param name="eventId">要查询的 EventDef 的 EventId。</param>
|
||||
/// <returns>如果找到,则返回第一个匹配的 EventDef,否则返回 null。</returns>
|
||||
public EventDef FindEventDefById(string eventId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(eventId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查询通用事件
|
||||
foreach (EntityEventType type in Enum.GetValues(typeof(EntityEventType)))
|
||||
{
|
||||
if (type == EntityEventType.None) continue; // 排除 None 类型
|
||||
var events = GetEventsByType(type);
|
||||
if (events != null)
|
||||
{
|
||||
var foundEvent = events.Where(e => e != null).FirstOrDefault(e => e.defName == eventId);
|
||||
if (foundEvent != null)
|
||||
{
|
||||
return foundEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询条件事件
|
||||
if (conditionalEvents != null)
|
||||
{
|
||||
foreach (var condEvent in conditionalEvents)
|
||||
{
|
||||
if (condEvent?.eventDefs != null)
|
||||
{
|
||||
var foundEvent = condEvent.eventDefs.Where(e => e != null).FirstOrDefault(e => e.defName == eventId);
|
||||
if (foundEvent != null)
|
||||
{
|
||||
return foundEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取属于特定事件类型下,并且描述包含特定关键字的所有事件。
|
||||
/// </summary>
|
||||
/// <param name="eventType">要查询的事件类型。</param>
|
||||
/// <param name="keyword">描述中需要包含的关键字。</param>
|
||||
/// <returns>匹配的 EventDef 数组。</returns>
|
||||
public EventDef[] GetEventsByTypeAndDescriptionKeyword(EntityEventType eventType, string keyword)
|
||||
{
|
||||
var events = GetEventsByType(eventType);
|
||||
if (events == null || string.IsNullOrEmpty(keyword))
|
||||
{
|
||||
return Array.Empty<EventDef>();
|
||||
}
|
||||
|
||||
return events.Where(e => e is { description: not null } && e.description.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Client/Assets/Scripts/Data/EntityEventDef.cs.meta
Normal file
3
Client/Assets/Scripts/Data/EntityEventDef.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 687cf248c62442969c245bf0ed7bdc98
|
||||
timeCreated: 1758594469
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
@@ -9,9 +8,15 @@ namespace Data
|
||||
{
|
||||
public Tile.ColliderType collider = Tile.ColliderType.None;
|
||||
public string texture;
|
||||
public float tileCost = 0;
|
||||
public RuleTileRuleDef[] rules;
|
||||
}
|
||||
|
||||
|
||||
public class NeighborConditionDef:Define
|
||||
{
|
||||
public string position;
|
||||
public RuleTileRuleDef.NeighborConditionType Type;
|
||||
}
|
||||
public class RuleTileRuleDef : Define
|
||||
{
|
||||
public enum NeighborConditionType
|
||||
@@ -22,6 +27,7 @@ namespace Data
|
||||
}
|
||||
|
||||
public NeighborConditionType[] neighborConditions = new NeighborConditionType[8];
|
||||
public NeighborConditionDef[] neighborConditionExtend;
|
||||
|
||||
public RuleTile.TilingRuleOutput.OutputSprite outputType = RuleTile.TilingRuleOutput.OutputSprite.Single;
|
||||
public RuleTile.TilingRuleOutput.Transform transform = RuleTile.TilingRuleOutput.Transform.Fixed;
|
||||
@@ -38,6 +44,7 @@ namespace Data
|
||||
// 如果 outputType 是 Animation,这里可以定义一系列动画帧的纹理路径或名称
|
||||
public List<string> animationTextures;
|
||||
public float animationSpeed = 1f;
|
||||
public float tileCost = 0;
|
||||
|
||||
// 构造函数或其他辅助方法
|
||||
public RuleTileRuleDef()
|
||||
Reference in New Issue
Block a user