(client) feat:添加事件定义,定义部分怪物
This commit is contained in:
@ -8,8 +8,8 @@ namespace Data
|
||||
public float moveSpeed = 1;
|
||||
public int attack = 1;
|
||||
public int defense = 0;
|
||||
public int attackSpeed = 2;
|
||||
public int attackRange = 3;
|
||||
public float attackSpeed = 2;
|
||||
public float attackRange = 3;
|
||||
public int attackTargetCount = 1;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Data
|
||||
{
|
||||
public class EntityEventDef:Define
|
||||
{
|
||||
public BuildingDef buildingDef;
|
||||
public MonsterDef monster;
|
||||
public CharacterDef character; // 要生成的实体Def的defName
|
||||
public int count = 1; // 生成的数量
|
||||
|
||||
public float minRadius = 0f; // 最小距离(以格数单位)
|
||||
public float maxRadius = 10f; // 最大距离(以格数单位)
|
||||
public int width = 5; // 宽度(以格数单位),指定一个方形区域
|
||||
public int height = 5; // 高度(以格数单位)
|
||||
public bool allowNearWalls = true; // 是否允许靠近墙壁生成
|
||||
public bool allowSpawnOnPawn = false; // 是否允许直接生成在角色身上
|
||||
// 可以添加更多约束,如:
|
||||
public List<string> allowedTerrainTags; // 允许生成的地形标签
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b4cf168bf1e41d4a63e78cb734453bd
|
||||
timeCreated: 1756305435
|
@ -2,8 +2,7 @@ namespace Data
|
||||
{
|
||||
public class EventDef : Define
|
||||
{
|
||||
public HediffEventDef hediffEvent;
|
||||
public EntityEventDef entityEvent;
|
||||
public string workClass;
|
||||
public string value;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Data
|
||||
{
|
||||
public class HediffEventDef:Define
|
||||
{
|
||||
public HediffDef hediff; // 要添加的HediffDef的defName
|
||||
public float hediffSeverity = 1.0f; // 添加时Hediff的严重程度或进度
|
||||
public AffiliationDef affiliation; // 目标的派系DefName
|
||||
public bool forAllPawnsInFaction = false; // 是否为该派系的所有Pawns添加Hediff
|
||||
public int specificPawnCount = 1; // 如果不是所有Pawns,指定数量
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d495178bf0c943fe9da8009592e20400
|
||||
timeCreated: 1756305417
|
47
Client/Assets/Scripts/Data/MessageDef.cs
Normal file
47
Client/Assets/Scripts/Data/MessageDef.cs
Normal file
@ -0,0 +1,47 @@
|
||||
namespace Data
|
||||
{
|
||||
/// <summary>
|
||||
/// 定义提示文本在游戏或应用中显示方式的类别。
|
||||
/// Defines categories for how prompt text is displayed in a game or application.
|
||||
/// </summary>
|
||||
public enum PromptDisplayCategory
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认或未分类的显示方式。
|
||||
/// Default or uncategorized display method.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 显示在玩家当前焦点实体(例如NPC或交互物)上方,以聊天气泡的形式呈现。
|
||||
/// Displayed as a chat bubble above the player's currently focused entity (e.g., NPC, interactive object).
|
||||
/// </summary>
|
||||
FocusedEntityChatBubble,
|
||||
|
||||
/// <summary>
|
||||
/// 显示在玩家当前焦点实体(例如NPC或交互物)的头顶,通常是简短的状态、名称或互动提示。
|
||||
/// Displayed as text above the player's currently focused entity (e.g., NPC, interactive object), typically for short status, names, or interaction prompts.
|
||||
/// </summary>
|
||||
FocusedEntityOverheadText,
|
||||
|
||||
/// <summary>
|
||||
/// 大型文本显示在屏幕中央,通常用于重要通知、标题或剧情提示,需要玩家立即注意。
|
||||
/// Large text displayed in the center of the screen, typically for important announcements, titles, or narrative prompts that demand immediate player attention.
|
||||
/// </summary>
|
||||
ScreenCenterLargeText,
|
||||
|
||||
/// <summary>
|
||||
/// 非焦点提示,通常以不易干扰的方式(如屏幕边缘、HUD小字或右下角浮动)显示,提供辅助信息、次要指引或环境提示。
|
||||
/// Non-focused hint, typically displayed in a non-intrusive way (e.g., screen corner, small HUD text, or bottom-right floating message) to provide auxiliary information, minor guidance, or environmental cues.
|
||||
/// </summary>
|
||||
PassiveHint,
|
||||
|
||||
}
|
||||
|
||||
public class MessageDef : Define
|
||||
{
|
||||
public PromptDisplayCategory type;
|
||||
public string text;
|
||||
public string color;
|
||||
}
|
||||
}
|
3
Client/Assets/Scripts/Data/MessageDef.cs.meta
Normal file
3
Client/Assets/Scripts/Data/MessageDef.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8df8531d3d53412e8c299262aeea6f57
|
||||
timeCreated: 1756860490
|
@ -3,8 +3,9 @@ namespace Data
|
||||
public class StoryStageDef : Define
|
||||
{
|
||||
public float lastWaitTime = 0;
|
||||
public EventDef eventDef;
|
||||
public float nextWaitTime = 0;
|
||||
public EventDef eventDef;
|
||||
public MessageDef messageDef;
|
||||
}
|
||||
public class StoryDef:Define
|
||||
{
|
||||
|
@ -9,8 +9,8 @@ namespace Entity
|
||||
public float moveSpeed = 1;
|
||||
public int attack = 1;
|
||||
public int defense = 0;
|
||||
public int attackSpeed = 2;
|
||||
public int attackRange = 3;
|
||||
public float attackSpeed = 2;
|
||||
public float attackRange = 3;
|
||||
public int attackTargetCount = 1;
|
||||
|
||||
public Attributes(AttributesDef def)
|
||||
@ -60,8 +60,11 @@ namespace Entity
|
||||
newAttributes.moveSpeed += offset.moveSpeedOffset;
|
||||
newAttributes.attack += (int)offset.attackOffset;
|
||||
newAttributes.defense += (int)offset.defenseOffset;
|
||||
newAttributes.attackSpeed += (int)offset.attackSpeedOffset;
|
||||
newAttributes.attackRange += (int)offset.attackRangeOffset;
|
||||
|
||||
// 修正: attackSpeed 和 attackRange 是 float,不应强制转换为 int
|
||||
newAttributes.attackSpeed += offset.attackSpeedOffset;
|
||||
newAttributes.attackRange += offset.attackRangeOffset;
|
||||
|
||||
newAttributes.attackTargetCount += (int)offset.attackTargetCountOffset;
|
||||
|
||||
// 3. 在副本上应用百分比偏移 (基于应用绝对值偏移后的结果)
|
||||
@ -69,8 +72,11 @@ namespace Entity
|
||||
newAttributes.moveSpeed *= (1 + offset.moveSpeedPercentOffset);
|
||||
newAttributes.attack = (int)(newAttributes.attack * (1 + offset.attackPercentOffset));
|
||||
newAttributes.defense = (int)(newAttributes.defense * (1 + offset.defensePercentOffset));
|
||||
newAttributes.attackSpeed = (int)(newAttributes.attackSpeed * (1 + offset.attackSpeedPercentOffset));
|
||||
newAttributes.attackRange = (int)(newAttributes.attackRange * (1 + offset.attackRangePercentOffset));
|
||||
|
||||
// 修正: attackSpeed 和 attackRange 是 float,不应强制转换为 int
|
||||
newAttributes.attackSpeed *= (1 + offset.attackSpeedPercentOffset);
|
||||
newAttributes.attackRange *= (1 + offset.attackRangePercentOffset);
|
||||
|
||||
newAttributes.attackTargetCount =
|
||||
(int)(newAttributes.attackTargetCount * (1 + offset.attackTargetCountPercentOffset));
|
||||
|
||||
@ -79,8 +85,11 @@ namespace Entity
|
||||
newAttributes.moveSpeed = Math.Max(0f, newAttributes.moveSpeed);
|
||||
newAttributes.attack = Math.Max(0, newAttributes.attack);
|
||||
newAttributes.defense = Math.Max(0, newAttributes.defense);
|
||||
newAttributes.attackSpeed = Math.Max(0, newAttributes.attackSpeed);
|
||||
newAttributes.attackRange = Math.Max(0, newAttributes.attackRange);
|
||||
|
||||
// 修正: Math.Max 期望相同类型,0f 对于 float 类型更准确
|
||||
newAttributes.attackSpeed = Math.Max(0f, newAttributes.attackSpeed);
|
||||
newAttributes.attackRange = Math.Max(0f, newAttributes.attackRange);
|
||||
|
||||
newAttributes.attackTargetCount = Math.Max(1, newAttributes.attackTargetCount);
|
||||
|
||||
// 5. 返回修改后的新 Attributes 实例
|
||||
@ -118,4 +127,4 @@ namespace Entity
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
Client/Assets/Scripts/EventWorkClass.meta
Normal file
3
Client/Assets/Scripts/EventWorkClass.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3747df4a5ee84ed5b9d4241f240af67a
|
||||
timeCreated: 1756786716
|
12
Client/Assets/Scripts/EventWorkClass/EventWorkClassBase.cs
Normal file
12
Client/Assets/Scripts/EventWorkClass/EventWorkClassBase.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Base;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EventWorkClass
|
||||
{
|
||||
public abstract class EventWorkClassBase
|
||||
{
|
||||
public abstract void Init(string value);
|
||||
|
||||
public abstract void Run(string dimensionID);
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1258c84f5c82460ead132b62741c0be3
|
||||
timeCreated: 1756786734
|
305
Client/Assets/Scripts/EventWorkClass/Event_EntityGenerater.cs
Normal file
305
Client/Assets/Scripts/EventWorkClass/Event_EntityGenerater.cs
Normal file
@ -0,0 +1,305 @@
|
||||
using System;
|
||||
using Data;
|
||||
using Managers;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace EventWorkClass
|
||||
{
|
||||
/// <summary>
|
||||
/// Event_EntityGenerater 事件的配置数据结构。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EntityGenerateConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 要生成的实体定义名 (defName)。
|
||||
/// </summary>
|
||||
public string EntityDefName;
|
||||
/// <summary>
|
||||
/// 要生成的实体定义的具体类型名,例如 "CharacterDef" 或 "MonsterDef"。
|
||||
/// 用于 DefineManager 的严格类型查找。
|
||||
/// </summary>
|
||||
public string EntityDefTypeName;
|
||||
/// <summary>
|
||||
/// 生成位置类型。
|
||||
/// </summary>
|
||||
public EntitySpawnLocationType LocationType;
|
||||
// 以下是各种LocationType可能需要的配置参数
|
||||
/// <summary>
|
||||
/// 用于 AroundSpecificCoordinates 类型:生成中心坐标。
|
||||
/// </summary>
|
||||
public Vector3 CenterCoordinates;
|
||||
/// <summary>
|
||||
/// 用于 AroundSpecificCoordinates 或 AroundTargetEntity 类型:生成半径。
|
||||
/// </summary>
|
||||
public float Radius = 10f; // 默认半径
|
||||
/// <summary>
|
||||
/// 用于 InsideSpecificBuildingType 类型:目标建筑的类型ID。
|
||||
/// </summary>
|
||||
public string BuildingTypeId;
|
||||
/// <summary>
|
||||
/// 用于 AroundTargetEntity 类型:目标派系的定义名 (factionDefName)。
|
||||
/// </summary>
|
||||
public string TargetFactionDefName;
|
||||
/// <summary>
|
||||
/// 用于 AtPredefinedSpawnPoint 类型:预定义生成点的ID。
|
||||
/// </summary>
|
||||
public string SpawnPointId;
|
||||
/// <summary>
|
||||
/// 用于 OffMap 类型:距离地图边界的额外偏移量。
|
||||
/// </summary>
|
||||
public float OffMapOffset = 5f;
|
||||
}
|
||||
/// <summary>
|
||||
/// 定义生成器生成地图实体的可能位置类型。
|
||||
/// </summary>
|
||||
public enum EntitySpawnLocationType
|
||||
{
|
||||
/// <summary>
|
||||
/// 未指定或无效的生成位置类型。
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// 在地图的可玩区域边界之外生成实体。
|
||||
/// 例如:用于在地图边缘或不可见区域生成物体,然后开始移动进入地图。
|
||||
/// </summary>
|
||||
OffMap,
|
||||
/// <summary>
|
||||
/// 在指定类型建筑的内部或附近生成实体。
|
||||
/// 例如:在 "工厂"、"商店"、"居住区" 等建筑内或其出入口。
|
||||
/// 需要一个标识符来指定建筑类型。
|
||||
/// </summary>
|
||||
InsideSpecificBuildingType,
|
||||
/// <summary>
|
||||
/// 在指定坐标点的周围区域内生成实体。
|
||||
/// 需要额外的坐标参数和半径/范围参数。
|
||||
/// </summary>
|
||||
AroundSpecificCoordinates,
|
||||
/// <summary>
|
||||
/// 在特定派系(或其他指定目标实体,例如NPC或特定对象)的周围区域内生成实体。
|
||||
/// 需要一个标识符来指定目标派系的定义名,以及一个半径/范围参数。
|
||||
/// </summary>
|
||||
AroundTargetEntity,
|
||||
/// <summary>
|
||||
/// 在地图上的随机可生成点生成实体。
|
||||
/// </summary>
|
||||
RandomlyOnMap,
|
||||
/// <summary>
|
||||
/// 在预定义的生成点(Spawn Point)生成实体。
|
||||
/// 这些点通常由地图设计者放置,并带有唯一的ID或名称。
|
||||
/// </summary>
|
||||
AtPredefinedSpawnPoint
|
||||
}
|
||||
public class Event_EntityGenerater : EventWorkClassBase
|
||||
{
|
||||
private EntityGenerateConfig _config;
|
||||
private EntityDef _aimEntity;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化实体生成器事件。
|
||||
/// </summary>
|
||||
/// <param name="value">包含事件配置的JSON字符串。</param>
|
||||
public override void Init(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
Debug.LogError("初始化值为空或null。请提供一个JSON配置字符串。");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
_config = JsonUtility.FromJson<EntityGenerateConfig>(value);
|
||||
if (_config == null)
|
||||
{
|
||||
Debug.LogError($"无法解析配置JSON: {value}");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(_config.EntityDefTypeName))
|
||||
{
|
||||
Debug.LogError($"实体定义类型名为空或null (实体定义名: '{_config.EntityDefName}')。无法查找实体定义。");
|
||||
return;
|
||||
}
|
||||
_aimEntity = (EntityDef)DefineManager.Instance.FindDefine(_config.EntityDefTypeName,_config.EntityDefName);
|
||||
if (_aimEntity == null)
|
||||
{
|
||||
Debug.LogError($"未找到实体定义 (名称: '{_config.EntityDefName}', 类型: '{_config.EntityDefTypeName}')。请检查配置。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"解析配置JSON时出错: {value}。异常信息: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行实体生成器事件,在指定维度生成实体。
|
||||
/// </summary>
|
||||
/// <param name="dimensionID">要生成实体的维度ID。</param>
|
||||
public override void Run(string dimensionID)
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
Debug.LogError("事件配置(_config)为空。Init()可能失败了。");
|
||||
return;
|
||||
}
|
||||
if (_aimEntity == null)
|
||||
{
|
||||
Debug.LogError($"目标实体定义为空 (名称: {_config.EntityDefName}, 类型: {_config.EntityDefTypeName})。无法生成实体。");
|
||||
return;
|
||||
}
|
||||
var position = GetPosition(dimensionID);
|
||||
// 检查 GetPosition 是否返回了有效的非零位置,除非它是 AroundSpecificCoordinates 且中心点就是 Vector3.zero
|
||||
if (position == Vector3.zero && (_config.LocationType != EntitySpawnLocationType.AroundSpecificCoordinates || _config.CenterCoordinates != Vector3.zero))
|
||||
{
|
||||
Debug.LogWarning($"未能为类型 {_config.LocationType} 获取有效的生成位置。实体可能在原点 (0,0,0) 生成。");
|
||||
}
|
||||
|
||||
if (_aimEntity is CharacterDef characterDef)
|
||||
{
|
||||
EntityManage.Instance.GenerateEntity(dimensionID, characterDef, position);
|
||||
Debug.Log($"已在维度 {dimensionID} 的 {position} 位置生成角色 '{characterDef.defName}'。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_aimEntity is MonsterDef monsterDef)
|
||||
{
|
||||
EntityManage.Instance.GenerateMonsterEntity(dimensionID, monsterDef, position);
|
||||
Debug.Log($"已在维度 {dimensionID} 的 {position} 位置生成怪物 '{monsterDef.defName}'。");
|
||||
return;
|
||||
}
|
||||
Debug.LogWarning($"目标实体 '{_aimEntity.defName}' (类型: {_aimEntity.GetType().Name}) 既不是 CharacterDef 也不是 MonsterDef。" +
|
||||
$"如果你想生成其他类型,EntityManage需要一个通用的生成实体方法。没有生成任何实体。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据配置获取实体生成位置。
|
||||
/// </summary>
|
||||
/// <param name="dimensionID">要获取位置的维度ID。</param>
|
||||
/// <returns>计算出的生成位置,如果失败则返回 Vector3.zero。</returns>
|
||||
private Vector3 GetPosition(string dimensionID)
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
Debug.LogError("获取位置时配置为空。返回 Vector3.zero。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
var dimension = Program.Instance.GetDimension(dimensionID);
|
||||
if (dimension == null)
|
||||
{
|
||||
Debug.LogError($"未找到维度 '{dimensionID}'。无法确定生成位置。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
var mapGenerator = dimension.mapGenerator;
|
||||
if (mapGenerator == null)
|
||||
{
|
||||
Debug.LogError($"维度 '{dimensionID}' 的地图生成器为空。无法确定生成位置。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
switch (_config.LocationType)
|
||||
{
|
||||
case EntitySpawnLocationType.OffMap:
|
||||
{
|
||||
var size = mapGenerator.GetSize();
|
||||
var dir = Random.Range(0, 4); // 0:上, 1:下, 2:左, 3:右
|
||||
Vector2Int gridCoord; // 地图网格坐标
|
||||
Vector2Int worldCoord2D; // GetWorldCoordinates 返回的 Vector2Int
|
||||
Vector3 worldPos3D; // 最终的 Vector3 世界坐标
|
||||
var offset = _config.OffMapOffset;
|
||||
switch (dir)
|
||||
{
|
||||
case 0: // Top border (max Y)
|
||||
gridCoord = new Vector2Int(Random.Range(0, size.x), size.y);
|
||||
worldCoord2D = mapGenerator.GetWorldCoordinates(gridCoord);
|
||||
worldPos3D = new Vector3(worldCoord2D.x, worldCoord2D.y, 0f); // 转换为 Vector3
|
||||
worldPos3D.y += offset;
|
||||
break;
|
||||
case 1: // Bottom border (min Y)
|
||||
gridCoord = new Vector2Int(Random.Range(0, size.x), 0);
|
||||
worldCoord2D = mapGenerator.GetWorldCoordinates(gridCoord);
|
||||
worldPos3D = new Vector3(worldCoord2D.x, worldCoord2D.y, 0f); // 转换为 Vector3
|
||||
worldPos3D.y -= offset;
|
||||
break;
|
||||
case 2: // Left border (min X)
|
||||
gridCoord = new Vector2Int(0, Random.Range(0, size.y));
|
||||
worldCoord2D = mapGenerator.GetWorldCoordinates(gridCoord);
|
||||
worldPos3D = new Vector3(worldCoord2D.x, worldCoord2D.y, 0f); // 转换为 Vector3
|
||||
worldPos3D.x -= offset;
|
||||
break;
|
||||
case 3: // Right border (max X)
|
||||
gridCoord = new Vector2Int(size.x, Random.Range(0, size.y));
|
||||
worldCoord2D = mapGenerator.GetWorldCoordinates(gridCoord);
|
||||
worldPos3D = new Vector3(worldCoord2D.x, worldCoord2D.y, 0f); // 转换为 Vector3
|
||||
worldPos3D.x += offset;
|
||||
break;
|
||||
default:
|
||||
Debug.LogError("OffMap 生成方向无效。不应该发生此情况。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
worldPos3D.x += Random.Range(-offset / 2f, offset / 2f);
|
||||
worldPos3D.y += Random.Range(-offset / 2f, offset / 2f);
|
||||
return worldPos3D;
|
||||
}
|
||||
case EntitySpawnLocationType.AroundSpecificCoordinates:
|
||||
{
|
||||
var center = _config.CenterCoordinates;
|
||||
var radius = _config.Radius;
|
||||
var randomOffset = Random.insideUnitCircle * radius;
|
||||
return new Vector3(center.x + randomOffset.x, center.y + randomOffset.y, center.z);
|
||||
}
|
||||
case EntitySpawnLocationType.AroundTargetEntity:
|
||||
{
|
||||
if (string.IsNullOrEmpty(_config.TargetFactionDefName))
|
||||
{
|
||||
Debug.LogWarning($"配置了 'AroundTargetEntity',但 'TargetFactionDefName' 为空或null。无法找到派系实体。将在原点生成。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
var factionEntities = EntityManage.Instance.FindEntitiesByFaction(dimensionID, _config.TargetFactionDefName);
|
||||
if (factionEntities == null || factionEntities.Length == 0)
|
||||
{
|
||||
Debug.LogWarning($"在维度 '{dimensionID}' 中未找到派系 '{_config.TargetFactionDefName}' 的任何实体。将在原点生成。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
var randomIndex = Random.Range(0, factionEntities.Length);
|
||||
var targetEntityPrefab = factionEntities[randomIndex];
|
||||
if (targetEntityPrefab == null || targetEntityPrefab.transform == null)
|
||||
{
|
||||
Debug.LogWarning($"从派系 '{_config.TargetFactionDefName}' 中随机选择的实体为空或没有Transform组件。将在原点生成。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
var center = targetEntityPrefab.transform.position;
|
||||
var radius = _config.Radius;
|
||||
var randomOffset = Random.insideUnitCircle * radius;
|
||||
|
||||
Debug.Log($"围绕派系 '{_config.TargetFactionDefName}' 的实体 (世界坐标: {center}) 生成。生成的偏移量: {randomOffset}。");
|
||||
return new Vector3(center.x + randomOffset.x, center.y + randomOffset.y, center.z);
|
||||
}
|
||||
case EntitySpawnLocationType.RandomlyOnMap:
|
||||
{
|
||||
var size = mapGenerator.GetSize();
|
||||
var randomGridPos = new Vector2Int(Random.Range(0, size.x), Random.Range(0, size.y));
|
||||
|
||||
var worldCoord2D = mapGenerator.GetWorldCoordinates(randomGridPos);
|
||||
var worldPos3D = new Vector3(worldCoord2D.x, worldCoord2D.y, 0f);
|
||||
|
||||
Debug.Log($"随机地图生成位置: {worldPos3D} (网格坐标: {randomGridPos})。");
|
||||
return worldPos3D;
|
||||
}
|
||||
case EntitySpawnLocationType.InsideSpecificBuildingType:
|
||||
{
|
||||
Debug.LogWarning($"类型为 'InsideSpecificBuildingType' ({_config.BuildingTypeId}) 的生成逻辑尚未实现。返回 Vector3.zero。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
case EntitySpawnLocationType.AtPredefinedSpawnPoint:
|
||||
{
|
||||
Debug.LogWarning($"类型为 'AtPredefinedSpawnPoint' ({_config.SpawnPointId}) 的生成逻辑尚未实现。返回 Vector3.zero。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
case EntitySpawnLocationType.None:
|
||||
default:
|
||||
Debug.LogWarning($"未知或不支持的生成位置类型: {_config.LocationType}。返回 Vector3.zero。");
|
||||
return Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aea1fb7d2e1c45e4ac62da4ae8f81393
|
||||
timeCreated: 1756789875
|
273
Client/Assets/Scripts/EventWorkClass/Event_GiveHediff.cs
Normal file
273
Client/Assets/Scripts/EventWorkClass/Event_GiveHediff.cs
Normal file
@ -0,0 +1,273 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Data;
|
||||
using Managers;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using Entity;
|
||||
using Map; // 用于 LINQ
|
||||
|
||||
namespace EventWorkClass
|
||||
{
|
||||
/// <summary>
|
||||
/// Event_GiveHediff 事件的配置数据结构。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class GiveHediffConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 要添加或移除的 Hediff 的定义名 (defName)。
|
||||
/// </summary>
|
||||
public string HediffDefName;
|
||||
/// <summary>
|
||||
/// 要添加或移除的 Hediff 定义的具体类型名,例如 "HediffDef" 或其子类名。
|
||||
/// 用于 DefineManager 的严格类型查找。
|
||||
/// </summary>
|
||||
public string HediffDefTypeName;
|
||||
/// <summary>
|
||||
/// 要执行的操作类型:添加或移除 Hediff。
|
||||
/// </summary>
|
||||
public HediffActionType ActionType;
|
||||
/// <summary>
|
||||
/// 目标实体选择类型。
|
||||
/// </summary>
|
||||
public TargetEntitySelectionType TargetSelectionType;
|
||||
// 以下是各种 TargetSelectionType 可能需要的配置参数
|
||||
|
||||
/// <summary>
|
||||
/// 用于 SpecificEntityById 类型:目标实体的唯一ID。
|
||||
/// </summary>
|
||||
public string TargetEntityId;
|
||||
/// <summary>
|
||||
/// 用于 AllEntitiesInFaction 或 TargetSpecificFactionLeader 类型:目标派系的定义名 (factionDefName)。
|
||||
/// </summary>
|
||||
public string TargetFactionDefName;
|
||||
/// <summary>
|
||||
/// 用于 AroundSpecificCoordinates 类型:生成中心坐标。
|
||||
/// </summary>
|
||||
public Vector3 CenterCoordinates;
|
||||
/// <summary>
|
||||
/// 用于 AroundSpecificCoordinates 类型:搜索半径。
|
||||
/// </summary>
|
||||
public float Radius = 10f; // 默认半径
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定义针对 Hediff 的操作类型。
|
||||
/// </summary>
|
||||
public enum HediffActionType
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加 Hediff。
|
||||
/// </summary>
|
||||
Add,
|
||||
/// <summary>
|
||||
/// 移除 Hediff。
|
||||
/// </summary>
|
||||
Remove
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定义目标实体选择的类型。
|
||||
/// </summary>
|
||||
public enum TargetEntitySelectionType
|
||||
{
|
||||
/// <summary>
|
||||
/// 未指定或无效的目标选择类型。
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// 目标是当前玩家(如果存在)。
|
||||
/// </summary>
|
||||
Player,
|
||||
/// <summary>
|
||||
/// 目标是指定派系的所有活动实体。
|
||||
/// </summary>
|
||||
AllEntitiesInFaction,
|
||||
/// <summary>
|
||||
/// 目标是指定坐标周围半径内的所有生物。
|
||||
/// </summary>
|
||||
AroundSpecificCoordinates
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event_GiveHediff 事件类:用于给予或移除健康状态 (Hediff)。
|
||||
/// </summary>
|
||||
public class Event_GiveHediff : EventWorkClassBase
|
||||
{
|
||||
private GiveHediffConfig _config;
|
||||
private HediffDef _aimHediffDef;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 Hediff 给予/移除事件。
|
||||
/// </summary>
|
||||
/// <param name="value">包含事件配置的JSON字符串。</param>
|
||||
public override void Init(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
Debug.LogError("Event_GiveHediff: 初始化值为空或null。请提供一个JSON配置字符串。");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
_config = JsonUtility.FromJson<GiveHediffConfig>(value);
|
||||
if (_config == null)
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: 无法解析配置JSON: {value}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(_config.HediffDefTypeName) || string.IsNullOrEmpty(_config.HediffDefName))
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: Hediff定义类型名或名称为空或null (名称: '{_config.HediffDefName}', 类型: '{_config.HediffDefTypeName}')。无法查找Hediff定义。");
|
||||
return;
|
||||
}
|
||||
|
||||
_aimHediffDef = (HediffDef)DefineManager.Instance.FindDefine(_config.HediffDefTypeName, _config.HediffDefName);
|
||||
if (_aimHediffDef == null)
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: 未找到Hediff定义 (名称: '{_config.HediffDefName}', 类型: '{_config.HediffDefTypeName}')。请检查配置。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: 解析配置JSON时出错: {value}。异常信息: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行 Hediff 给予/移除事件。
|
||||
/// </summary>
|
||||
/// <param name="dimensionID">目标实体所在的维度ID。</param>
|
||||
public override void Run(string dimensionID)
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
Debug.LogError("Event_GiveHediff: 事件配置(_config)为空。Init()可能失败了。");
|
||||
return;
|
||||
}
|
||||
if (_aimHediffDef == null)
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: 目标Hediff定义为空 (名称: {_config.HediffDefName}, 类型: {_config.HediffDefTypeName})。无法执行操作。");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetEntities = GetTargetEntities(dimensionID);
|
||||
if (targetEntities == null || targetEntities.Count == 0)
|
||||
{
|
||||
Debug.LogWarning($"Event_GiveHediff: 在维度 '{dimensionID}' 中未找到符合条件的目标实体 (选择类型: {_config.TargetSelectionType})。");
|
||||
return;
|
||||
}
|
||||
|
||||
var successCount = 0;
|
||||
var failedCount = 0;
|
||||
var hediffInstance = new Hediff(_aimHediffDef); // 创建 Hediff 实例
|
||||
|
||||
foreach (var entity in targetEntities)
|
||||
{
|
||||
if (entity is LivingEntity livingEntity)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_config.ActionType == HediffActionType.Add)
|
||||
{
|
||||
livingEntity.AddHediff(hediffInstance);
|
||||
Debug.Log($"Event_GiveHediff: 已向实体 '{livingEntity.name}' 添加 Hediff '{_aimHediffDef.defName}'。");
|
||||
successCount++;
|
||||
}
|
||||
else if (_config.ActionType == HediffActionType.Remove)
|
||||
{
|
||||
livingEntity.RemoveHediff(hediffInstance);
|
||||
Debug.Log($"Event_GiveHediff: 已从实体 '{livingEntity.name}' 移除 Hediff '{_aimHediffDef.defName}'。");
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: 对实体 '{entity.name}' 执行 Hediff 操作时出错: {ex.Message}");
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Event_GiveHediff: 实体 '{entity.name}' (类型: {entity.GetType().Name}) 不是 LivingEntity,无法添加/移除 Hediff。");
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
Debug.Log($"Event_GiveHediff: 完成操作。成功: {successCount},失败: {failedCount} (Hediff: {_aimHediffDef.defName}, 操作: {_config.ActionType})。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据配置获取目标实体列表。
|
||||
/// </summary>
|
||||
/// <param name="dimensionID">维度ID。</param>
|
||||
/// <returns>符合条件的目标实体列表。</returns>
|
||||
private List<Entity.Entity> GetTargetEntities(string dimensionID)
|
||||
{
|
||||
var entities = new List<Entity.Entity>();
|
||||
var dimension = Program.Instance.GetDimension(dimensionID);
|
||||
|
||||
if (dimension == null)
|
||||
{
|
||||
Debug.LogError($"Event_GiveHediff: 未找到维度 '{dimensionID}'。无法获取目标实体。");
|
||||
return entities;
|
||||
}
|
||||
|
||||
switch (_config.TargetSelectionType)
|
||||
{
|
||||
case TargetEntitySelectionType.Player:
|
||||
// 假设 PlayerManager.Instance.GetPlayerEntity(dimensionID) 返回 LivingEntity
|
||||
// 或者你的玩家实体本身就是 LivingEntity
|
||||
var player = dimension.focusEntity as LivingEntity; // 假设玩家是维度的一部分且是LivingEntity
|
||||
if (player != null)
|
||||
{
|
||||
entities.Add(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Event_GiveHediff: 未能找到维度 '{dimensionID}' 中的玩家实体或玩家不是 LivingEntity。");
|
||||
}
|
||||
break;
|
||||
|
||||
case TargetEntitySelectionType.AllEntitiesInFaction:
|
||||
if (string.IsNullOrEmpty(_config.TargetFactionDefName))
|
||||
{
|
||||
Debug.LogWarning("Event_GiveHediff: 配置了 'AllEntitiesInFaction',但 'TargetFactionDefName' 为空。");
|
||||
return entities;
|
||||
}
|
||||
|
||||
entities.AddRange(EntityManage.Instance
|
||||
.FindEntitiesByFaction(dimensionID, _config.TargetFactionDefName)
|
||||
.Select(item => item.entity));
|
||||
break;
|
||||
|
||||
case TargetEntitySelectionType.AroundSpecificCoordinates:
|
||||
// 假设 EntityManage 提供了根据位置和半径查找实体的方法
|
||||
// 或者可以直接通过场景查询(例如 Physics.OverlapSphere 或者自定义管理系统)
|
||||
// 为了简化,我将假设 EntityManage 提供 FindEntitiesAroundRadius 方法
|
||||
var allEntitiesInDimension = EntityManage.Instance.GetAllEntities(dimensionID)
|
||||
.Select(item => item.entity);
|
||||
var center = _config.CenterCoordinates;
|
||||
var radius = _config.Radius;
|
||||
|
||||
foreach (var ent in allEntitiesInDimension)
|
||||
{
|
||||
// 确保实体有 Transform 且在半径内
|
||||
if (ent != null && ent.transform != null && Vector3.Distance(ent.transform.position, center) <= radius)
|
||||
{
|
||||
entities.Add(ent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TargetEntitySelectionType.None:
|
||||
default:
|
||||
Debug.LogWarning($"Event_GiveHediff: 未知或不支持的目标实体选择类型: {_config.TargetSelectionType}。");
|
||||
break;
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e8b013e0825473e9dbba1f7f393e66f
|
||||
timeCreated: 1756860849
|
@ -51,31 +51,44 @@ namespace Managers
|
||||
/// <summary> 默认实体的预制体,用于生成失败时的回退。 </summary>
|
||||
public EntityPrefab defaultEntityPrefab;
|
||||
|
||||
|
||||
public EntityPrefab[] GetAllEntities(string dimensionId)
|
||||
{
|
||||
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
|
||||
{
|
||||
Debug.LogWarning($"实体管理器:尝试在维度 '{dimensionId}' 中查找实体,但其内部存储未初始化。");
|
||||
return null;
|
||||
}
|
||||
// 获取对应维度的内层字典
|
||||
var factionEntitiesForDimension = _dimensionFactionEntities[dimensionId];
|
||||
// 使用 LINQ 的 SelectMany 方法来扁平化所有 LinkedList 中的 EntityPrefab
|
||||
return factionEntitiesForDimension.Values // 获取所有 LinkedList<EntityPrefab> 的集合
|
||||
.SelectMany(linkedList => linkedList) // 将每个 LinkedList 中的元素展开到一个单一的序列中
|
||||
.ToArray(); // 将该序列转换为一个数组
|
||||
}
|
||||
/// <summary>
|
||||
/// 在指定维度中,根据派系键查找所有实体。
|
||||
/// </summary>
|
||||
/// <param name="dimensionId">维度的唯一标识符。</param>
|
||||
/// <param name="factionKey">派系键。</param>
|
||||
/// <returns>指定派系下的实体列表,如果未找到则返回空列表。</returns>
|
||||
public LinkedList<EntityPrefab> FindEntitiesByFaction(string dimensionId, string factionKey)
|
||||
public EntityPrefab[] FindEntitiesByFaction(string dimensionId, string factionKey)
|
||||
{
|
||||
// 如果在场景加载前或维度未在Program中注册,_dimensionFactionEntities可能还没有该维度ID的条目。
|
||||
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
|
||||
{
|
||||
Debug.LogWarning($"实体管理器:尝试在维度 '{dimensionId}' 中查找实体,但其内部存储未初始化。");
|
||||
return new LinkedList<EntityPrefab>();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_dimensionFactionEntities.TryGetValue(dimensionId, out var factionDict))
|
||||
{
|
||||
if (factionDict.TryGetValue(factionKey, out var entities))
|
||||
{
|
||||
return entities;
|
||||
return entities.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return new LinkedList<EntityPrefab>(); // 如果未找到,返回一个空列表
|
||||
return null; // 如果未找到,返回一个空列表
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,75 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Data;
|
||||
using Entity;
|
||||
using Prefab;
|
||||
using UnityEngine;
|
||||
using EventWorkClass;
|
||||
using Utils;
|
||||
using Random = System.Random;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Managers
|
||||
{
|
||||
class EventManager:Singleton<EventManager>,ILaunchManager
|
||||
/// <summary>
|
||||
/// 事件管理器,负责事件的加载、注册和执行。
|
||||
/// 遵循单例模式,并在启动流程中扮演一个管理器角色。
|
||||
/// </summary>
|
||||
class EventManager : Singleton<EventManager>, ILaunchManager
|
||||
{
|
||||
private static Random _random = new();
|
||||
public EventDef[] EventDefs { get; private set; }
|
||||
/// <summary>
|
||||
/// 存储所有已加载的事件定义,键为事件名称,值为对应的事件工作类实例。
|
||||
/// </summary>
|
||||
public Dictionary<string, EventWorkClassBase> EventDefs { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前加载步骤的描述,用于启动流程的进度显示。
|
||||
/// </summary>
|
||||
public string StepDescription => "正在载入事件";
|
||||
|
||||
/// <summary>
|
||||
/// 初始化事件管理器,从定义管理器中加载所有事件定义并实例化其工作类。
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
if(EventDefs!=null)
|
||||
// 如果事件定义已经加载,则直接返回,避免重复初始化。
|
||||
if (EventDefs != null)
|
||||
return;
|
||||
EventDefs = DefineManager.Instance.QueryDefinesByType<EventDef>();
|
||||
|
||||
var defs = DefineManager.Instance.QueryDefinesByType<EventDef>();
|
||||
EventDefs = new Dictionary<string, EventWorkClassBase>();
|
||||
foreach (var def in defs)
|
||||
{
|
||||
if (EventDefs.ContainsKey(def.defName))
|
||||
{
|
||||
Debug.LogWarning($"警告:事件名称重复,已跳过加载名称为 {def.defName} 的事件定义。");
|
||||
continue;
|
||||
}
|
||||
var eventWorker = GetAndInstantiateEventWorker(def.workClass);
|
||||
if (eventWorker == null)
|
||||
{
|
||||
Debug.LogWarning($"警告:未能找到或实例化名称为 '{def.workClass}' 的事件工作类,已跳过加载名称为 '{def.defName}' 的事件定义。");
|
||||
continue;
|
||||
}
|
||||
eventWorker.Init(def.value);
|
||||
EventDefs.Add(def.defName, eventWorker);
|
||||
}
|
||||
Debug.Log($"事件管理器初始化完成,共载入 {EventDefs.Count} 个事件。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理事件管理器,释放所有已加载的事件定义。
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
EventDefs = null;
|
||||
Debug.Log("事件管理器已清理。");
|
||||
}
|
||||
|
||||
public static void ExecuteEvent(EventDef eventDef)
|
||||
/// <summary>
|
||||
/// 执行指定名称的事件。
|
||||
/// </summary>
|
||||
/// <param name="eventName">要执行的事件的名称。</param>
|
||||
/// <param name="dimensionID">事件执行的维度ID,如果为null,将使用当前焦点的维度ID。</param>
|
||||
public void Action(string eventName, string dimensionID = null)
|
||||
{
|
||||
if(eventDef == null)
|
||||
if (EventDefs == null)
|
||||
{
|
||||
Debug.LogError($"错误:事件管理器尚未初始化或已被清理。无法执行事件 '{eventName}'。");
|
||||
return;
|
||||
if (eventDef.hediffEvent != null)
|
||||
{
|
||||
var entityList = EntityManage.Instance.FindEntitiesByFaction(Program.Instance.FocusedDimensionId,
|
||||
eventDef.hediffEvent.affiliation.defName);
|
||||
List<Entity.Entity> filteredEntitiesTraditional = new();
|
||||
foreach (var prefab in entityList)
|
||||
{
|
||||
var entity = prefab.entity;
|
||||
if (entity is Character || entity is Monster)
|
||||
{
|
||||
filteredEntitiesTraditional.Add(entity);
|
||||
}
|
||||
}
|
||||
var selectedElements = SelectRandomElements_FisherYates(filteredEntitiesTraditional, eventDef.hediffEvent.specificPawnCount);
|
||||
foreach (var selectedElement in selectedElements)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!EventDefs.ContainsKey(eventName))
|
||||
{
|
||||
Debug.LogWarning($"警告:未能找到名称为 '{eventName}' 的事件定义,已跳过执行该事件。");
|
||||
return;
|
||||
}
|
||||
// 假设 Program.Instance 和 FocusedDimensionId 存在且可访问。
|
||||
// 如果 dimensionID 为 null,则使用当前焦点维度ID。
|
||||
dimensionID ??= Program.Instance.FocusedDimensionId;
|
||||
EventDefs[eventName].Run(dimensionID);
|
||||
}
|
||||
public static List<T> SelectRandomElements_FisherYates<T>(List<T> sourceList, int count)
|
||||
|
||||
/// <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) // 默认程序集
|
||||
{
|
||||
if (sourceList == null) throw new ArgumentNullException(nameof(sourceList));
|
||||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be negative.");
|
||||
if (count == 0) return new List<T>();
|
||||
if (count >= sourceList.Count) return new List<T>(sourceList); // 如果n大于等于列表大小,则返回所有元素副本
|
||||
|
||||
List<T> result = new List<T>(count); // 预分配容量
|
||||
List<T> temp = new List<T>(sourceList); // 创建一个副本以避免修改原始列表
|
||||
|
||||
int n = temp.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
// 1. 确定要搜索的程序集。
|
||||
if (assemblyToSearch == null)
|
||||
{
|
||||
int k = _random.Next(i, n);
|
||||
result.Add(temp[k]);
|
||||
(temp[k], temp[i]) = (temp[i], temp[k]);
|
||||
// 默认从 EventWorkClassBase 所在的程序集查找,通常其实现类也会在这个程序集。
|
||||
assemblyToSearch = typeof(EventWorkClassBase).Assembly;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 构造完整的类型名称。
|
||||
string 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 实例化对象。它默认调用无参公共构造函数。
|
||||
object 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ namespace Map
|
||||
[SerializeField] public MapGenerator mapGenerator;
|
||||
|
||||
public Vector3 cameraPosition;
|
||||
|
||||
public Entity.Entity focusEntity;
|
||||
/// <summary>
|
||||
/// 获取此维度的唯一标识符。
|
||||
/// </summary>
|
||||
|
@ -28,6 +28,15 @@ namespace Map
|
||||
|
||||
baseMap.RefreshAllTiles();
|
||||
}
|
||||
|
||||
|
||||
public Vector2Int GetSize()
|
||||
{
|
||||
return baseMap.GetSize();
|
||||
}
|
||||
|
||||
public Vector2Int GetWorldCoordinates(Vector2Int mapCoordinates)
|
||||
{
|
||||
return new Vector2Int((int)transform.position.x, (int)transform.position.y) + mapCoordinates;
|
||||
}
|
||||
}
|
||||
}
|
@ -208,6 +208,8 @@ public class Program : Singleton<Program>
|
||||
|
||||
// 更新内部状态
|
||||
FocusedEntity = entity;
|
||||
if(FocusedDimension)
|
||||
FocusedDimension.focusEntity=entity;
|
||||
|
||||
// 触发事件,将新的焦点实体(或 null)作为参数传递。
|
||||
OnFocusedEntityChanged?.Invoke(FocusedEntity);
|
||||
|
@ -77,7 +77,6 @@ namespace UI
|
||||
InitDefineButtons<EventDef>(
|
||||
"事件菜单",
|
||||
"未定义任何事件",
|
||||
// 假设 EventDef 也有 label 字段作为按钮文本
|
||||
def => def.label,
|
||||
eventDef =>
|
||||
{
|
||||
|
Reference in New Issue
Block a user