(client) feat:实现技能树界面,实现地图生成器,实现维度指定,实现规则瓦片定义,实现逃跑逻辑,实现消息定义,实现武器动画,实现受击动画 fix: 修复单攻击子弹击中多个目标,修复人物属性计算错误 (#56)

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/56
This commit is contained in:
2025-09-19 08:26:54 +08:00
parent 78849e0cc5
commit 87a8abe86c
282 changed files with 19364 additions and 8824 deletions

View File

@@ -0,0 +1,54 @@
using UnityEngine;
using System;
// 确保你已经通过 Package Manager 或手动导入了 Newtonsoft.Json
using Newtonsoft.Json;
using UnityEngine.Tilemaps;
public class RuleTileInspector : MonoBehaviour
{
[Tooltip("将一个 RuleTile 资产拖拽到这里以检查其内容。")]
public RuleTile ruleTile;
// 使用 ContextMenu 属性在 Inspector 组件右键菜单或齿轮菜单中添加按钮
[ContextMenu("打印 RuleTile 内容 (JSON)")]
private void PrintRuleTileContentAsJson()
{
if (ruleTile == null)
{
Debug.LogWarning("RuleTile 字段未分配,请拖拽一个 RuleTile 资产。", this);
return;
}
// 创建序列化设置
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore, // 忽略 null 值属性,防止 UnassignedReferenceException
ReferenceLoopHandling = ReferenceLoopHandling.Ignore, // 忽略循环引用(作为安全网)
Formatting = Formatting.Indented, // 格式化输出,可读性更好
// 应用自定义的 ContractResolver 来处理 Unity 值类型属性
ContractResolver = new UnityPropertyContractResolver(),
// 应用自定义的 Converter 来处理 UnityEngine.Object 引用类型
Converters = { new UnityObjectConverter() }
};
try
{
// 序列化 ruleTile.m_TilingRules 列表
string json = JsonConvert.SerializeObject(ruleTile.m_TilingRules, settings);
Debug.Log("Serialized RuleTile Tiling Rules:\n" + json);
}
catch (JsonSerializationException ex)
{
Debug.LogError($"JSON Serialization Error: {ex.Message}\nPath: {ex.Path}\nStackTrace: {ex.StackTrace}");
if (ex.InnerException != null)
{
Debug.LogError(
$"Inner Exception: {ex.InnerException.Message}\nInner StackTrace: {ex.InnerException.StackTrace}");
}
}
catch (Exception ex)
{
Debug.LogError($"Unexpected Error during serialization: {ex.Message}\nStackTrace: {ex.StackTrace}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e12bac1ea0ab44e79a24cdb1101397aa
timeCreated: 1758009087

View File

@@ -0,0 +1,33 @@
using System;
using Data;
using Managers;
using UnityEngine;
namespace Test
{
public class TempAnimationTest:MonoBehaviour
{
public string testMessage="测试消息";
public PromptDisplayCategory displayCategory;
public Color messsageColor = Color.white;
private void Start()
{
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
TemporaryAnimationManager.Instance.GenerateTemporaryAnimation("1,2,3,4,5,1,2,3,4,5",
Camera.main.ScreenToWorldPoint(Input.mousePosition));
}
if (Input.GetMouseButtonDown(1))
{
MessageManager.Instance.DisplayMessage(testMessage,displayCategory,messsageColor);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7a743a0b262a45d8bb1203e776cbbe00
timeCreated: 1757066158

View File

@@ -0,0 +1,100 @@
using System;
using System.Threading.Tasks;
using Managers;
using UI;
using UnityEngine;
using Map;
namespace Test
{
public class TestInit : MonoBehaviour
{
public SkillTreeUI skillTreePageUI;
private Task _currentMapGenerationTask = Task.CompletedTask; // 初始化为已完成任务
private readonly object _mapGenerationLock = new object();
public MapGenerator mapGenerator;
private void Start()
{
Reload();
mapGenerator = Program.Instance.FocusedDimension?.mapGenerator;
}
public async void Reload() // Make Reload async to await the previous task
{
// 在清理之前,等待任何正在进行的地图生成任务完成
// 注意:这会使 Reload() 异步,并且在等待期间 UI 可能会被阻塞,
// 或者如果你不await后续代码可能在任务完成前执行。
Task oldMapTask;
lock (_mapGenerationLock)
{
oldMapTask = _currentMapGenerationTask;
}
if (!oldMapTask.IsCompleted)
{
Debug.Log("TestInit: 等待之前的地图生成任务完成,然后再进行清理和新生成...");
try
{
await oldMapTask; // 等待之前的任务完成
}
catch (Exception ex)
{
Debug.LogWarning($"TestInit: 之前的地图生成任务在等待时失败: {ex.Message}");
// 可以选择忽略或者重新抛出
}
}
mapGenerator?.Clear();
// --- 清理和初始化阶段 ---
DefineManager.Instance.Clear();
PackagesImageManager.Instance.Clear();
TileManager.Instance.Clear();
DefineManager.Instance.Init();
PackagesImageManager.Instance.Init();
TileManager.Instance.Init();
// --- 清理和初始化阶段结束 ---
// 启动新的地图生成任务
StartNewMapGeneration(); // 这是一个非 async 的包装方法
}
/// <summary>
/// 启动新的地图生成任务,并更新 _currentMapGenerationTask。
/// </summary>
private void StartNewMapGeneration()
{
lock (_mapGenerationLock)
{
_currentMapGenerationTask = InitializeMapGenerationAsync();
}
}
/// <summary>
/// 异步初始化并应用所有地图生成器。
/// </summary>
private async Task InitializeMapGenerationAsync()
{
try
{
// 异步应用地图生成器,并且按顺序等待它们完成
await TileManager.Instance.ApplyMapGenerator("DefaultMapGenerator");
// await TileManager.Instance.ApplyMapGenerator("WaterMapGenerator");
await TileManager.Instance.ApplyMapGenerator("TreeGenerator");
Debug.Log("TestInit: 所有地图生成器已成功应用并完成。");
}
catch (OperationCanceledException)
{
Debug.LogWarning("TestInit: 地图生成任务被取消。");
}
catch (Exception ex)
{
Debug.LogError($"TestInit: 在地图生成过程中发生未处理的错误: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d9f93d1858fb4a46b362523ed93ddd4e
timeCreated: 1757851653

View File

@@ -0,0 +1,116 @@
using UnityEngine;
using System;
using System.Reflection;
// 确保你已经通过 Package Manager 或手动导入了 Newtonsoft.Json
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Object = UnityEngine.Object; // 用于自定义序列化,可选但推荐
public class UnityObjectConverter : JsonConverter<Object>
{
public override void WriteJson(JsonWriter writer, Object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
}
else
{
// 对于 Unity 对象,最简单的序列化方式是它们的名称。
// 也可以选择序列化 InstanceID 或 Asset Path (在编辑器环境下)。
writer.WriteValue(value.name);
// 如果你需要 Asset Path (仅在 Unity 编辑器中可用)
// #if UNITY_EDITOR
// string path = UnityEditor.AssetDatabase.GetAssetPath(value);
// writer.WriteValue(path);
// #else
// writer.WriteValue(value.name);
// #endif
}
}
public override Object ReadJson(JsonReader reader, Type objectType, Object existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
string objectIdentifier = reader.Value?.ToString();
if (string.IsNullOrEmpty(objectIdentifier))
{
return null;
}
// 示例反序列化:尝试从 Resources 文件夹加载同名对象
// 这需要你的对象位于 "Resources/" 路径下
// 并且 objectType 必须是正确的目标类型 (如 Sprite, GameObject等)
return Resources.Load(objectIdentifier, objectType);
// 如果你的对象不是通过 Resources 加载的,你可能需要自定义查找逻辑
// 例如:
// if (objectType == typeof(Sprite))
// {
// // 假设你有一个方法可以根据名称找到 Sprite Asset
// return MyAssetManager.LoadSpriteByName(objectIdentifier);
// }
// return null;
}
}
public class UnityPropertyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
// --- 1. 处理 Unity 数学结构体及其循环引用问题 ---
// Vector3, Vector2, Bounds, Rect 都是 struct但它们的某些属性返回新实例导致 JsonConvert 误判循环。
if (member.DeclaringType == typeof(Vector3) || member.DeclaringType == typeof(Vector2))
{
// 明确忽略 normalized, magnitude, sqrMagnitude 等计算属性
if (member.Name == "normalized" || member.Name == "magnitude" || member.Name == "sqrMagnitude")
{
property.ShouldSerialize = instance => false;
}
}
else if (member.DeclaringType == typeof(Bounds))
{
// Bounds 结构体在内部引用 Vector3也可能有一些我们不希望序列化的计算属性
// 例如min/max 可以通过 center 和 extents 计算得出,通常不需单独序列化
if (member.Name == "min" || member.Name == "max")
{
property.ShouldSerialize = instance => false;
}
}
else if (member.DeclaringType == typeof(Rect))
{
// Rect 也有一些计算属性,如果不需要可以忽略
// 例如xMax, yMax, center, position, size
if (member.Name.EndsWith("Max") || member.Name == "center" || member.Name == "position" || member.Name == "size")
{
property.ShouldSerialize = instance => false;
}
}
// --- 2. 处理 UnityEditor 命名空间中的类型 (在运行时通常不序列化) ---
// 这些通常是编辑器专属数据,不应包含在运行时序列化中。
if (property.DeclaringType != null && property.DeclaringType.Namespace != null && property.DeclaringType.Namespace.StartsWith("UnityEditor"))
{
property.ShouldSerialize = instance => false;
}
// --- 3. 处理 Unity.Mathematics 命名空间中的类型 (如果有使用 DOTS/Job System) ---
// 尽管 Unity.Mathematics 类型通常没有循环引用,但如果你只想序列化原始字段,可以这样做。
// if (property.DeclaringType != null && property.DeclaringType.Namespace != null && property.DeclaringType.Namespace.StartsWith("Unity.Mathematics"))
// { /* ... */ }
// --- 4. 确保 Unity Object 引用由专门的 Converter 处理,而不是默认序列化器 ---
// 虽然我们已经提供了 UnityObjectConverter但这一步可以作为补充。
// 如果某个属性的类型是 UnityEngine.Object 或其派生,但又没有显式地被 Converter 捕获
// 我们可以禁用其默认序列化,以避免尝试序列化内部数据。
// 但由于我们注册了 UnityObjectConverter它应该会优先处理。
// 这一部分通常是多余的,除非你的 Converter 只能处理特定的 Unity Object 类型 (例如只处理 Sprite)。
/*
if (typeof(Object).IsAssignableFrom(property.PropertyType) && !property.PropertyType.IsPrimitive && !property.PropertyType.IsEnum)
{
// 除非你有一个针对特定 Unity Object 类型的自定义转换器,否则通常不应该直接序列化它们。
// 这里我们假设 UnityObjectConverter 会处理所有 Object 类型。
// 如果你有特定的 Object 类型需要排除,可以在这里添加逻辑。
}
*/
return property;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9293ba2273e64c27af650873933707c8
timeCreated: 1758011099