mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 01:17:12 +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:
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Data;
|
||||
using Prefab;
|
||||
using UnityEngine;
|
||||
@@ -9,31 +8,43 @@ namespace Utils
|
||||
{
|
||||
public class GameObjectCreate:Singleton<GameObjectCreate>
|
||||
{
|
||||
private SpriteAnimator _animatorPrefab;
|
||||
public SpriteAnimator AnimatorPrefab
|
||||
private static SpriteAnimator _animatorPrefab;
|
||||
public static SpriteAnimator AnimatorPrefab
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_animatorPrefab == null)
|
||||
if (!_animatorPrefab)
|
||||
{
|
||||
_animatorPrefab=Resources.Load<SpriteAnimator>("Prefab/Animation");
|
||||
_animatorPrefab=Resources.Load<SpriteAnimator>("Prefab/ControlUI/Animation");
|
||||
}
|
||||
return _animatorPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
private ImagePrefab _imagePrefab;
|
||||
public ImagePrefab ImagePrefab
|
||||
private static ImagePrefab _imagePrefab;
|
||||
public static ImagePrefab ImagePrefab
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_imagePrefab == null)
|
||||
if (!_imagePrefab)
|
||||
{
|
||||
_imagePrefab=Resources.Load<ImagePrefab>("Prefab/Image");
|
||||
_imagePrefab=Resources.Load<ImagePrefab>("Prefab/ControlUI/Image");
|
||||
}
|
||||
return _imagePrefab;
|
||||
}
|
||||
}
|
||||
private static ProgressBarPrefab _progressBarPrefab;
|
||||
public static ProgressBarPrefab ProgressBarPrefab
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_progressBarPrefab)
|
||||
{
|
||||
_progressBarPrefab=Resources.Load<ProgressBarPrefab>("Prefab/ControlUI/ProgressBar");
|
||||
}
|
||||
return _progressBarPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -70,7 +81,7 @@ namespace Utils
|
||||
break;
|
||||
case 1:
|
||||
// 单纹理节点
|
||||
if (!Instance.ImagePrefab)
|
||||
if (!ImagePrefab)
|
||||
{
|
||||
Debug.LogError($"InitBodyPart: imagePrefab未设置 (节点名: {drawNode.nodeName})");
|
||||
return null;
|
||||
@@ -85,7 +96,7 @@ namespace Utils
|
||||
$"InitBodyPart: 无法获取纹理 (节点名: {drawNode.nodeName}, 纹理ID: {drawNode.textures[0]})");
|
||||
}
|
||||
|
||||
var imagePrefabCom = Object.Instantiate(Instance.ImagePrefab, parent.transform);
|
||||
var imagePrefabCom = Object.Instantiate(ImagePrefab, parent.transform);
|
||||
if (imagePrefabCom)
|
||||
{
|
||||
imagePrefabCom.SetSprite(texture);
|
||||
@@ -100,13 +111,13 @@ namespace Utils
|
||||
break;
|
||||
default:
|
||||
// 多纹理动画节点
|
||||
if (!Instance.AnimatorPrefab)
|
||||
if (!AnimatorPrefab)
|
||||
{
|
||||
Debug.LogError($"InitBodyPart: animatorPrefab未设置 (节点名: {drawNode.nodeName})");
|
||||
return null;
|
||||
}
|
||||
|
||||
var animator = Object.Instantiate(Instance.AnimatorPrefab, parent.transform);
|
||||
var animator = Object.Instantiate(AnimatorPrefab, parent.transform);
|
||||
if (!animator)
|
||||
{
|
||||
Debug.LogWarning($"InitBodyPart: 无法获取SpriteAnimator组件 (节点名: {drawNode.nodeName})");
|
||||
@@ -162,7 +173,7 @@ namespace Utils
|
||||
|
||||
public static SpriteAnimator SpriteAnimator(Sprite[] sprites,Transform parent)
|
||||
{
|
||||
var spriteAnimator = Object.Instantiate(Instance.AnimatorPrefab,parent);
|
||||
var spriteAnimator = Object.Instantiate(AnimatorPrefab,parent);
|
||||
spriteAnimator.SetSprites(sprites);
|
||||
spriteAnimator.transform.localPosition=Vector3.zero;
|
||||
return spriteAnimator;
|
||||
@@ -175,7 +186,7 @@ namespace Utils
|
||||
|
||||
public static ImagePrefab SpriteImage(Sprite sprite, Transform parent)
|
||||
{
|
||||
var spriteImage = Object.Instantiate(Instance.ImagePrefab,parent);
|
||||
var spriteImage = Object.Instantiate(ImagePrefab,parent);
|
||||
spriteImage.SetSprite(sprite);
|
||||
spriteImage.transform.localPosition=Vector3.zero;
|
||||
return spriteImage;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// 文件: Assets/Scripts/Utils/StringUtils.cs (或你的实际路径)
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using EventWorkClass;
|
||||
using Map;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
using UnityEngine; // 引入Unity命名空间,以便使用Vector2和Vector3
|
||||
|
||||
public static class StringUtils
|
||||
{
|
||||
// 以下是你原始代码中未修改的部分,为了完整性列出
|
||||
/// <summary>
|
||||
/// 尝试从字符串中解析出指定数量的浮点数组件。
|
||||
/// 这是StringToVector2和StringToVector3的核心辅助方法。
|
||||
@@ -26,11 +26,10 @@ namespace Utils
|
||||
float defaultComponentValue = 0f)
|
||||
{
|
||||
parsedComponents = new float[expectedComponentCount];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(source))
|
||||
{
|
||||
// 如果字符串为空或空白,则用默认值填充并失败
|
||||
for (int i = 0; i < expectedComponentCount; i++)
|
||||
for (var i = 0; i < expectedComponentCount; i++)
|
||||
{
|
||||
parsedComponents[i] = defaultComponentValue;
|
||||
}
|
||||
@@ -40,23 +39,21 @@ namespace Utils
|
||||
|
||||
// 移除所有可能存在的括号或方括号
|
||||
// 采用Replace而不是Regex是因为简单字符替换的性能优势
|
||||
string cleanedSource = source
|
||||
var cleanedSource = source
|
||||
.Replace("[", "")
|
||||
.Replace("]", "")
|
||||
.Replace("(", "")
|
||||
.Replace(")", "");
|
||||
|
||||
// 定义所有可能的分隔符:逗号、空格、分号
|
||||
// 使用 StringSplitOptions.RemoveEmptyEntries 确保即使有多个分隔符连续出现,也不会创建空字符串项
|
||||
char[] delimiters = { ',', ' ', ';' };
|
||||
string[] componentStrings = cleanedSource.Split(
|
||||
var componentStrings = cleanedSource.Split(
|
||||
delimiters,
|
||||
System.StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (componentStrings.Length < expectedComponentCount)
|
||||
{
|
||||
// 如果组件数量不足,则用默认值填充并失败
|
||||
for (int i = 0; i < expectedComponentCount; i++)
|
||||
for (var i = 0; i < expectedComponentCount; i++)
|
||||
{
|
||||
parsedComponents[i] = defaultComponentValue;
|
||||
}
|
||||
@@ -64,13 +61,13 @@ namespace Utils
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < expectedComponentCount; i++)
|
||||
for (var i = 0; i < expectedComponentCount; i++)
|
||||
{
|
||||
// 尝试解析每个组件,并去除前后空格
|
||||
if (!float.TryParse(componentStrings[i].Trim(), out parsedComponents[i]))
|
||||
{
|
||||
// 如果任何一个组件解析失败,则用默认值填充所有组件并返回 false
|
||||
for (int j = 0; j < expectedComponentCount; j++)
|
||||
for (var j = 0; j < expectedComponentCount; j++)
|
||||
{
|
||||
parsedComponents[j] = defaultComponentValue;
|
||||
}
|
||||
@@ -128,6 +125,100 @@ namespace Utils
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// 原始代码结束
|
||||
// #region 新增代码
|
||||
/// <summary>
|
||||
/// 尝试从字符串中解析出指定数量的整数组件。
|
||||
/// 这是StringToVector3Int的核心辅助方法。
|
||||
/// </summary>
|
||||
/// <param name="source">要解析的源字符串。</param>
|
||||
/// <param name="expectedComponentCount">期望的组件数量(例如,Vector3Int为3)。</param>
|
||||
/// <param name="parsedComponents">如果解析成功,包含解析出的整数;否则为 null。</param>
|
||||
/// <param name="defaultComponentValue">在解析失败时,用于填充parsedComponents数组的默认值。</param>
|
||||
/// <returns>如果所有组件都成功解析,则返回 true;否则返回 false。</returns>
|
||||
private static bool TryParseVectorIntComponents(
|
||||
string source,
|
||||
int expectedComponentCount,
|
||||
out int[] parsedComponents,
|
||||
int defaultComponentValue = 0)
|
||||
{
|
||||
parsedComponents = new int[expectedComponentCount];
|
||||
if (string.IsNullOrWhiteSpace(source))
|
||||
{
|
||||
// 如果字符串为空或空白,则用默认值填充并失败
|
||||
for (var i = 0; i < expectedComponentCount; i++)
|
||||
{
|
||||
parsedComponents[i] = defaultComponentValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 移除所有可能存在的括号或方括号
|
||||
var cleanedSource = source
|
||||
.Replace("[", "")
|
||||
.Replace("]", "")
|
||||
.Replace("(", "")
|
||||
.Replace(")", "");
|
||||
// 定义所有可能的分隔符:逗号、空格、分号
|
||||
char[] delimiters = { ',', ' ', ';' };
|
||||
var componentStrings = cleanedSource.Split(
|
||||
delimiters,
|
||||
System.StringSplitOptions.RemoveEmptyEntries);
|
||||
if (componentStrings.Length < expectedComponentCount)
|
||||
{
|
||||
// 如果组件数量不足,则用默认值填充并失败
|
||||
for (var i = 0; i < expectedComponentCount; i++)
|
||||
{
|
||||
parsedComponents[i] = defaultComponentValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < expectedComponentCount; i++)
|
||||
{
|
||||
// 尝试解析每个组件,并去除前后空格
|
||||
if (!int.TryParse(componentStrings[i].Trim(), out parsedComponents[i]))
|
||||
{
|
||||
// 如果任何一个组件解析失败,则用默认值填充所有组件并返回 false
|
||||
for (var j = 0; j < expectedComponentCount; j++)
|
||||
{
|
||||
parsedComponents[j] = defaultComponentValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 所有组件都成功解析
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将字符串转换为 Unity 的 Vector3Int。
|
||||
/// 支持格式如 "1,2,3", "[1 2 3]", "(1;2;3)",并能处理空格。
|
||||
/// </summary>
|
||||
/// <param name="str">要转换的字符串。</param>
|
||||
/// <param name="defaultValue">转换失败时返回的默认 Vector3Int 值。</param>
|
||||
/// <returns>转换后的 Vector3Int 值或默认值。</returns>
|
||||
public static Vector3Int StringToVector3Int(string str, Vector3Int defaultValue = default)
|
||||
{
|
||||
// C# 7.1 以上版本允许 'default' 用于值类型,对于引用类型为 null,对于值类型为所有成员的默认值(例如0),
|
||||
// 所以 Vector3Int.zero 可以作为显式默认值。
|
||||
if (defaultValue == default)
|
||||
{
|
||||
defaultValue = Vector3Int.zero; // 如果未指定,则使用 Vector3Int.zero 作为默认值
|
||||
}
|
||||
|
||||
// 默认整数值为0,用于内部解析失败填充
|
||||
if (TryParseVectorIntComponents(str, 3, out var components))
|
||||
{
|
||||
return new Vector3Int(components[0], components[1], components[2]);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类名字符串创建并返回一个继承自 MapGeneratorWorkClassBase 的实例。
|
||||
/// </summary>
|
||||
@@ -139,10 +230,10 @@ namespace Utils
|
||||
const string preferredNamespace = "Map";
|
||||
Type foundType = null;
|
||||
// 第一遍:优先在指定的命名空间下查找
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
string fullClassNameInPreferredNamespace = preferredNamespace + "." + className;
|
||||
Type type = assembly.GetType(fullClassNameInPreferredNamespace);
|
||||
var fullClassNameInPreferredNamespace = preferredNamespace + "." + className;
|
||||
var type = assembly.GetType(fullClassNameInPreferredNamespace);
|
||||
if (type != null)
|
||||
{
|
||||
foundType = type;
|
||||
@@ -153,9 +244,9 @@ namespace Utils
|
||||
// 如果在优先命名空间中没有找到,则进行第二遍:在所有命名空间中查找(不指定命名空间,即只用className)
|
||||
if (foundType == null)
|
||||
{
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
Type type = assembly.GetType(className);
|
||||
var type = assembly.GetType(className);
|
||||
if (type != null)
|
||||
{
|
||||
// 如果找到多个同名的类型(在不同命名空间,但都不在preferredNamespace),
|
||||
@@ -196,7 +287,7 @@ namespace Utils
|
||||
}
|
||||
}
|
||||
|
||||
string foundTypeName = foundType.FullName;
|
||||
var foundTypeName = foundType.FullName;
|
||||
Debug.LogError($"Type '{foundTypeName}' found but does not meet criteria:" +
|
||||
$" IsAssignableFrom({nameof(MapGeneratorWorkClassBase)}): {typeof(MapGeneratorWorkClassBase).IsAssignableFrom(foundType)}," +
|
||||
$" IsAbstract: {foundType.IsAbstract}," +
|
||||
@@ -208,6 +299,71 @@ namespace Utils
|
||||
$"Type '{className}' not found in preferred namespace '{preferredNamespace}' or any loaded assembly.");
|
||||
return null; // 类型未找到
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类名从指定命名空间和程序集下获取并实例化一个 <see cref="EventWorkClassBase"/> 的子类。
|
||||
/// </summary>
|
||||
/// <param name="className">要实例化的类的短名称(不包含命名空间)。</param>
|
||||
/// <param name="targetNamespace">目标类所在的完整命名空间。</param>
|
||||
/// <param name="assemblyToSearch">要搜索的程序集。如果为 null,将搜索 <see cref="EventWorkClassBase"/> 所在的程序集。</param>
|
||||
/// <returns>实例化后的 <see cref="EventWorkClassBase"/> 对象,如果找不到或不符合条件则返回 null。</returns>
|
||||
public static EventWorkClassBase GetAndInstantiateEventWorker(
|
||||
string className,
|
||||
string targetNamespace = "EventWorkClass", // 默认命名空间
|
||||
Assembly assemblyToSearch = null) // 默认程序集
|
||||
{
|
||||
// 1. 确定要搜索的程序集。
|
||||
if (assemblyToSearch == null)
|
||||
{
|
||||
// 默认从 EventWorkClassBase 所在的程序集查找,通常其实现类也位于此程序集。
|
||||
assemblyToSearch = typeof(EventWorkClassBase).Assembly;
|
||||
}
|
||||
|
||||
// 2. 构造完整的类型名称。
|
||||
var fullTypeName = $"{targetNamespace}.{className}";
|
||||
Type targetType = null;
|
||||
|
||||
// 3. 尝试直接从程序集获取类型。
|
||||
targetType = assemblyToSearch.GetType(fullTypeName);
|
||||
|
||||
// 4. 进行类型检查。
|
||||
if (targetType == null)
|
||||
{
|
||||
Debug.LogError($"错误:在程序集 '{assemblyToSearch.FullName}' 的命名空间 '{targetNamespace}' 中未找到类 '{className}'。");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否是 EventWorkClassBase 的子类。
|
||||
if (!typeof(EventWorkClassBase).IsAssignableFrom(targetType))
|
||||
{
|
||||
Debug.LogError($"错误:类 '{fullTypeName}' 不是 '{typeof(EventWorkClassBase).FullName}' 的子类。");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否可以实例化(非抽象类,非接口)。
|
||||
if (targetType.IsAbstract || targetType.IsInterface)
|
||||
{
|
||||
Debug.LogError($"错误:类 '{fullTypeName}' 是抽象类或接口,不能直接实例化。");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 5. 实例化对象。
|
||||
try
|
||||
{
|
||||
// 使用 Activator.CreateInstance 实例化对象。它默认调用无参公共构造函数。
|
||||
var instance = Activator.CreateInstance(targetType);
|
||||
return instance as EventWorkClassBase;
|
||||
}
|
||||
catch (MissingMethodException ex)
|
||||
{
|
||||
Debug.LogError($"错误:类 '{fullTypeName}' 没有公共的无参构造函数。详细信息: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"实例化类 '{fullTypeName}' 时发生未知错误。详细信息: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user