NLDClient-yudde/ProjectNLD/Assets/Editor/LevelEditor/LevelEditorWindow.cs

1756 lines
56 KiB
C#
Raw Normal View History

using TGS;
using Framework;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;
2023-08-22 19:08:45 +08:00
using Gameplay.Level;
using Sirenix.Utilities;
using Sirenix.OdinInspector;
2023-08-22 19:08:45 +08:00
using Sirenix.Utilities.Editor;
using System.Collections.Generic;
2024-11-18 16:50:35 +08:00
using cfg.FightCfg;
2025-06-04 15:23:36 +08:00
using cfg.LevelCfg;
2024-11-18 16:50:35 +08:00
using cfg.MonsterCfg;
using cfg.VehicleCfg;
using Sirenix.OdinInspector.Editor;
2024-11-18 16:50:35 +08:00
using Level = cfg.LevelCfg.Level;
2023-08-22 19:08:45 +08:00
using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment;
using static Gameplay.Level.LevelData;
2023-08-22 19:08:45 +08:00
2025-12-10 17:39:34 +08:00
public partial class LevelEditorWindow : OdinEditorWindow
2023-08-22 19:08:45 +08:00
{
2025-02-27 13:31:47 +08:00
[MenuItem("Tools/*地图场景/关卡编辑器", false, (int)NLDMenuID.LevelEditor)]
private static void OpenLevelEditorWindow()
{
var window = GetWindow<LevelEditorWindow>();
window.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
window.titleContent = new GUIContent("关卡编辑器");
}
public static void OpenWindow(LevelEditor levelEditor)
{
MapEditorSettings.Init();
currWindow = GetWindow<LevelEditorWindow>();
currWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
currWindow.currentLevelData = null;
currWindow._levelEditor = levelEditor;
currWindow.LoadLevel(levelEditor.LevelData);
var level = Path.GetFileNameWithoutExtension(levelEditor.LevelDataJson.name);
currWindow.levelID = level.Substring(level.Length - 6);
2025-07-02 14:51:53 +08:00
//currWindow.GetLevelMonsterClass();
DebugUtil.Log("关卡数据:{0}", currWindow.levelID);
}
2025-05-28 17:49:04 +08:00
private static LevelEditorWindow currWindow;
2024-11-07 15:50:33 +08:00
2025-05-28 17:49:04 +08:00
private MapManager _mapManager;
2024-11-04 18:43:29 +08:00
2025-05-28 17:49:04 +08:00
private Map _curMap;
2024-11-07 15:50:33 +08:00
2025-05-28 17:49:04 +08:00
private LevelEditor _levelEditor;
2025-02-17 17:11:38 +08:00
2025-05-28 17:49:04 +08:00
#region 配置表
2025-02-17 17:11:38 +08:00
2025-05-28 17:49:04 +08:00
private Level LevelCfg => EditorTableManager.instance.tables.Level;
private Monster MonsterCfg => EditorTableManager.instance.tables.Monster;
private MonsterClass MonsterClassCfg => EditorTableManager.instance.tables.MonsterClass;
2025-05-28 17:49:04 +08:00
private VehicleConfig VehicleCfg => EditorTableManager.instance.tables.VehicleConfig;
private FightNPCConfig FightNpcCfg => EditorTableManager.instance.tables.FightNPCConfig;
private BuildConfig FightBuildCfg => EditorTableManager.instance.tables.BuildConfig;
2024-11-04 18:19:57 +08:00
2025-05-28 17:49:04 +08:00
#endregion
2024-11-04 18:19:57 +08:00
2025-05-28 17:49:04 +08:00
#region 地块颜色
2024-11-04 18:19:57 +08:00
2025-05-28 17:49:04 +08:00
private static readonly Color RegionColor = MapUtils.GetRGBAColor("FF960072");
2024-11-04 18:19:57 +08:00
2025-12-10 19:41:23 +08:00
private static readonly Color ShowRegionColor = Color.red;
2025-11-17 15:09:39 +08:00
private static readonly Color CaptureRegionColor = Color.yellow;
2025-11-17 17:47:26 +08:00
private static readonly Color RetreatRegionColor = Color.cyan;
2025-12-23 16:58:55 +08:00
private static readonly Color GroupHighlightColor = new Color(1f, 0.5f, 0f, 0.8f);
2025-05-28 17:49:04 +08:00
#endregion
2024-11-04 18:19:57 +08:00
2025-12-09 13:05:27 +08:00
#region 任务相关
2025-12-09 16:21:59 +08:00
[BoxGroup("任务列表")] [LabelText("任务列表"), Indent]
public List<TaskInfoEditor> taskInfos = new List<TaskInfoEditor>();
#endregion
/*#region 胜利失败星级条件
2025-12-09 16:21:59 +08:00
2025-12-09 19:01:17 +08:00
private int successTaskID;
[FoldoutGroup("胜利失败星级条件")]
[HorizontalGroup("胜利失败星级条件/1")]
[LabelText("胜利条件"), Indent]
[ReadOnly]
[InfoBox("胜利条件任务无效,请在任务列表中检查配置。", InfoMessageType.Error, "@!IsTaskInvalid(successTaskID)")]
2025-12-09 16:21:59 +08:00
public string successTask;
[FoldoutGroup("胜利失败星级条件")]
[HorizontalGroup("胜利失败星级条件/1")]
[Button("搜索/选择胜利任务", ButtonSizes.Small)]
2025-12-09 19:01:17 +08:00
[InfoBox("胜利条件任务无效,请在任务列表中检查配置。", InfoMessageType.Error, "@!IsTaskInvalid(successTaskID)")]
2025-12-09 16:21:59 +08:00
private void OpenSuccessTaskSelector()
{
2025-12-09 19:01:17 +08:00
ShowTaskSelector("选择胜利条件任务", taskName => successTask = taskName, id => successTaskID = id);
2025-12-09 16:21:59 +08:00
}
2025-12-09 19:01:17 +08:00
private int failTaskID;
2025-12-09 16:21:59 +08:00
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/2")] [LabelText("失败条件"), Indent] [ReadOnly]
public string failTask;
[FoldoutGroup("胜利失败星级条件")]
[HorizontalGroup("胜利失败星级条件/2")]
[Button("搜索/选择失败任务", ButtonSizes.Small)]
private void OpenFailTaskSelector()
{
2025-12-09 19:01:17 +08:00
ShowTaskSelector("选择失败条件任务", taskName => failTask = taskName, id => failTaskID = id);
2025-12-09 16:21:59 +08:00
}
2025-12-09 19:01:17 +08:00
private List<int> starTaskIDs = new List<int>() { 0, 0, 0 };
2025-12-09 16:21:59 +08:00
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/3")] [LabelText("1星条件"), Indent] [ReadOnly]
public string oneStarTask;
[FoldoutGroup("胜利失败星级条件")]
[HorizontalGroup("胜利失败星级条件/3")]
[Button("搜索/选择1星任务", ButtonSizes.Small)]
private void OpenOneStarTaskSelector()
{
2025-12-09 19:01:17 +08:00
ShowTaskSelector("选择1星条件任务", taskName => oneStarTask = taskName, id => starTaskIDs[0] = id);
2025-12-09 16:21:59 +08:00
}
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/4")] [LabelText("2星条件"), Indent] [ReadOnly]
public string twoStarTask;
[FoldoutGroup("胜利失败星级条件")]
[HorizontalGroup("胜利失败星级条件/4")]
[Button("搜索/选择2星任务", ButtonSizes.Small)]
private void OpenTwoStarTaskSelector()
{
2025-12-09 19:01:17 +08:00
ShowTaskSelector("选择2星条件任务", taskName => twoStarTask = taskName, id => starTaskIDs[1] = id);
2025-12-09 16:21:59 +08:00
}
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/5")] [LabelText("3星条件"), Indent] [ReadOnly]
public string threeStarTask;
[FoldoutGroup("胜利失败星级条件")]
[HorizontalGroup("胜利失败星级条件/5")]
[Button("搜索/选择3星任务", ButtonSizes.Small)]
private void OpenThreeStarTaskSelector()
{
2025-12-09 19:01:17 +08:00
ShowTaskSelector("选择3星条件任务", taskName => threeStarTask = taskName, id => starTaskIDs[2] = id);
2025-12-09 16:21:59 +08:00
}
#endregion*/
2025-12-09 13:05:27 +08:00
2025-05-28 17:49:04 +08:00
#region 关卡数据
2023-12-22 15:26:48 +08:00
2025-12-30 13:45:24 +08:00
[FoldoutGroup("当前关卡数据")] [HideLabel]
2025-05-28 17:49:04 +08:00
public LevelData currentLevelData = null;
2024-11-04 18:43:29 +08:00
2025-05-28 17:49:04 +08:00
#endregion
2023-12-22 15:26:48 +08:00
2025-12-30 13:45:24 +08:00
#region 触发器
[FoldoutGroup("当前关卡数据")] [BoxGroup("当前关卡数据/触发器列表")] [Indent, LabelText("触发器")]
public List<LevelTriggerDataEditor> levelTriggerData = new List<LevelTriggerDataEditor>();
#endregion
#region 波次管理
[FoldoutGroup("当前关卡数据")]
[BoxGroup("当前关卡数据/波次管理")]
[LabelText("编辑波次"), Indent]
[OnValueChanged(nameof(OnIsEditingWaveChanged))]
[SerializeField]
public bool isEditingWave;
private void OnIsEditingWaveChanged()
{
if (isEditingWave)
{
// 刷新波次信息显示
RefreshWaveInfoEditors();
}
}
[FoldoutGroup("当前关卡数据")]
[BoxGroup("当前关卡数据/波次管理")]
[LabelText("波次列表(管理怪物组)"), Indent]
[ShowIf(nameof(isEditingWave))]
[InfoBox("说明波次管理基于怪物组ID不是NPC索引。一个怪物组只能属于一个波次。直接添加项来创建新波次波次ID可修改。", InfoMessageType.Info)]
[ListDrawerSettings(
CustomRemoveIndexFunction = nameof(CustomRemoveWave),
DraggableItems = false,
ShowFoldout = true
)]
public List<WaveInfoEditor> waveInfoEditors = new();
private void CustomRemoveWave(int index)
{
if (index >= 0 && index < waveInfoEditors.Count)
{
var wave = waveInfoEditors[index];
// 清除该波次中所有怪物组的怪物的波次信息
if (currentEnemyNpcInfo != null)
{
foreach (var groupId in wave.enemies)
{
foreach (var npc in currentEnemyNpcInfo)
{
if (npc.npcInfo.groups != null && npc.npcInfo.groups.Contains(groupId))
{
npc.npcInfo.waveIndex = 0;
npc.npcInfo.isHideOnLoad = false;
}
}
}
}
waveInfoEditors.RemoveAt(index);
}
}
2025-12-30 15:46:47 +08:00
2025-12-30 13:45:24 +08:00
/// <summary>
/// 刷新波次信息编辑器
/// </summary>
2025-12-30 15:46:47 +08:00
[FoldoutGroup("当前关卡数据")]
[BoxGroup("当前关卡数据/波次管理")]
[Button("刷新至怪物属性"), Indent]
[ShowIf(nameof(isEditingWave))]
2025-12-30 13:45:24 +08:00
private void RefreshWaveInfoEditors()
{
if (waveInfoEditors == null)
waveInfoEditors = new List<WaveInfoEditor>();
2025-12-30 15:46:47 +08:00
if (currentEnemyNpcInfo == null)
return;
// 第一步:重建 _enemyNpcObjectWaveDic 字典
// 创建新的字典结构
var newWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
// 遍历所有NPC根据当前的waveIndex重新组织字典
foreach (var npc in currentEnemyNpcInfo)
{
int oldWaveIndex = npc.npcInfo.waveIndex;
// 从旧字典中找到这个NPC的GameObject
GameObject npcObj = null;
if (_enemyNpcObjectWaveDic != null && _enemyNpcObjectWaveDic.TryGetValue(oldWaveIndex, out var oldNpcDic))
{
if (oldNpcDic.TryGetValue(npc, out npcObj))
{
// 找到了GameObject
}
}
// 如果找不到,尝试在所有波次中查找
if (npcObj == null && _enemyNpcObjectWaveDic != null)
{
foreach (var waveDic in _enemyNpcObjectWaveDic.Values)
{
if (waveDic.TryGetValue(npc, out npcObj))
{
break;
}
}
}
// 将GameObject添加到新字典中按照即将更新的waveIndex
if (npcObj != null)
{
// 先暂存到旧的waveIndex后面会更新
if (!newWaveDic.ContainsKey(oldWaveIndex))
{
newWaveDic[oldWaveIndex] = new Dictionary<NpcEditorInfo, GameObject>();
}
newWaveDic[oldWaveIndex][npc] = npcObj;
}
}
// 第二步清空所有NPC的波次信息
foreach (var npc in currentEnemyNpcInfo)
{
npc.npcInfo.waveIndex = 0;
npc.npcInfo.isHideOnLoad = false;
}
// 第三步根据波次编辑器更新NPC属性
var finalWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
2025-12-30 13:45:24 +08:00
foreach (var wave in waveInfoEditors)
{
foreach (var groupId in wave.enemies)
{
2025-12-30 15:46:47 +08:00
foreach (var npc in currentEnemyNpcInfo)
2025-12-30 13:45:24 +08:00
{
2025-12-30 15:46:47 +08:00
if (npc.npcInfo.groups != null && npc.npcInfo.groups.Contains(groupId))
2025-12-30 13:45:24 +08:00
{
2025-12-30 15:46:47 +08:00
npc.npcInfo.waveIndex = wave.waveID;
npc.npcInfo.isHideOnLoad = true;
// 更新到最终字典使用新的waveIndex
// 从临时字典中找到GameObject
GameObject npcObj = null;
foreach (var waveDic in newWaveDic.Values)
2025-12-30 13:45:24 +08:00
{
2025-12-30 15:46:47 +08:00
if (waveDic.TryGetValue(npc, out npcObj))
{
break;
}
}
if (npcObj != null)
{
if (!finalWaveDic.ContainsKey(wave.waveID))
{
finalWaveDic[wave.waveID] = new Dictionary<NpcEditorInfo, GameObject>();
}
finalWaveDic[wave.waveID][npc] = npcObj;
2025-12-30 13:45:24 +08:00
}
}
}
}
}
2025-12-30 15:46:47 +08:00
// 第四步处理不在任何波次中的NPCwaveIndex = 0
foreach (var npc in currentEnemyNpcInfo)
{
if (npc.npcInfo.waveIndex == 0)
{
// 从临时字典中找到GameObject
GameObject npcObj = null;
foreach (var waveDic in newWaveDic.Values)
{
if (waveDic.TryGetValue(npc, out npcObj))
{
break;
}
}
if (npcObj != null)
{
if (!finalWaveDic.ContainsKey(0))
{
finalWaveDic[0] = new Dictionary<NpcEditorInfo, GameObject>();
}
finalWaveDic[0][npc] = npcObj;
}
}
}
// 第五步:替换原字典
_enemyNpcObjectWaveDic = finalWaveDic;
DebugUtil.Log("已刷新波次信息至怪物属性,并更新了预制体字典");
2025-12-30 13:45:24 +08:00
}
#endregion
2025-12-09 16:21:59 +08:00
#region 战役关卡
[FoldoutGroup("当前关卡数据")]
[BoxGroup("当前关卡数据/支线(战役)")]
[LabelText("设置该关卡为评分关卡"), Indent]
[OnValueChanged(nameof(OnScoreLevelChanged))]
public bool scoreLevel;
private void OnScoreLevelChanged()
{
currentLevelData.scoreLevel = scoreLevel;
}
[FoldoutGroup("当前关卡数据")]
[BoxGroup("当前关卡数据/支线(战役)")]
[Indent, ShowIf("@currentLevelData.scoreLevel")]
[LabelText("评分条件")]
public List<ScoreTaskEditor> scoreTasks = new List<ScoreTaskEditor>();
#endregion
#region 关卡引导
[FoldoutGroup("关卡引导")] [BoxGroup("关卡引导/关卡进度")] [LabelText("关卡进度"), Indent]
2025-12-09 16:21:59 +08:00
public List<ProgressGuideDataEditor> progressGuideDatas = new();
2025-06-10 18:45:59 +08:00
[FoldoutGroup("关卡引导")] [BoxGroup("关卡引导/立标数据")] [LabelText("立标数据"), Indent]
2025-12-09 16:21:59 +08:00
public List<SetFlagGuideDataEditor> setFlagEditorInfos = new();
2025-06-10 18:45:59 +08:00
[FoldoutGroup("关卡引导")] [BoxGroup("关卡引导/信息板数据")] [LabelText("信息板数据"), Indent]
2025-12-09 16:21:59 +08:00
public List<InfoPanelGuideDataEditor> infoPanelGuideDatas = new();
2025-06-10 18:45:59 +08:00
#endregion
2025-07-08 20:07:21 +08:00
#region 关卡AI广播
[FoldoutGroup("关卡AI广播")] [BoxGroup("关卡AI广播/数据")] [LabelText("AI广播数据"), Indent]
2025-12-09 16:21:59 +08:00
public List<AIBroadcastDataEditor> listAIBroadcastData = new();
2025-07-08 20:07:21 +08:00
#endregion
2025-12-10 19:41:23 +08:00
#region 地区相关
/// <summary>
/// 每种地区对应的显示颜色
/// </summary>
private static readonly Dictionary<ShowRegionType, Color> ShowRegionTypeColors =
new Dictionary<ShowRegionType, Color>
{
{ ShowRegionType.CaptureRegion, CaptureRegionColor },
{ ShowRegionType.RetreatRegion, RetreatRegionColor },
{ ShowRegionType.EnemyRetreatRegion, Color.green },
{ ShowRegionType.FlagStratRegion, new Color(1f, 0.5f, 0f) },
{ ShowRegionType.FlagEndRegion, new Color(1f, 0.3f, 0.3f) },
{ ShowRegionType.MinesRegion, Color.black },
{ ShowRegionType.DefenseRegion, Color.magenta },
{ ShowRegionType.BlockRegion, Color.blue },
};
2025-12-22 15:33:08 +08:00
[FoldoutGroup("地区相关")] [LabelText("显示地区颜色")] [EnumToggleButtons] [OnValueChanged(nameof(OnShowRegionTypeChanged))]
2025-12-10 19:41:23 +08:00
public ShowRegionType showRegionType;
/// <summary>
/// 根据当前选择的地区类型集合,高亮对应的地区格子,每种地区使用独立颜色。
2025-12-10 19:41:23 +08:00
/// </summary>
private void OnShowRegionTypeChanged()
{
if (_curMap == null || currentLevelData == null)
return;
ClearShowRegionColor();
if (showRegionType == ShowRegionType.None)
{
SceneView.RepaintAll();
2025-12-10 19:41:23 +08:00
return;
}
var mask = showRegionType;
if (mask.HasFlag(ShowRegionType.All))
{
mask |= ShowRegionType.All;
}
foreach (var kv in ShowRegionTypeColors)
{
var type = kv.Key;
var color = kv.Value;
2025-12-10 19:41:23 +08:00
if (!mask.HasFlag(type))
continue;
var points = GetRegionPoints(type);
if (points == null || points.Count == 0)
continue;
_curMap.SetBlocksColor(points, true, color);
}
SceneView.RepaintAll();
}
/// <summary>
/// 按地区类型获取需要高亮的格子索引列表
/// </summary>
private List<int> GetRegionPoints(ShowRegionType type)
{
2025-12-10 19:41:23 +08:00
var points = new HashSet<int>();
switch (type)
2025-12-10 19:41:23 +08:00
{
case ShowRegionType.CaptureRegion:
if (captureEditorInfos != null)
{
foreach (var capture in captureEditorInfos)
{
if (capture?.capturePointEditorInfos == null) continue;
foreach (var p in capture.capturePointEditorInfos)
{
points.Add(p.capturePoint);
}
}
}
break;
case ShowRegionType.RetreatRegion:
if (retreatEditorInfo != null)
{
foreach (var info in retreatEditorInfo)
{
points.Add(info.retreatPoint);
}
}
break;
case ShowRegionType.EnemyRetreatRegion:
if (enemyRetreatEditorInfo?.fallbackReusablePoints != null)
{
foreach (var pos in enemyRetreatEditorInfo.fallbackReusablePoints)
{
points.Add(_curMap.BlockPosition2TGSCellIndex(pos));
}
}
break;
case ShowRegionType.FlagStratRegion:
if (flagEditorInfo?.flagStartPoints != null)
{
foreach (var pos in flagEditorInfo.flagStartPoints)
{
points.Add(_curMap.BlockPosition2TGSCellIndex(pos));
}
}
break;
case ShowRegionType.FlagEndRegion:
if (flagEditorInfo?.flagEndPoints != null)
{
foreach (var pos in flagEditorInfo.flagEndPoints)
{
points.Add(_curMap.BlockPosition2TGSCellIndex(pos));
}
}
break;
case ShowRegionType.MinesRegion:
if (minesRegionList != null)
{
foreach (var area in minesRegionList)
{
if (area?.Positions == null) continue;
foreach (var cell in area.Positions)
{
points.Add(cell);
}
}
}
break;
case ShowRegionType.DefenseRegion:
if (defenseRegionList != null)
{
foreach (var area in defenseRegionList)
{
if (area?.Positions == null) continue;
foreach (var cell in area.Positions)
{
points.Add(cell);
}
}
}
break;
case ShowRegionType.BlockRegion:
if (blockRegionList != null)
{
foreach (var area in blockRegionList)
{
if (area?.Positions == null) continue;
foreach (var cell in area.Positions)
{
points.Add(cell);
}
}
}
break;
}
return points.ToList();
2025-12-10 19:41:23 +08:00
}
#region 撤离相关
2025-12-10 19:41:23 +08:00
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/撤离相关")]
[VerticalGroup("地区相关/撤离相关/编辑")]
[LabelText("编辑撤离数据"), Indent]
[OnValueChanged("OnIsEditingRetreatChanged")]
public bool isEditingRetreat;
2025-12-10 19:41:23 +08:00
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/撤离相关")]
[LabelText("当前撤离数据"), Indent]
[ShowIf("isEditingRetreat")]
[ListDrawerSettings(CustomRemoveIndexFunction = "CustomRemoveRetreatPoint",
DraggableItems = false)]
public List<RetreatEditorInfo> retreatEditorInfo = new();
private void CustomRemoveRetreatPoint(int index)
{
if (index >= retreatEditorInfo.Count) return;
var point = retreatEditorInfo[index].retreatPoint;
_curMap.TerrainGridSystem.CellHideRegionSurface(point);
retreatEditorInfo.RemoveAt(index);
}
#endregion
#region 敌人撤离相关
2025-12-10 19:41:23 +08:00
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/敌人撤离相关")]
[LabelText("编辑敌人撤离数据"), Indent]
[OnValueChanged("OnIsEditingEnemyRetreatChanged")]
public bool isEditingEnemyRetreat;
private void OnIsEditingEnemyRetreatChanged()
{
if (isEditingEnemyRetreat)
return;
isEditingFallbackReusable = false;
}
private bool isEditingFallbackReusable;
2025-12-10 19:41:23 +08:00
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/敌人撤离相关")] [LabelText("当前撤离数据"), Indent] [ShowIf("isEditingEnemyRetreat")]
public EnemyRetreatEditorInfo enemyRetreatEditorInfo = new();
#endregion
#region 出战防守区
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/出战防守")] [LabelText("当前地区数据"), Indent]
public RegionData curRegionData = null;
#endregion
2025-05-28 17:49:04 +08:00
#region 占领相关
2023-08-22 19:08:45 +08:00
2025-12-10 17:39:34 +08:00
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/占领相关")] [VerticalGroup("地区相关/占领相关/编辑")] [LabelText("编辑占领区"), Indent]
public bool isEditingCapture = false;
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/占领相关")]
[VerticalGroup("地区相关/占领相关/编辑")]
[LabelText("编辑占领区"), Indent]
[ShowIf("isEditingCapture")]
public List<CaptureEditorInfo> captureEditorInfos = new();
2025-12-10 17:39:34 +08:00
#endregion
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
#region 扛旗相关
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/扛棋相关")] [LabelText("当前扛旗数据"), Indent]
public FlagEditorInfo flagEditorInfo = new();
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
#endregion
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
#region 雷区
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/雷区信息")]
[HorizontalGroup("地区相关/雷区信息/Region")]
[LabelText("编辑雷区"), Indent]
[OnValueChanged("OnCanEditorMinesAreaTypeChanged")]
[LabelWidth(100)]
[SerializeField]
private bool canEditorMinesArea;
2025-11-17 15:09:39 +08:00
2025-12-10 17:39:34 +08:00
private void OnCanEditorMinesAreaTypeChanged()
{
if (canEditorMinesArea)
2024-11-11 13:46:47 +08:00
{
canEditorBlockArea = false;
canEditorDefenseArea = false;
2025-12-10 17:39:34 +08:00
_isEditorSingleBlockRegion = false;
_isEditorSingleDefenseRegion = false;
ClearDefenseRegionColor();
ClearBlockRegionColor();
}
else
{
ClearMinesRegionColor();
SceneView.RepaintAll();
2025-12-10 17:39:34 +08:00
_isEditorSingleMinesRegion = false;
_currEditMinesRegionArea = null;
2024-11-11 13:46:47 +08:00
}
}
[FoldoutGroup("地区相关")]
[VerticalGroup("地区相关/雷区信息/RegionInfo"), Indent]
[LabelText("雷区列表")]
[ShowIf("canEditorMinesArea")]
[ListDrawerSettings(CustomAddFunction = "CustomAddMinesRegion",
CustomRemoveIndexFunction = "CustomRemoveMinesRegion",
DraggableItems = false)]
public List<MinesRegionArea> minesRegionList = new();
private void CustomAddMinesRegion()
2025-11-17 17:47:26 +08:00
{
var region = new LevelData.Region();
currentLevelData.minesRegions.Add(region);
UpdateMinesRegion();
2025-11-17 17:47:26 +08:00
}
private void CustomRemoveMinesRegion(int index)
2025-11-17 17:47:26 +08:00
{
ClearMinesRegionColor();
currentLevelData.minesRegions.RemoveAt(index);
UpdateMinesRegion();
2025-11-17 17:47:26 +08:00
}
2025-02-21 17:03:56 +08:00
#endregion
#region 阻挡区信息
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/阻挡区信息")]
[HorizontalGroup("地区相关/阻挡区信息/Region")]
[LabelText("编辑阻挡区"), Indent]
[OnValueChanged("OnCanEditorBlockAreaChanged")]
[LabelWidth(100)]
[SerializeField]
private bool canEditorBlockArea;
private void OnCanEditorBlockAreaChanged()
{
if (canEditorBlockArea)
{
canEditorMinesArea = false;
canEditorDefenseArea = false;
2025-12-10 17:39:34 +08:00
_isEditorSingleDefenseRegion = false;
ClearDefenseRegionColor();
ClearMinesRegionColor();
}
else
{
ClearBlockRegionColor();
SceneView.RepaintAll();
_currEditBlockRegion = null;
2025-12-10 17:39:34 +08:00
_isEditorSingleBlockRegion = false;
}
}
[FoldoutGroup("地区相关")]
[LabelText("阻挡区列表")]
[ShowIf("canEditorBlockArea")]
[VerticalGroup("地区相关/阻挡区信息/RegionInfo"), Indent]
[ListDrawerSettings(CustomAddFunction = "CustomAddBlockRegion",
CustomRemoveIndexFunction = "CustomRemoveBlockRegionIndex",
DraggableItems = false)]
public List<BlockRegionArea> blockRegionList = new();
private void CustomAddBlockRegion()
{
var region = new BlockRegion();
currentLevelData.blockRegions.Add(region);
UpdateBlockRegion();
}
private void CustomRemoveBlockRegionIndex(int index)
{
if (index < blockRegionList.Count)
{
if (blockRegionList[index].obj != null)
{
DebugUtil.LogError($"删除{blockRegionList[index].id}的指示");
DestroyImmediate(blockRegionList[index].obj);
}
}
ClearBlockRegionColor();
currentLevelData.blockRegions.RemoveAt(index);
UpdateBlockRegion();
}
#endregion
#region 刷怪触发区
[FoldoutGroup("地区相关")]
[BoxGroup("地区相关/刷怪触发区")]
[HorizontalGroup("地区相关/刷怪触发区/Region")]
[LabelText("编辑触发区"), Indent]
[OnValueChanged("OnCanEditorDefenseAreaChanged")]
[LabelWidth(100)]
[SerializeField]
private bool canEditorDefenseArea;
private void OnCanEditorDefenseAreaChanged()
{
if (canEditorDefenseArea)
{
canEditorBlockArea = false;
canEditorMinesArea = false;
2025-12-10 17:39:34 +08:00
_isEditorSingleBlockRegion = false;
ClearBlockRegionColor();
ClearMinesRegionColor();
}
else
{
ClearDefenseRegionColor();
SceneView.RepaintAll();
_currEditDefenseRegion = null;
2025-12-10 17:39:34 +08:00
_isEditorSingleDefenseRegion = false;
}
}
[FoldoutGroup("地区相关")]
[LabelText("刷怪触发区列表")]
[ShowIf("canEditorDefenseArea")]
[VerticalGroup("地区相关/刷怪触发区/RegionInfo"), Indent]
[ListDrawerSettings(CustomAddFunction = "CustomAddDefenseRegion",
CustomRemoveIndexFunction = "CustomRemoveDefenseRegion",
DraggableItems = false)]
public List<DefenseRegionArea> defenseRegionList = new();
private void CustomAddDefenseRegion()
{
var region = new LevelData.Region();
currentLevelData.defenseRegions.Add(region);
UpdateDefenseRegion();
}
private void CustomRemoveDefenseRegion(int index)
{
ClearDefenseRegionColor();
currentLevelData.defenseRegions.RemoveAt(index);
UpdateDefenseRegion();
}
2025-12-10 17:39:34 +08:00
#endregion
2025-02-21 17:03:56 +08:00
2025-05-28 17:49:04 +08:00
#endregion
2025-02-21 17:03:56 +08:00
#region 指定路线
2025-06-04 12:56:03 +08:00
[BoxGroup("制定路线")] [LabelText("编辑指定路径"), Indent]
2025-05-28 17:49:04 +08:00
public bool isEditingRoad;
2025-02-21 17:03:56 +08:00
2025-06-04 12:56:03 +08:00
[BoxGroup("制定路线")] [LabelText("编辑指定路线"), Indent] [ShowIf("isEditingRoad")]
public List<PrescribedRoadEditorInfo> roadEditorInfos = new();
2025-02-21 17:03:56 +08:00
#endregion
2025-06-26 15:25:35 +08:00
#region 指定区域
2025-12-10 13:23:32 +08:00
[BoxGroup("巡逻区域")] [LabelText("编辑巡逻区域"), Indent]
2025-06-26 15:25:35 +08:00
public bool isEditingArea;
2025-12-10 13:23:32 +08:00
[BoxGroup("巡逻区域")] [LabelText("编辑巡逻区域"), Indent] [ShowIf("isEditingArea")]
2025-06-26 15:25:35 +08:00
public List<PrescribedAreaEditorInfo> areaEditorInfos = new();
#endregion
2025-05-28 17:49:04 +08:00
#region 显示地图索引
2025-08-25 17:34:39 +08:00
[BoxGroup("显示地格索引")]
[LabelText("显示类型"), Indent]
[OnValueChanged("ShowCellIndex")]
2025-05-28 17:49:04 +08:00
[LabelWidth(100)]
[SerializeField]
2025-08-25 17:34:39 +08:00
private CellDebugInfo cellDebugInfo = CellDebugInfo.Nothing;
2025-08-25 17:34:39 +08:00
private void ShowCellIndex()
2024-11-04 18:19:57 +08:00
{
if (_curMap == null || _curMap.TerrainGridSystem == null) return;
2025-08-25 17:34:39 +08:00
_curMap.TerrainGridSystem.displayCellDebugInfo = cellDebugInfo;
2024-11-04 18:19:57 +08:00
var obj = FindObjectOfType<TerrainGridSystem>().gameObject;
Selection.activeGameObject = obj;
}
2025-05-28 17:49:04 +08:00
#endregion
2024-11-13 17:14:27 +08:00
#region 敌方Npc
2025-08-28 15:12:14 +08:00
private GameObject enemyObjRoot;
/// <summary>
/// 波次/怪物ID对应的NPC预制体
/// </summary>
2025-06-30 18:46:13 +08:00
private Dictionary<int, Dictionary<NpcEditorInfo, GameObject>> _enemyNpcObjectWaveDic;
2025-05-28 17:49:04 +08:00
[BoxGroup("敌方Npc")]
[LabelText("编辑NPC"), Indent]
[LabelWidth(100)]
[SerializeField]
2025-06-30 18:46:13 +08:00
[OnValueChanged("OnIsEditingEnemyNpcChanged")]
public bool isEditingEnemyNpc;
2024-11-18 16:50:35 +08:00
[BoxGroup("敌方Npc")] [LabelText("显示所有怪物序号ID"), Indent] [OnValueChanged("ShowAllEnemyNpcId")] [SerializeField]
2025-06-30 18:46:13 +08:00
public bool isShowAllEnemyNpcID;
2024-11-18 16:50:35 +08:00
[BoxGroup("敌方Npc")] [LabelText("筛选怪物ID"), Indent, LabelWidth(100)] [SerializeField] [ShowIf("isEditingEnemyNpc")]
2025-07-02 14:51:53 +08:00
public string selectEnemyMonsterId;
2025-05-28 17:49:04 +08:00
[BoxGroup("敌方Npc")]
2024-11-12 20:31:06 +08:00
[LabelText("怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
2025-06-30 18:46:13 +08:00
[OnValueChanged("EnemyMonsterIDChanged")]
[ValueDropdown("GetEnemyMonsterIDs")]
[ShowIf("isEditingEnemyNpc")]
2025-12-22 15:33:08 +08:00
public string curEnemyMonsterIDStr;
private int curEnemyMonsterID;
2025-05-28 17:49:04 +08:00
[BoxGroup("敌方Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
2025-06-30 18:46:13 +08:00
[LabelText("NPC预制体预览图"), ShowIf("isEditingEnemyNpc")]
public GameObject enemyNpcObject;
2023-12-21 12:48:58 +08:00
2025-12-10 18:54:43 +08:00
/// <summary>
/// 真实敌人列表
/// </summary>
2025-12-10 19:41:23 +08:00
[HideInInspector] public List<NpcEditorInfo> currentEnemyNpcInfo = null;
2024-11-12 20:31:06 +08:00
2025-12-22 15:33:08 +08:00
private IEnumerable<string> GetEnemyMonsterIDs()
{
2025-12-22 15:33:08 +08:00
if (string.IsNullOrEmpty(selectEnemyMonsterId))
return _allMonsterIDs.Keys;
_selectMonsterIDs.Clear();
foreach (var enemyMonster in _allMonsterIDs.Keys)
2025-07-02 14:51:53 +08:00
{
2025-12-22 15:33:08 +08:00
if (enemyMonster.Contains(selectEnemyMonsterId))
_selectMonsterIDs.Add(enemyMonster);
2025-07-02 14:51:53 +08:00
}
2025-12-22 15:33:08 +08:00
return _selectMonsterIDs;
}
2024-04-02 16:53:46 +08:00
2025-06-30 18:46:13 +08:00
private void EnemyMonsterIDChanged()
2023-12-21 12:48:58 +08:00
{
2025-12-22 15:33:08 +08:00
if (!_allMonsterIDs.TryGetValue(curEnemyMonsterIDStr, out var id))
return;
curEnemyMonsterID = id;
2025-06-30 18:46:13 +08:00
var obj = LoadEnemyNpcPrefab(curEnemyMonsterID);
2024-11-04 18:19:57 +08:00
if (obj != null)
2025-06-30 18:46:13 +08:00
enemyNpcObject = obj;
2024-11-04 18:19:57 +08:00
}
2023-12-21 12:48:58 +08:00
2025-06-30 18:46:13 +08:00
private void OnIsEditingEnemyNpcChanged()
2024-11-18 16:50:35 +08:00
{
2025-12-22 15:33:08 +08:00
if (isEditingEnemyNpc)
2025-06-30 18:46:13 +08:00
{
2024-11-18 16:50:35 +08:00
isEditingSelfNpc = false;
2025-06-30 18:46:13 +08:00
isEditingMidNpc = false;
2025-12-22 15:33:08 +08:00
return;
}
foreach (var npcEditorInfo in currentEnemyNpcInfo)
{
npcEditorInfo.isChangePos = false;
2025-06-30 18:46:13 +08:00
}
2025-12-29 14:41:29 +08:00
2025-12-22 15:49:23 +08:00
isEditingNpcPos = false;
2025-12-22 15:45:40 +08:00
currWindow._currNpcEditorInfo = null;
currWindow._currEditingNpcInfo = null;
2025-12-29 14:41:29 +08:00
2025-12-23 16:58:55 +08:00
// 清除所有组的高亮显示
2025-12-23 18:36:45 +08:00
ClearAllGroupHighlights();
2024-11-18 16:50:35 +08:00
}
2025-06-30 18:46:13 +08:00
private void ShowAllEnemyNpcId()
2024-11-04 18:19:57 +08:00
{
foreach (var npc in currentEnemyNpcInfo)
2024-09-05 13:26:43 +08:00
{
2025-06-30 18:46:13 +08:00
npc.isShowNpcID = isShowAllEnemyNpcID;
if (isShowAllEnemyNpcID)
2024-09-05 12:28:32 +08:00
{
2024-11-04 18:19:57 +08:00
if (!_showNpcInfos.Contains(npc))
2024-09-05 12:28:32 +08:00
{
2024-11-04 18:19:57 +08:00
_showNpcInfos.Add(npc);
2024-09-05 12:28:32 +08:00
}
}
2024-11-04 18:19:57 +08:00
else
{
2024-11-04 18:19:57 +08:00
_showNpcInfos.Remove(npc);
}
}
2023-12-21 12:48:58 +08:00
}
2025-12-10 19:41:23 +08:00
2025-12-29 14:41:29 +08:00
[BoxGroup("敌方Npc")]
[Button("保存"), ShowIf("isEditingEnemyNpc")]
private void SaveNewGroup()
{
if (enemyNpcGroups == null || enemyNpcGroups.Count == 0)
{
DebugUtil.LogWarning("没有分组需要保存");
return;
}
int changedCount = 0;
foreach (var group in enemyNpcGroups)
{
if (group != null)
{
group.ApplyGroupIdChange(false);
changedCount++;
}
}
// 所有修改完成后,统一刷新一次视图
RefreshEnemyNpcGroups();
}
2025-12-10 18:54:43 +08:00
/// <summary>
/// 敌方 NPC 的分组展示数据
/// </summary>
[BoxGroup("敌方Npc")]
[LabelText("按组查看怪物"), Indent, ShowIf("isEditingEnemyNpc")]
[ShowInInspector]
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, DraggableItems = false, ShowFoldout = true)]
public List<EnemyNpcGroupView> enemyNpcGroups = new();
2025-12-23 18:36:45 +08:00
/// <summary>
/// 清除所有组的高亮显示
/// </summary>
private void ClearAllGroupHighlights()
{
if (enemyNpcGroups == null)
return;
foreach (var group in enemyNpcGroups)
{
if (group != null)
{
// 强制清除高亮
group.ForceClearHighlight();
}
}
}
2024-11-12 20:31:06 +08:00
#endregion
2024-11-13 17:14:27 +08:00
#region 己方Npc
2024-11-12 20:31:06 +08:00
2025-12-29 14:41:29 +08:00
private const int SelfID = 800;
2025-05-28 17:49:04 +08:00
2025-08-28 15:12:14 +08:00
private GameObject selfObjRoot;
2025-05-28 17:49:04 +08:00
private Dictionary<Vector2Int, GameObject> _selfNpcObjectDic;
[BoxGroup("己方Npc")]
[LabelText("编辑己方NPC"), Indent]
[LabelWidth(100)]
[OnValueChanged("OnIsEditingSelfNpcChanged")]
[SerializeField]
2024-11-13 17:14:27 +08:00
public bool isEditingSelfNpc;
2024-11-12 20:31:06 +08:00
2025-05-28 17:49:04 +08:00
[BoxGroup("己方Npc")] [LabelText("显示所有己方序号ID"), Indent] [OnValueChanged("ShowAllSelfNpcId")] [SerializeField]
2024-11-18 16:50:35 +08:00
public bool isShowAllSelfNpcID;
[BoxGroup("己方Npc")] [LabelText("筛选怪物ID"), Indent, LabelWidth(100)] [SerializeField] [ShowIf("isEditingSelfNpc")]
2025-07-02 14:51:53 +08:00
public string selectSelfMonsterId;
2025-05-28 17:49:04 +08:00
[BoxGroup("己方Npc")]
2024-11-13 17:14:27 +08:00
[LabelText("己方NpcID"), Indent, LabelWidth(100)]
2024-11-12 20:31:06 +08:00
[SerializeField]
2024-11-13 17:14:27 +08:00
[OnValueChanged("SelfNpcIDChanged")]
[ValueDropdown("GetSelfNpcIDs")]
[ShowIf("isEditingSelfNpc")]
2025-12-22 15:33:08 +08:00
public string curSelfNpcIDStr;
private int curSelfNpcID;
2024-11-12 20:31:06 +08:00
2025-05-28 17:49:04 +08:00
[BoxGroup("己方Npc")]
2024-11-13 13:21:36 +08:00
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
2024-11-13 17:14:27 +08:00
[LabelText("己方NPC预制体预览图"), ShowIf("isEditingSelfNpc")]
public GameObject selfNpcObject;
2024-11-12 20:31:06 +08:00
2025-05-28 17:49:04 +08:00
[BoxGroup("己方Npc")]
2024-11-13 17:14:27 +08:00
[LabelText("当前己方NPC列表"), Indent, ShowIf("isEditingSelfNpc")]
2024-11-13 13:21:36 +08:00
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true)]
2024-11-18 16:50:35 +08:00
public List<NpcEditorInfo> currentSelfNpcInfo = null;
2024-11-12 20:31:06 +08:00
2025-12-22 15:33:08 +08:00
private IEnumerable<string> GetSelfNpcIDs()
2024-11-12 20:31:06 +08:00
{
2025-12-22 15:33:08 +08:00
if (string.IsNullOrEmpty(selectSelfMonsterId))
return _allMonsterIDs.Keys;
_selectMonsterIDs.Clear();
foreach (var enemyMonster in _allMonsterIDs.Keys)
2025-07-02 14:51:53 +08:00
{
2025-12-22 15:33:08 +08:00
if (enemyMonster.Contains(selectSelfMonsterId))
_selectMonsterIDs.Add(enemyMonster);
2025-07-02 14:51:53 +08:00
}
2025-12-22 15:33:08 +08:00
return _selectMonsterIDs;
2024-11-12 20:31:06 +08:00
}
2024-11-13 17:14:27 +08:00
private void SelfNpcIDChanged()
2024-11-12 20:31:06 +08:00
{
2025-12-22 15:33:08 +08:00
if (!_allMonsterIDs.TryGetValue(curSelfNpcIDStr, out var id))
return;
curSelfNpcID = id;
2024-11-13 17:14:27 +08:00
var obj = LoadSelfNpcPrefab(curSelfNpcID);
2024-11-12 20:31:06 +08:00
if (obj != null)
2024-11-13 17:14:27 +08:00
selfNpcObject = obj;
2024-11-12 20:31:06 +08:00
}
2024-11-18 16:50:35 +08:00
private void OnIsEditingSelfNpcChanged()
{
2025-12-22 15:33:08 +08:00
if (isEditingSelfNpc)
2025-06-30 18:46:13 +08:00
{
isEditingEnemyNpc = false;
isEditingMidNpc = false;
2025-12-22 15:33:08 +08:00
return;
}
foreach (var npcEditorInfo in currentSelfNpcInfo)
{
npcEditorInfo.isChangePos = false;
2025-06-30 18:46:13 +08:00
}
2025-12-29 14:41:29 +08:00
2025-12-22 15:49:23 +08:00
isEditingNpcPos = false;
2025-12-22 15:45:40 +08:00
currWindow._currNpcEditorInfo = null;
currWindow._currEditingNpcInfo = null;
2024-11-18 16:50:35 +08:00
}
private void ShowAllSelfNpcId()
{
foreach (var npc in currentSelfNpcInfo)
{
npc.isShowNpcID = isShowAllSelfNpcID;
if (isShowAllSelfNpcID)
{
if (!_showNpcInfos.Contains(npc))
{
_showNpcInfos.Add(npc);
}
}
else
{
_showNpcInfos.Remove(npc);
}
}
}
2024-11-12 20:31:06 +08:00
#endregion
2024-06-04 16:50:16 +08:00
2025-06-30 18:46:13 +08:00
#region 中立Npc
2025-12-29 14:41:29 +08:00
private const int MidID = 500;
2025-08-28 15:12:14 +08:00
private GameObject midObjRoot;
2025-06-30 14:51:47 +08:00
/// <summary>
2025-06-30 18:46:13 +08:00
/// 中立 波次/怪物ID对应的NPC预制体
2025-06-30 14:51:47 +08:00
/// </summary>
2025-06-30 18:46:13 +08:00
private Dictionary<int, Dictionary<NpcEditorInfo, GameObject>> _midNpcObjectWaveDic;
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
[BoxGroup("中立Npc")]
2025-12-22 15:33:08 +08:00
[LabelText("编辑中立NPC"), Indent]
2025-06-30 14:51:47 +08:00
[LabelWidth(100)]
[SerializeField]
2025-06-30 18:46:13 +08:00
[OnValueChanged("OnIsEditingMidNpcChanged")]
public bool isEditingMidNpc;
2025-06-30 14:51:47 +08:00
[BoxGroup("中立Npc")] [LabelText("显示所有怪物序号ID"), Indent] [OnValueChanged("ShowAllMidNpcId")] [SerializeField]
2025-06-30 18:46:13 +08:00
public bool isShowAllMidNpcID;
2025-06-30 14:51:47 +08:00
[BoxGroup("中立Npc")] [LabelText("筛选怪物ID"), Indent, LabelWidth(100)] [SerializeField] [ShowIf("isEditingMidNpc")]
2025-07-02 14:51:53 +08:00
public string selectMidMonsterId;
2025-06-30 18:46:13 +08:00
[BoxGroup("中立Npc")]
[LabelText("怪物ID"), Indent, LabelWidth(100)]
2025-06-30 14:51:47 +08:00
[SerializeField]
2025-06-30 18:46:13 +08:00
[OnValueChanged("MidMonsterIDChanged")]
[ValueDropdown("GetMidMonsterIDs")]
[ShowIf("isEditingMidNpc")]
2025-12-22 15:33:08 +08:00
public string curMidMonsterIDStr;
private int curMidMonsterID;
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
[BoxGroup("中立Npc")]
2025-06-30 14:51:47 +08:00
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
2025-06-30 18:46:13 +08:00
[LabelText("NPC预制体预览图"), ShowIf("isEditingMidNpc")]
public GameObject midNpcObject;
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
[BoxGroup("中立Npc")]
[LabelText("当前怪物列表"), Indent, ShowIf("isEditingMidNpc")]
2025-06-30 14:51:47 +08:00
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
2025-06-30 18:46:13 +08:00
public List<NpcEditorInfo> currentMidNpcInfo = null;
2025-06-30 14:51:47 +08:00
2025-12-22 15:33:08 +08:00
private IEnumerable<string> GetMidMonsterIDs()
2025-06-30 14:51:47 +08:00
{
2025-12-22 15:33:08 +08:00
if (string.IsNullOrEmpty(selectMidMonsterId))
return _allMonsterIDs.Keys;
_selectMonsterIDs.Clear();
foreach (var enemyMonster in _allMonsterIDs.Keys)
2025-07-02 14:51:53 +08:00
{
2025-12-22 15:33:08 +08:00
if (enemyMonster.Contains(selectMidMonsterId))
_selectMonsterIDs.Add(enemyMonster);
2025-07-02 14:51:53 +08:00
}
2025-12-22 15:33:08 +08:00
return _selectMonsterIDs;
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
private void MidMonsterIDChanged()
2025-06-30 14:51:47 +08:00
{
2025-12-22 15:33:08 +08:00
if (!_allMonsterIDs.TryGetValue(curMidMonsterIDStr, out var id))
return;
curMidMonsterID = id;
2025-06-30 18:46:13 +08:00
var obj = LoadMidNpcPrefab(curMidMonsterID);
if (obj != null)
midNpcObject = obj;
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
private void OnIsEditingMidNpcChanged()
2025-06-30 14:51:47 +08:00
{
2025-12-22 15:33:08 +08:00
if (isEditingMidNpc)
2025-06-30 18:46:13 +08:00
{
isEditingEnemyNpc = false;
2025-06-30 14:51:47 +08:00
isEditingSelfNpc = false;
2025-12-22 15:33:08 +08:00
return;
}
foreach (var npcEditorInfo in currentMidNpcInfo)
{
npcEditorInfo.isChangePos = false;
2025-06-30 18:46:13 +08:00
}
2025-12-22 15:49:23 +08:00
isEditingNpcPos = false;
2025-12-22 15:45:40 +08:00
currWindow._currNpcEditorInfo = null;
currWindow._currEditingNpcInfo = null;
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
private void ShowAllMidNpcId()
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
foreach (var npc in currentMidNpcInfo)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
npc.isShowNpcID = isShowAllMidNpcID;
if (isShowAllMidNpcID)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
if (!_showNpcInfos.Contains(npc))
{
_showNpcInfos.Add(npc);
}
2025-06-30 14:51:47 +08:00
}
else
2025-06-30 18:46:13 +08:00
{
_showNpcInfos.Remove(npc);
}
2025-06-30 14:51:47 +08:00
}
}
#endregion
#region 阻挡球编辑
2025-12-10 17:39:34 +08:00
[BoxGroup("攻击阻挡球")]
[HorizontalGroup("攻击阻挡球/Block")]
[LabelText("编辑攻击阻挡球"), Indent]
[OnValueChanged("OnCanEditorBlockSphereChanged")]
[LabelWidth(100)]
[SerializeField]
private bool canEditorBlockSphere;
2025-12-10 17:39:34 +08:00
private void OnCanEditorBlockSphereChanged()
{
2025-12-10 17:39:34 +08:00
if (canEditorBlockSphere)
{
2025-12-10 17:39:34 +08:00
showBuildings = false;
HideObjectsExcept();
2025-12-10 17:39:34 +08:00
blockSphereEditorList.Clear();
UpdateBlockSphereInfo();
foreach (var cellIndex in banAttackCells)
{
2025-12-10 17:39:34 +08:00
if (blockSphereInfo.TryGetValue(cellIndex, out var sphereInfo))
{
2025-12-10 17:39:34 +08:00
var sphere = CreateSphere(cellIndex, sphereInfo.offestPos, Vector3.one * sphereInfo.scale);
var blockEditorInfo = new BlockSpereEditorInfo(sphereInfo, sphere);
blockSphereEditorList.Add(blockEditorInfo);
}
2025-12-10 17:39:34 +08:00
else
{
2025-12-10 17:39:34 +08:00
var pos = _curMap.TGSCellIndex2WorldPosition(cellIndex);
var sphere = CreateSphere(cellIndex, pos, Vector3.one * Calibre);
var blockEditorInfo = new BlockSpereEditorInfo(cellIndex, sphere);
blockSphereEditorList.Add(blockEditorInfo);
}
}
2025-12-10 17:39:34 +08:00
editingBlockSphereList.Clear();
foreach (var editorInfo in blockSphereEditorList)
{
2025-12-10 17:39:34 +08:00
if (editorInfo.isChanged)
{
2025-12-10 17:39:34 +08:00
editingBlockSphereList.Add(editorInfo);
}
}
}
2025-12-10 17:39:34 +08:00
else
{
2025-12-10 17:39:34 +08:00
// 清理所有临时材质
foreach (var editorInfo in blockSphereEditorList)
{
2025-12-10 17:39:34 +08:00
if (editorInfo.editingMaterial != null)
{
2025-12-10 17:39:34 +08:00
if (editorInfo.sphere != null)
{
var renderer = editorInfo.sphere.GetComponent<Renderer>();
if (renderer != null)
{
renderer.sharedMaterial = editorInfo.originalSharedMaterial;
}
}
2025-12-10 17:39:34 +08:00
DestroyImmediate(editorInfo.editingMaterial);
}
}
2025-12-10 17:39:34 +08:00
showBuildings = true;
ShowHiddenObjects();
DestroyBlockSphere();
}
2025-12-10 17:39:34 +08:00
}
2025-12-10 17:39:34 +08:00
[LabelText("展示建筑")]
[HorizontalGroup("攻击阻挡球/BlockBuildings"), Indent]
[ShowIf("canEditorBlockSphere")]
[OnValueChanged("OnShowBuildingsChanged")]
public bool showBuildings;
2025-12-10 17:39:34 +08:00
private void OnShowBuildingsChanged()
{
if (showBuildings)
{
ShowHiddenObjects();
}
else
{
HideObjectsExcept();
}
}
[LabelText("添加地格")] [HorizontalGroup("攻击阻挡球/新数据"), Indent] [ShowIf("canEditorBlockSphere")]
public int addCellIndex;
[Button("添加编辑")]
[HorizontalGroup("攻击阻挡球/新数据/Add"), Indent]
[ShowIf("canEditorBlockSphere")]
public void AddBlockSphere()
{
if (!banAttackCells.Contains(addCellIndex))
{
EditorUtility.DisplayDialog("错误", $"地格 {addCellIndex} 不是攻击阻挡地格!", "确定");
return;
}
foreach (var blockSpereEditor in editingBlockSphereList)
{
if (blockSpereEditor.cellIndex == addCellIndex)
{
return;
}
}
foreach (var blockSpereEditor in blockSphereEditorList)
{
if (blockSpereEditor.cellIndex == addCellIndex)
{
editingBlockSphereList.Add(blockSpereEditor);
break;
}
}
}
[LabelText("阻挡球列表")]
[HorizontalGroup("攻击阻挡球/EditList"), Indent]
[ShowIf("canEditorBlockSphere")]
[ListDrawerSettings(HideAddButton = true, CustomRemoveIndexFunction = "CustomRemoveBlockSphereIndex")]
public List<BlockSpereEditorInfo> editingBlockSphereList = new();
[HideInInspector] public List<BlockSpereEditorInfo> blockSphereEditorList = new();
private void CustomRemoveBlockSphereIndex(int index)
{
if (index < editingBlockSphereList.Count)
{
editingBlockSphereList[index].Revert();
DebugUtil.Log($"删除并还原{editingBlockSphereList[index].cellIndex}的阻挡球编辑数据");
editingBlockSphereList.RemoveAt(index);
}
}
2025-12-10 17:39:34 +08:00
#endregion
2025-12-10 17:39:34 +08:00
#region 保存
2025-12-10 17:39:34 +08:00
[Button("保存当前关卡"), Indent]
private void SaveCurrentLevel()
{
2025-12-10 17:39:34 +08:00
CheckCorrectLevel();
2025-12-10 17:39:34 +08:00
if (!CheckTask())
return;
2026-01-04 13:40:25 +08:00
2025-12-10 17:39:34 +08:00
currentLevelData.taskInfos = taskInfos.Select(t => t.taskInfo).ToList();
2026-01-04 13:40:25 +08:00
ProcessCondition();
/*// 胜利失败星级条件
2025-12-10 17:39:34 +08:00
currentLevelData.successTaskID = successTaskID;
currentLevelData.failTaskID = failTaskID;
for (var i = 0; i < starTaskIDs.Count; i++)
{
2025-12-10 17:39:34 +08:00
currentLevelData.starTaskIDs[i] = starTaskIDs[i];
}*/
2025-12-10 17:39:34 +08:00
// 地区
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
2025-12-10 17:39:34 +08:00
// 评分关卡
currentLevelData.scoreTaskID = scoreTasks.Select(s => s.scoreTaskID).ToList();
//触发器
currentLevelData.levelTriggerDatas = levelTriggerData.Select(e => e.levelTriggerData).ToList();
2025-12-10 17:39:34 +08:00
#region 敌方NPC
2025-12-10 17:39:34 +08:00
foreach (var npcEditor in currentEnemyNpcInfo)
{
2025-12-10 17:39:34 +08:00
npcEditor.npcInfo.index = npcEditor.id;
}
2025-12-10 17:39:34 +08:00
currentLevelData.npcInfos = currentEnemyNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
2025-12-10 17:39:34 +08:00
#endregion
2025-12-29 19:07:03 +08:00
#region 波次信息
// 验证波次ID是否有重复且大于0
if (waveInfoEditors != null && waveInfoEditors.Count > 0)
{
var waveIdSet = new HashSet<int>();
foreach (var waveEditor in waveInfoEditors)
{
if (waveEditor.waveID <= 0)
{
EditorUtility.DisplayDialog("错误", $"波次ID必须大于0当前有波次ID为 {waveEditor.waveID}", "确定");
return;
}
2025-12-30 13:45:24 +08:00
2025-12-29 19:07:03 +08:00
if (!waveIdSet.Add(waveEditor.waveID))
{
EditorUtility.DisplayDialog("错误", $"波次ID {waveEditor.waveID} 重复,请修改后再保存!", "确定");
return;
}
}
}
// 更新所有敌方NPC的波次信息基于怪物组
foreach (var npc in currentEnemyNpcInfo)
{
bool inWave = false;
2025-12-30 13:45:24 +08:00
2025-12-29 19:07:03 +08:00
if (npc.npcInfo.groups != null && npc.npcInfo.groups.Count > 0)
{
// 检查该NPC的任何一个组是否在某个波次中
foreach (var wave in waveInfoEditors)
{
foreach (var groupId in npc.npcInfo.groups)
{
if (wave.enemies.Contains(groupId))
{
npc.npcInfo.waveIndex = wave.waveID;
npc.npcInfo.isHideOnLoad = true;
inWave = true;
break;
}
}
2025-12-30 13:45:24 +08:00
2025-12-29 19:07:03 +08:00
if (inWave) break;
}
}
// 如果不在任何波次中,清除波次信息
if (!inWave)
{
npc.npcInfo.waveIndex = 0;
npc.npcInfo.isHideOnLoad = false;
}
}
#endregion
2025-12-23 16:58:55 +08:00
#region 怪物组信息
// 保存敌方NPC的分组信息
currentLevelData.groupInfos.Clear();
if (enemyNpcGroups != null)
{
foreach (var groupView in enemyNpcGroups)
{
// 跳过"无编组怪物"组groupId为-1
if (groupView.groupId < 0)
continue;
var groupInfo = new GroupInfo
{
groupID = groupView.groupId,
groupName = groupView.groupName
};
currentLevelData.groupInfos.Add(groupInfo);
}
}
#endregion
2025-12-10 17:39:34 +08:00
#region 己方NPC
2025-12-10 17:39:34 +08:00
foreach (var npcFightEditorInfo in currentSelfNpcInfo)
{
2025-12-10 17:39:34 +08:00
npcFightEditorInfo.npcInfo.index = npcFightEditorInfo.id;
}
2025-12-10 17:39:34 +08:00
currentLevelData.selfNpcInfos =
currentSelfNpcInfo.Select(editorFightNpcInfo => editorFightNpcInfo.npcInfo).ToList();
2025-12-10 17:39:34 +08:00
#endregion
2025-12-10 17:39:34 +08:00
#region 中立NPC
2025-12-10 17:39:34 +08:00
foreach (var npcEditor in currentMidNpcInfo)
{
2025-12-10 17:39:34 +08:00
npcEditor.npcInfo.index = npcEditor.id;
}
2025-12-10 17:39:34 +08:00
currentLevelData.midNpcInfos = currentMidNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
2025-12-10 17:39:34 +08:00
#endregion
2025-12-10 17:39:34 +08:00
// 占领数据
currentLevelData.CapturePoints.Clear();
foreach (var captureInfo in captureEditorInfos)
{
2025-12-10 17:39:34 +08:00
var points = captureInfo.capturePointEditorInfos.Select(x => x.capturePoint).ToList();
var flagPoint = 0;
2025-12-10 17:39:34 +08:00
foreach (var pointData in captureInfo.capturePointEditorInfos)
{
2025-12-10 17:39:34 +08:00
if (pointData.captureFlag)
flagPoint = pointData.capturePoint;
}
2025-12-10 17:39:34 +08:00
var capture = new CaptureInfo
2025-11-17 15:09:39 +08:00
{
captureRegionID = captureInfo.captureRegionID,
capturePoints = points,
captureFlag = flagPoint,
CaptureProgress = captureInfo.captureProgress,
2025-11-17 15:09:39 +08:00
captureEffectID = captureInfo.captureEffectID,
captureEffectPoint = captureInfo.captureEffectPoint,
};
currentLevelData.CapturePoints.Add(capture);
}
// 扛旗数据
currentLevelData.flagStartPoints.Clear();
currentLevelData.flagEndPoints.Clear();
foreach (var flag in flagEditorInfo.flagStartPoints)
{
var cellIndex = _curMap.BlockPosition2TGSCellIndex(flag);
currentLevelData.flagStartPoints.Add(cellIndex);
}
foreach (var flag in flagEditorInfo.flagEndPoints)
{
var cellIndex = _curMap.BlockPosition2TGSCellIndex(flag);
currentLevelData.flagEndPoints.Add(cellIndex);
}
2024-11-11 13:46:47 +08:00
// 撤离数据
2025-11-17 17:47:26 +08:00
currentLevelData.retreatPoints.retreatPoints.Clear();
currentLevelData.retreatPoints.retreatFlag = -1;
foreach (var retreatPoint in retreatEditorInfo)
2024-11-11 13:46:47 +08:00
{
2025-11-17 17:47:26 +08:00
if (retreatPoint.retreatFlag)
currentLevelData.retreatPoints.retreatFlag = retreatPoint.retreatPoint;
currentLevelData.retreatPoints.retreatPoints.Add(retreatPoint.retreatPoint);
2024-11-11 13:46:47 +08:00
}
// 撤离数据
currentLevelData.enemyRetreatReusablePoints.Clear();
foreach (var fallback in enemyRetreatEditorInfo.fallbackReusablePoints)
{
var cellIndex = _curMap.BlockPosition2TGSCellIndex(fallback);
currentLevelData.enemyRetreatReusablePoints.Add(cellIndex);
}
2025-02-21 17:03:56 +08:00
// 指定路径
currentLevelData.patrolRoadData = roadEditorInfos.Select(editorInfo => new PatrolData
2025-02-21 17:03:56 +08:00
{
id = editorInfo.roadID,
patrolInfos = editorInfo.roadPoints,
2025-06-11 17:37:11 +08:00
}).ToList();
2025-02-21 17:03:56 +08:00
2025-06-26 15:25:35 +08:00
// 指定区域
currentLevelData.patrolRegionData = areaEditorInfos.Select(editorInfo => new PatrolData
{
id = editorInfo.areaID,
patrolInfos = editorInfo.areaPoints,
}).ToList();
2025-06-10 18:45:59 +08:00
// 关卡进度
2025-12-09 16:21:59 +08:00
currentLevelData.progressGuideDatas = progressGuideDatas.Select(p => p.progressGuideData).ToList();
2025-06-10 18:45:59 +08:00
// 立标数据
2025-12-09 16:21:59 +08:00
currentLevelData.setFlagGuideDatas = setFlagEditorInfos.Select(f => f.flagGuideData).ToList();
2025-06-10 18:45:59 +08:00
// 信息板数据
2025-12-09 16:21:59 +08:00
currentLevelData.infoPanelGuideDatas = infoPanelGuideDatas.Select(i => i.infoPanelGuideData).ToList();
2025-12-09 16:21:59 +08:00
// 关卡广播
currentLevelData.listAIBroadcastData = listAIBroadcastData.Select(a => a.aiBroadcastData).ToList();
2025-07-09 13:12:36 +08:00
// 阻挡球
SaveBlockSphereInfo();
2023-11-21 15:04:56 +08:00
_levelEditor.SaveLevelData();
_mapManager.SaveMapData();
2023-11-21 15:04:56 +08:00
}
2023-08-22 19:08:45 +08:00
#endregion
2025-05-28 17:49:04 +08:00
#region 关卡ID相关
2024-11-18 14:34:15 +08:00
2024-11-12 20:31:06 +08:00
/// <summary>
2025-05-28 17:49:04 +08:00
/// 关卡ID 通过关卡数据 json文件名 获得
2024-11-12 20:31:06 +08:00
/// </summary>
2025-05-28 17:49:04 +08:00
[LabelText("手动指定关卡ID"), Indent, LabelWidth(100), ShowIf("needManualInputLevelID")]
[InfoBox("无法正确获得关卡ID请手动指定")]
[SerializeField]
public string levelID;
2024-11-12 20:31:06 +08:00
/// <summary>
/// 需要手动输入关卡ID
/// </summary>
2024-11-18 16:50:35 +08:00
[HideInInspector] public bool needManualInputLevelID;
2025-12-09 19:01:17 +08:00
2025-05-28 17:49:04 +08:00
#endregion
2025-12-10 17:39:34 +08:00
#region Npc某些值改变时响应事件
2025-12-10 17:39:34 +08:00
private void ReorderEnemyNpcID()
2023-08-22 19:08:45 +08:00
{
2025-12-10 17:39:34 +08:00
for (var i = 0; i < currentEnemyNpcInfo.Count; i++)
{
2025-12-10 17:39:34 +08:00
currentEnemyNpcInfo[i].id = i + 1;
currentEnemyNpcInfo[i].npcInfo.index = currentEnemyNpcInfo[i].id;
}
2025-12-30 13:45:24 +08:00
2025-12-29 19:07:03 +08:00
// 注意波次存储的是怪物组ID不是NPC ID所以不需要更新波次信息
2025-12-10 17:39:34 +08:00
}
2025-12-10 17:39:34 +08:00
private void ReorderMidNpcID()
{
for (var i = 0; i < currentMidNpcInfo.Count; i++)
2024-11-11 13:46:47 +08:00
{
2025-12-29 14:41:29 +08:00
currentMidNpcInfo[i].id = MidID + i + 1;
2025-12-10 17:39:34 +08:00
currentMidNpcInfo[i].npcInfo.index = currentMidNpcInfo[i].id;
2024-11-11 13:46:47 +08:00
}
2025-12-10 17:39:34 +08:00
}
2024-11-11 13:46:47 +08:00
2025-12-10 17:39:34 +08:00
private void ReorderSelfNpcID()
{
for (var i = 0; i < currentSelfNpcInfo.Count; i++)
{
2025-12-10 17:39:34 +08:00
currentSelfNpcInfo[i].id = SelfID + i + 1;
}
}
2024-11-04 18:19:57 +08:00
2025-12-10 17:39:34 +08:00
private void ChangeEnemyNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
{
2025-12-10 17:39:34 +08:00
if (_enemyNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
{
2025-12-10 17:39:34 +08:00
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
2024-06-04 16:50:16 +08:00
{
2025-12-10 17:39:34 +08:00
var newObj = LoadEnemyNpcPrefab(newMonsterID);
if (newObj != null)
{
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
if (enemyObjRoot == null)
enemyObjRoot = new GameObject("enemyObjRoot");
if (obj != null)
obj.transform.SetParent(enemyObjRoot.transform);
2024-09-05 12:28:32 +08:00
2025-12-10 17:39:34 +08:00
npcEditorInfo.npcInfo.id = newMonsterID;
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
npcObjectDic[npcEditorInfo] = obj;
2025-06-30 18:46:13 +08:00
2025-12-10 17:39:34 +08:00
DestroyImmediate(npcObj);
DebugUtil.Log(
$"从[ {npcEditorInfo.npcInfo.position} ]的怪物ID改为:[ {npcEditorInfo.npcInfo.id} ]");
2025-06-30 18:46:13 +08:00
}
}
}
}
2025-12-10 17:39:34 +08:00
private void ChangeMidNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
2025-06-30 18:46:13 +08:00
{
2025-12-10 17:39:34 +08:00
if (_midNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
2025-06-30 18:46:13 +08:00
{
2025-12-10 17:39:34 +08:00
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
2025-06-30 18:46:13 +08:00
{
2025-12-10 17:39:34 +08:00
var newObj = LoadMidNpcPrefab(newMonsterID);
if (newObj != null)
{
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
2025-06-30 18:46:13 +08:00
2025-12-10 17:39:34 +08:00
if (midObjRoot == null)
midObjRoot = new GameObject("midObjRoot");
2024-11-18 16:50:35 +08:00
2025-12-10 17:39:34 +08:00
if (obj != null)
obj.transform.SetParent(midObjRoot.transform);
2025-08-28 15:12:14 +08:00
2025-12-10 17:39:34 +08:00
npcEditorInfo.npcInfo.id = newMonsterID;
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
npcObjectDic[npcEditorInfo] = obj;
DestroyImmediate(npcObj);
DebugUtil.Log(
$"从[ {npcEditorInfo.npcInfo.position} ]的怪物ID改为:[ {npcEditorInfo.npcInfo.id} ]");
}
2024-04-02 16:53:46 +08:00
}
}
}
2025-12-10 17:39:34 +08:00
private void ChangeSelfNpcID(NPCInfo npcInfoInfo, int newMonsterID)
2024-11-12 20:31:06 +08:00
{
2025-12-10 17:39:34 +08:00
if (_selfNpcObjectDic.TryGetValue(npcInfoInfo.position, out var npcObj))
2024-11-12 20:31:06 +08:00
{
2025-12-10 17:39:34 +08:00
var newObj = LoadSelfNpcPrefab(newMonsterID);
if (newObj != null)
2024-11-12 20:31:06 +08:00
{
2025-12-10 17:39:34 +08:00
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
2025-08-28 15:12:14 +08:00
if (selfObjRoot == null)
selfObjRoot = new GameObject("selfObjRoot");
if (obj != null)
obj.transform.SetParent(selfObjRoot.transform);
2025-12-10 17:39:34 +08:00
npcInfoInfo.id = newMonsterID;
_selfNpcObjectDic[npcInfoInfo.position] = obj;
2024-11-12 20:31:06 +08:00
DestroyImmediate(npcObj);
DebugUtil.Log("位置上[ {0} ]的fight怪物ID改为: [ {1} ] ", npcInfoInfo.position, npcInfoInfo.id);
}
}
}
2025-06-30 14:51:47 +08:00
#endregion
2023-08-22 19:08:45 +08:00
}