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

3487 lines
111 KiB
C#
Raw Normal View History

using TGS;
using System;
2023-08-22 19:08:45 +08:00
using Gameplay;
using Framework;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;
using Gameplay.Utils;
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-07 15:40:07 +08:00
using cfg;
2025-06-25 17:48:43 +08:00
using cfg.AICfg;
2024-11-18 16:50:35 +08:00
using cfg.FightCfg;
2025-06-10 18:45:59 +08:00
using cfg.GuideCfg;
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;
2025-06-30 18:46:13 +08:00
using Gameplay.Character;
2023-08-22 19:08:45 +08:00
public class LevelEditorWindow : OdinEditorWindow
{
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-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 关卡数据
2023-12-22 15:26:48 +08:00
2025-05-28 17:49:04 +08:00
[BoxGroup("当前关卡数据")] [LabelText("当前关卡数据"), Indent]
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-06-10 18:45:59 +08:00
#region 关卡进度
2025-06-11 13:31:37 +08:00
[BoxGroup("关卡引导")] [LabelText("关卡进度"), Indent]
2025-06-10 18:45:59 +08:00
public List<LevelData.ProgressGuideData> progressGuideDatas = new();
#endregion
#region 引导立标
[Serializable]
public class SetFlagGuideEditorInfo
{
public SetFlagGuideEditorInfo(LevelData.SetFlagGuideData flagGuideData)
{
this.flagGuideData = flagGuideData;
guideTagID = flagGuideData.guideTagID;
if (GuideTagConfig.DataMap.TryGetValue(guideTagID, out var guideData))
{
flagGuideData.guideTagPath = guideData.ImagePath;
guideTagName = guideData.Name;
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(guideData.ImagePath);
if (sprite != null)
guideTagSprite = sprite;
}
}
private GuideTagConfig GuideTagConfig => EditorTableManager.instance.tables.GuideTagConfig;
[HorizontalGroup("1")] [LabelText("立标配置ID")] [ValueDropdown("GetGuideTagIDs")] [OnValueChanged("ChangeTagID")]
public int guideTagID;
[HorizontalGroup("1")] [LabelText("立标名字")] [ReadOnly]
public string guideTagName;
[HorizontalGroup("2")] [LabelText("预览图")] [PreviewField(150, ObjectFieldAlignment.Center), Indent]
public Sprite guideTagSprite;
[HorizontalGroup("3")] [LabelText("具体数据")]
public LevelData.SetFlagGuideData flagGuideData;
private IEnumerable<int> GetGuideTagIDs()
{
return GuideTagConfig.DataMap.Keys;
}
private void ChangeTagID()
{
if (GuideTagConfig.DataMap.TryGetValue(guideTagID, out var guideData))
{
flagGuideData.guideTagPath = guideData.ImagePath;
flagGuideData.guideTagID = guideTagID;
guideTagName = guideData.Name;
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(guideData.ImagePath);
if (sprite != null)
guideTagSprite = sprite;
}
}
}
[BoxGroup("关卡引导")] [LabelText("立标数据"), Indent]
public List<SetFlagGuideEditorInfo> setFlagEditorInfos = new();
#endregion
#region 关卡进度
2025-06-11 13:31:37 +08:00
[BoxGroup("关卡引导")] [LabelText("信息板数据"), Indent]
2025-06-10 18:45:59 +08:00
public List<LevelData.InfoPanelGuideData> infoPanelGuideDatas = new();
#endregion
2025-07-08 20:07:21 +08:00
#region 关卡AI广播
[BoxGroup("关卡AI广播")] [LabelText("AI广播数据"), Indent]
2025-07-08 20:07:21 +08:00
public List<AIBroadcastData> listAIBroadcastData = new();
2025-07-08 20:07:21 +08:00
#endregion
2025-05-28 17:49:04 +08:00
#region 占领相关
2023-08-22 19:08:45 +08:00
[Serializable]
public class CaptureEditorInfo
{
[LabelText("占领点位")] public Vector2Int capturePoint;
[LabelText("占领时间")] public int captureProgress;
}
[BoxGroup("占领相关")] [VerticalGroup("占领相关/数据")] [LabelText("当前占领数据"), Indent]
2025-05-28 17:49:04 +08:00
public List<CaptureEditorInfo> captureEditorInfo = new();
[BoxGroup("占领相关")] [VerticalGroup("占领相关/编辑")] [LabelText("编辑占领数据"), Indent]
2025-05-28 17:49:04 +08:00
public bool isEditingCapture = false;
#endregion
#region 扛旗相关
[Serializable]
public class FlagEditorInfo
{
[LabelText("扛旗起点")] public List<Vector2Int> flagStartPoints = new();
[LabelText("扛旗终点")] public List<Vector2Int> flagEndPoints = new();
[LabelText("添加起点")] [OnValueChanged("EditingStartPoints")]
public bool isEditingStart;
[LabelText("添加终点")] [OnValueChanged("EditingEndPoints")]
public bool isEditingEnd;
private void EditingStartPoints()
{
currWindow.isEditingFlagStart = isEditingStart;
if (isEditingStart)
{
isEditingEnd = false;
currWindow.isEditingFlagEnd = false;
}
}
private void EditingEndPoints()
{
currWindow.isEditingFlagEnd = isEditingEnd;
if (isEditingEnd)
{
isEditingStart = false;
currWindow.isEditingFlagStart = false;
}
}
}
2025-05-28 17:49:04 +08:00
private bool isEditingFlagStart;
private bool isEditingFlagEnd;
[BoxGroup("扛棋相关")] [LabelText("当前扛旗数据"), Indent]
2025-05-28 17:49:04 +08:00
public FlagEditorInfo flagEditorInfo = new();
#endregion
#region 撤离相关
2024-11-11 13:46:47 +08:00
[Serializable]
public class FallbackEditorInfo
{
[LabelText("单次撤离点")] public List<Vector2Int> fallbackSinglePoints = new();
[LabelText("复用撤离点")] public List<Vector2Int> fallbackReusablePoints = new();
[LabelText("添加单次撤离点")] [OnValueChanged("EditingFallbackPoints")]
public bool isEditingSinglePoints;
[LabelText("添加复用撤离点")] [OnValueChanged("EditingMultiplexPoint")]
public bool isEditingReusablePoints;
private void EditingFallbackPoints()
{
currWindow.isEditingFallbackSingle = isEditingSinglePoints;
if (isEditingSinglePoints)
{
isEditingReusablePoints = false;
currWindow.isEditingFallbackReusable = false;
}
}
private void EditingMultiplexPoint()
{
currWindow.isEditingFallbackReusable = isEditingReusablePoints;
if (isEditingReusablePoints)
{
isEditingSinglePoints = false;
currWindow.isEditingFallbackSingle = false;
}
}
}
2025-05-28 17:49:04 +08:00
private bool isEditingFallbackSingle;
2025-02-21 17:03:56 +08:00
2025-05-28 17:49:04 +08:00
private bool isEditingFallbackReusable;
2025-02-21 17:03:56 +08:00
[BoxGroup("撤离相关")] [LabelText("当前撤离数据"), Indent]
2025-05-28 17:49:04 +08:00
public FallbackEditorInfo fallbackEditorInfo = new();
#endregion
2025-05-28 17:49:04 +08:00
#region 地区相关
2023-10-19 15:00:19 +08:00
2025-05-28 17:49:04 +08:00
[Serializable]
public class RegionData
{
[LabelText("出战区")] [OnValueChanged("OnRegionChanged")]
public int preparingRegionId;
2023-12-22 15:26:48 +08:00
2025-05-28 17:49:04 +08:00
[LabelText("出战区朝向")] public LevelData.CharacterToward preparingRegionToward;
2025-05-28 17:49:04 +08:00
[LabelText("撤退区")] public int fallbackRegionId;
2024-11-07 18:30:47 +08:00
2025-05-28 17:49:04 +08:00
[LabelText("敌方撤退区")] public int enemyFallbackRegionId;
2025-05-28 17:49:04 +08:00
[LabelText("PVP防守区")] public int pvpDefendRegionId;
2025-05-28 17:49:04 +08:00
[LabelText("PVP防守方朝向")] public LevelData.CharacterToward pvpDefendToward;
2025-05-28 17:49:04 +08:00
private void OnRegionChanged()
{
var regionsList = currWindow._curMap.MapData.regions;
for (int i = 0; i < regionsList.Count; i++)
{
currWindow._curMap.SetRegionColor(i, false, RegionColor);
}
2024-11-11 13:46:47 +08:00
2025-05-28 17:49:04 +08:00
currWindow._curMap.SetRegionColor(preparingRegionId, true, RegionColor);
}
2024-11-11 13:46:47 +08:00
}
2025-05-28 17:49:04 +08:00
[BoxGroup("地区相关")] [LabelText("当前地区数据"), Indent]
public RegionData curRegionData = null;
2023-12-22 15:26:48 +08:00
2025-05-28 17:49:04 +08:00
#endregion
#region NPC刷新点位相关
2024-11-04 18:19:57 +08:00
2025-05-28 17:49:04 +08:00
[HideInInspector] [BoxGroup("刷新点位")] [LabelText("编辑刷新点"), Indent, OnValueChanged("OnIsEditingRefreshIDChanged")]
2025-02-21 17:03:56 +08:00
public bool isEditingRefreshID;
2025-05-28 17:49:04 +08:00
[HideInInspector] [BoxGroup("刷新点位")] [LabelText("刷新点位"), Indent] [ShowIf("isEditingRefreshID")]
2025-02-21 17:03:56 +08:00
public List<int> refreshPoints = new List<int>();
private void OnIsEditingRefreshIDChanged()
{
if (!isEditingRefreshID)
{
foreach (var point in refreshPoints)
{
_curMap.TerrainGridSystem.CellHideRegionSurface(point);
}
}
else
{
foreach (var point in refreshPoints)
{
_curMap.TerrainGridSystem.CellToggleRegionSurface(point, true, RegionColor);
}
}
}
2025-05-28 17:49:04 +08:00
#endregion
2025-02-21 17:03:56 +08:00
#region 指定路线
2025-05-28 17:49:04 +08:00
[Serializable]
public class PrescribedRoadEditorInfo
{
[LabelText("路线ID")] public int roadID;
[LabelText("路线点位")] public List<PatrolInfo> roadPoints = new();
2025-05-28 17:49:04 +08:00
private bool isEditingRoadInfo;
public PrescribedRoadEditorInfo()
{
roadID = currWindow.roadEditorInfos.Count + 1;
}
[Button("开始编辑路线"), Indent]
[HideIf("isEditingRoadInfo")]
private void StartEditRoad()
{
isEditingRoadInfo = true;
currWindow.StartEditRoadInfo(this);
}
[Button("完成路线编辑"), Indent]
[ShowIf("isEditingRoadInfo")]
private void EndEditRoad()
{
isEditingRoadInfo = false;
currWindow.FinishEditRoadInfo();
}
}
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
private bool isEditingRoadInfo;
2025-05-28 17:49:04 +08:00
private PrescribedRoadEditorInfo _currEditingRoadInfo;
2025-02-21 17:03:56 +08:00
private void StartEditRoadInfo(PrescribedRoadEditorInfo roadInfo)
{
isEditingRoadInfo = true;
_currEditingRoadInfo = roadInfo;
}
private void FinishEditRoadInfo()
{
isEditingRoadInfo = false;
_currEditingRoadInfo = null;
}
#endregion
2025-06-26 15:25:35 +08:00
#region 指定区域
[Serializable]
public class PrescribedAreaEditorInfo
{
[LabelText("区域ID")] public int areaID;
[LabelText("区域点位")] public List<PatrolInfo> areaPoints = new();
private bool isEditingAreaInfo;
public PrescribedAreaEditorInfo()
{
areaID = currWindow.areaEditorInfos.Count + 1;
}
[Button("开始编辑区域"), Indent]
[HideIf("isEditingAreaInfo")]
private void StartEditArea()
{
isEditingAreaInfo = true;
currWindow.StartEditAreaInfo(this);
}
[Button("完成区域编辑"), Indent]
[ShowIf("isEditingAreaInfo")]
private void EndEditArea()
{
isEditingAreaInfo = false;
currWindow.FinishEditAreaInfo();
}
}
[BoxGroup("制定区域")] [LabelText("编辑指定区域"), Indent]
2025-06-26 15:25:35 +08:00
public bool isEditingArea;
[BoxGroup("制定区域")] [LabelText("编辑指定区域"), Indent] [ShowIf("isEditingArea")]
2025-06-26 15:25:35 +08:00
public List<PrescribedAreaEditorInfo> areaEditorInfos = new();
private bool isEditingAreaInfo;
private PrescribedAreaEditorInfo _currEditingAreaInfo;
private void StartEditAreaInfo(PrescribedAreaEditorInfo roadInfo)
{
isEditingAreaInfo = true;
_currEditingAreaInfo = roadInfo;
}
private void FinishEditAreaInfo()
{
isEditingAreaInfo = false;
_currEditingAreaInfo = null;
}
#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
#region NPC编辑器类
[Serializable]
public class NpcEditorInfo
{
2025-07-09 19:39:40 +08:00
private AITypeMonsterConfig AITypeCfg => EditorTableManager.instance.tables.AITypeMonsterConfig;
2025-06-25 17:48:43 +08:00
2025-06-30 18:46:13 +08:00
[HideInInspector] public int npcTroopId;
2025-05-28 17:49:04 +08:00
[ReadOnly] [LabelText("序号ID")] public int id;
2025-06-04 16:59:05 +08:00
[FoldoutGroup("详细信息")] [LabelText("MonsterID")] [ValueDropdown("GetMonsterIDs")] [OnValueChanged("ChangeNpcID")]
2025-05-28 17:49:04 +08:00
public int monsterId;
2025-06-25 12:13:54 +08:00
[FoldoutGroup("详细信息")] [LabelText("等级")] [ReadOnly]
public int level;
2025-05-28 17:49:04 +08:00
private IEnumerable<int> GetMonsterIDs()
{
2025-06-30 18:46:13 +08:00
return npcTroopId switch
{
ETroopsId.Neutral => currWindow.GetMidMonsterIDs(), // 中立
ETroopsId.Self => currWindow.GetSelfNpcIDs(), // 友方
2025-07-01 12:59:20 +08:00
ETroopsId.Enemy => currWindow.GetEnemyMonsterIDs(), // 敌人
2025-06-30 18:46:13 +08:00
_ => null
};
2025-05-28 17:49:04 +08:00
}
private void ChangeNpcID()
{
2025-06-30 18:46:13 +08:00
switch (npcTroopId)
{
2025-07-24 19:26:57 +08:00
case ETroopsId.Neutral: // 中立
2025-06-30 18:46:13 +08:00
currWindow.ChangeMidNpcID(this, monsterId);
break;
2025-07-24 19:26:57 +08:00
case ETroopsId.Self: // 友方
2025-06-30 18:46:13 +08:00
currWindow.ChangeSelfNpcID(npcInfo, monsterId);
break;
2025-07-24 19:26:57 +08:00
case ETroopsId.Enemy: // 敌人
2025-06-30 18:46:13 +08:00
currWindow.ChangeEnemyNpcID(this, monsterId);
break;
default:
DebugUtil.LogError($"未处理类型:{npcTroopId}");
break;
}
2025-05-28 17:49:04 +08:00
}
2025-06-04 16:59:05 +08:00
[FoldoutGroup("详细信息")] [LabelText("朝向")] [OnValueChanged("NpcTowardOnChange")]
2025-06-30 18:46:13 +08:00
public CharacterToward npcToward;
2025-05-28 17:49:04 +08:00
private void NpcTowardOnChange()
{
npcInfo.npcToward = npcToward;
2025-06-30 18:46:13 +08:00
switch (npcTroopId)
{
2025-07-24 19:26:57 +08:00
case ETroopsId.Neutral: // 中立
2025-06-30 18:46:13 +08:00
currWindow.ChangeMidNpcToward(this, npcToward);
break;
2025-07-24 19:26:57 +08:00
case ETroopsId.Self: // 友方
2025-06-30 18:46:13 +08:00
currWindow.ChangeSelfNpcToward(npcInfo.position, npcToward);
break;
2025-07-24 19:26:57 +08:00
case ETroopsId.Enemy: // 敌人
2025-06-30 18:46:13 +08:00
currWindow.ChangeEnemyNpcToward(this, npcToward);
break;
default:
DebugUtil.LogError($"未处理类型:{npcTroopId}");
break;
}
2025-05-28 17:49:04 +08:00
}
2025-06-30 18:46:13 +08:00
[FoldoutGroup("详细信息")] [HideLabel] public NPCInfo npcInfo;
2025-05-28 17:49:04 +08:00
2025-06-25 12:13:54 +08:00
[FoldoutGroup("详细信息")] [LabelText("AI预设")] [ReadOnly]
public string aiType;
2025-06-30 18:46:13 +08:00
public NpcEditorInfo(NPCInfo npcInfo, int index, int level, int aiType, int npcTroopId)
2025-05-28 17:49:04 +08:00
{
this.npcInfo = npcInfo;
2025-06-25 12:13:54 +08:00
this.level = level;
this.aiType = GetAITypeData(aiType);
2025-05-28 17:49:04 +08:00
monsterId = npcInfo.id;
id = index;
2025-06-30 18:46:13 +08:00
this.npcTroopId = npcTroopId;
2025-05-28 17:49:04 +08:00
npcToward = this.npcInfo.npcToward;
}
2025-06-04 16:59:05 +08:00
[FoldoutGroup("详细信息")] [LabelText("位置调整")] [OnValueChanged("ChangeNpcPos")]
2025-05-28 17:49:04 +08:00
public bool isChangePos;
private void ChangeNpcPos()
{
if (isChangePos)
{
if (currWindow._currEditingNpcInfo != null)
DebugUtil.LogWarning("检查其他怪物是否处于位置调整或编辑巡逻信息状态");
}
currWindow._currNpcEditorInfo = isChangePos ? this : null;
2025-05-28 17:49:04 +08:00
currWindow.isEditingNpcPos = isChangePos;
2025-06-30 18:46:13 +08:00
currWindow.npcTroopId = npcTroopId;
2025-05-28 17:49:04 +08:00
currWindow._currEditingNpcInfo = isChangePos ? npcInfo : null;
}
2025-06-04 16:59:05 +08:00
[FoldoutGroup("详细信息")] [LabelText("显示该怪物序号")] [OnValueChanged("ShowNpcID")]
2025-05-28 17:49:04 +08:00
public bool isShowNpcID;
private void ShowNpcID()
{
if (isShowNpcID && !currWindow._showNpcInfos.Contains(this))
currWindow._showNpcInfos.Add(this);
else if (!isShowNpcID)
{
currWindow._showNpcInfos.Remove(this);
}
}
2025-06-25 17:48:43 +08:00
private string GetAITypeData(int aiTypeID)
2025-06-25 12:13:54 +08:00
{
2025-06-25 17:48:43 +08:00
if (AITypeCfg.DataMap.TryGetValue(aiTypeID, out var dataAIType))
{
return dataAIType.Name;
}
return $"无效AI类型: {aiTypeID},请检查配置表";
2025-06-25 12:13:54 +08:00
}
2025-05-28 17:49:04 +08:00
}
2025-06-30 18:46:13 +08:00
private NPCInfo _currEditingNpcInfo;
private NpcEditorInfo _currNpcEditorInfo;
2025-05-28 17:49:04 +08:00
private bool isEditingNpcPos;
2025-06-30 18:46:13 +08:00
private int npcTroopId;
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")]
public 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-05-28 17:49:04 +08:00
[BoxGroup("敌方Npc")]
2025-06-30 18:46:13 +08:00
[LabelText("当前怪物列表"), Indent, ShowIf("isEditingEnemyNpc")]
2025-06-04 16:59:05 +08:00
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
public List<NpcEditorInfo> currentEnemyNpcInfo = null;
2024-11-12 20:31:06 +08:00
2025-05-28 17:49:04 +08:00
/// <summary>
/// 该关卡的敌方NPCID
/// </summary>
2025-06-30 18:46:13 +08:00
[HideInInspector] public List<int> enemyMonsterIDs;
2025-05-28 17:49:04 +08:00
2025-06-30 18:46:13 +08:00
private IEnumerable<int> GetEnemyMonsterIDs()
{
2025-07-02 14:51:53 +08:00
enemyMonsterIDs ??= new List<int>();
enemyMonsterIDs.Clear();
if (null == selectEnemyMonsterId)
return enemyMonsterIDs;
foreach (var monster in MonsterCfg.DataMap)
{
string strID = monster.Key.ToString();
if (!strID.StartsWith(selectEnemyMonsterId))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.EnemyCharacter:
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
enemyMonsterIDs.Add(monster.Key);
}
2025-07-02 14:51:53 +08:00
break;
case EMonsterType.SelfCharacter:
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
}
2025-06-30 18:46:13 +08:00
return enemyMonsterIDs;
}
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-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-06-30 18:46:13 +08:00
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
{
2024-11-18 16:50:35 +08:00
isEditingSelfNpc = false;
2025-06-30 18:46:13 +08:00
isEditingMidNpc = false;
}
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
}
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-05-28 17:49:04 +08:00
private const int SelfID = 200;
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")]
public 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-05-28 17:49:04 +08:00
/// <summary>
/// 该关卡的己方NPCID
/// </summary>
[HideInInspector] public List<int> selfMonsterIDs;
2024-11-13 17:14:27 +08:00
private IEnumerable<int> GetSelfNpcIDs()
2024-11-12 20:31:06 +08:00
{
2025-07-02 14:51:53 +08:00
selfMonsterIDs ??= new List<int>();
selfMonsterIDs.Clear();
if (null == selectSelfMonsterId)
return selfMonsterIDs;
foreach (var monster in MonsterCfg.DataMap)
{
string strID = monster.Key.ToString();
if (!strID.StartsWith(selectSelfMonsterId))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.SelfCharacter:
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
selfMonsterIDs.Add(monster.Key);
}
2025-07-02 14:51:53 +08:00
break;
case EMonsterType.EnemyCharacter:
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
}
2024-11-18 14:34:15 +08:00
return selfMonsterIDs;
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
{
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-06-30 18:46:13 +08:00
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
{
isEditingEnemyNpc = false;
isEditingMidNpc = false;
}
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-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")]
[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")]
public 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
/// <summary>
2025-06-30 18:46:13 +08:00
/// 该关卡的中立NPCID
2025-06-30 14:51:47 +08:00
/// </summary>
2025-06-30 18:46:13 +08:00
[HideInInspector] public List<int> midMonsterIDs;
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
private IEnumerable<int> GetMidMonsterIDs()
2025-06-30 14:51:47 +08:00
{
2025-07-02 14:51:53 +08:00
midMonsterIDs ??= new List<int>();
midMonsterIDs.Clear();
if (null == selectMidMonsterId)
return midMonsterIDs;
foreach (var monster in MonsterCfg.DataMap)
{
string strID = monster.Key.ToString();
if (!strID.StartsWith(selectMidMonsterId))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
midMonsterIDs.Add(monster.Key);
}
2025-07-02 14:51:53 +08:00
break;
case EMonsterType.EnemyCharacter:
case EMonsterType.SelfCharacter:
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
}
2025-06-30 18:46:13 +08:00
return midMonsterIDs;
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-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-06-30 18:46:13 +08:00
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
{
isEditingEnemyNpc = false;
2025-06-30 14:51:47 +08:00
isEditingSelfNpc = false;
2025-06-30 18:46:13 +08:00
}
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 阻挡球编辑
/// <summary>
/// 球体根节点
/// </summary>
private GameObject blockSphereRoot;
/// <summary>
/// 已修改阻挡球字典
/// </summary>
private readonly Dictionary<int, MapData.BlockSphereInfo> blockSphereInfo = new();
/// <summary>
/// 被隐藏的物体列表,用于后续恢复显示
/// </summary>
private readonly List<GameObject> hideObjs = new List<GameObject>();
/// <summary>
/// 所有禁止攻击的格子
/// </summary>
private readonly List<int> banAttackCells = new();
/// <summary>
/// 标准六边形内接圆直径
/// </summary>
private static readonly float Calibre = 3f;
/// <summary>
/// 编辑时颜色
/// </summary>
private static readonly Color EditingSphereColor = Color.red;
/// <summary>
/// 已编辑过的数据颜色
/// </summary>
private static readonly Color ChangedSphereColor = Color.green;
[Serializable]
public class BlockSpereEditorInfo
{
[HideInInspector] public MapData.BlockSphereInfo blockSphereInfo;
#region 可视字段
[HorizontalGroup("1", 0.1f)] [LabelText("地格")] [LabelWidth(30)] [ReadOnly]
public int cellIndex;
[HorizontalGroup("1", 0.12f)]
[LabelText("缩放")]
[LabelWidth(30)]
[EnableIf("canEditor")]
[ShowIf("@isChanged||canEditor")]
[OnValueChanged("OnScaleValueChanged")]
public float scale = 1f;
[HorizontalGroup("1", 0.25f)]
[LabelText("偏移")]
[LabelWidth(30)]
[EnableIf("canEditor")]
[ShowIf("@isChanged||canEditor")]
[OnValueChanged("OnOffestValueChanged")]
public Vector2 offest;
[HorizontalGroup("1", 0.25f)]
[LabelText("备注")]
[LabelWidth(30)]
[EnableIf("canEditor")]
// [ShowIf("@isChanged||canEditor")]
[OnValueChanged("OnNoteValueChanged")]
public string note;
#endregion
#region 字段
/// <summary>
/// 可编辑
/// </summary>
[HideInInspector] public bool canEditor;
/// <summary>
/// 数据已经变化
/// </summary>
[HideInInspector] public bool isChanged;
/// <summary>
/// 阻挡球物体
/// </summary>
[HideInInspector] public GameObject sphere;
/// <summary>
/// 原始共享材质
/// </summary>
[HideInInspector] public Material originalSharedMaterial;
/// <summary>
/// 编辑时的临时材质
/// </summary>
[HideInInspector] public Material editingMaterial;
/// <summary>
/// 地格中心位置
/// </summary>
[HideInInspector] public Vector3 originalPos;
#endregion
#region 构造函数
public BlockSpereEditorInfo(int cellIndex, GameObject sphere)
{
var map = currWindow._curMap;
this.cellIndex = cellIndex;
blockSphereInfo = new MapData.BlockSphereInfo()
{
cellIndex = cellIndex,
};
originalPos = map.TGSCellIndex2WorldPosition(cellIndex);
if (sphere != null)
{
this.sphere = sphere;
SetSphereColor(Color.white);
}
isChanged = false;
}
public BlockSpereEditorInfo(MapData.BlockSphereInfo blockInfo, GameObject sphere)
{
var map = currWindow._curMap;
blockSphereInfo = new MapData.BlockSphereInfo
{
cellIndex = blockInfo.cellIndex,
scale = blockInfo.scale,
note = blockInfo.note,
offestPos = blockInfo.offestPos,
};
cellIndex = blockInfo.cellIndex;
originalPos = map.TGSCellIndex2WorldPosition(blockInfo.cellIndex);
offest = new Vector2(blockInfo.offestPos.x - originalPos.x, blockInfo.offestPos.z - originalPos.z);
scale = blockInfo.scale / Calibre;
if (sphere != null)
{
this.sphere = sphere;
}
UpdateChangedData();
}
#endregion
#region 按钮
[Button("恢复默认")]
[HorizontalGroup("1")]
[ShowIf("isChanged")]
public void Revert()
{
if (!isChanged) return;
isChanged = false;
if (sphere != null)
{
scale = 1f;
offest = new Vector2(0f, 0f);
blockSphereInfo.offestPos = originalPos;
blockSphereInfo.scale = Calibre;
sphere.transform.localScale = Vector3.one * Calibre;
sphere.transform.position = originalPos;
// 如果正在监听这个球体,更新监听的位置和缩放
if (currWindow.currentEditingSphere == this)
{
currWindow.lastPosition = originalPos;
currWindow.lastScale = Vector3.one * Calibre;
}
if (!canEditor)
{
SetSphereColor(Color.white);
}
}
}
[Button("编辑")]
[HorizontalGroup("1")]
[HideIf("canEditor")]
private void EditorBlockAttack()
{
canEditor = true;
if (sphere != null)
{
var renderer = sphere.GetComponent<Renderer>();
// 保存原始材质(可能已经是绿色的编辑过材质)
originalSharedMaterial = renderer.sharedMaterial;
// 创建编辑用的红色材质
editingMaterial = new Material(originalSharedMaterial);
editingMaterial.color = EditingSphereColor;
renderer.sharedMaterial = editingMaterial;
if (currWindow.currentEditingSphere != null)
{
currWindow.currentEditingSphere.ExitEditorBlockAttack();
}
Selection.activeGameObject = sphere;
currWindow.StartMonitoringSphere(this);
}
}
[Button("保存")]
[HorizontalGroup("1")]
[ShowIf("canEditor")]
public void ExitEditorBlockAttack()
{
canEditor = false;
if (sphere != null)
{
var renderer = sphere.GetComponent<Renderer>();
// 清理临时材质并恢复原始材质
if (editingMaterial != null)
{
DestroyImmediate(editingMaterial);
editingMaterial = null;
}
// 恢复原始材质
if (originalSharedMaterial != null)
{
renderer.sharedMaterial = originalSharedMaterial;
}
blockSphereInfo.scale = Calibre * scale;
blockSphereInfo.offestPos = sphere.transform.position;
DebugUtil.Log(
$"保存 {blockSphereInfo.cellIndex} 上的阻挡攻击球体真实直径为: {blockSphereInfo.scale}, 具体位置为: {blockSphereInfo.offestPos}, " +
$"原始的位置是:{originalPos}, 原始直径是:{Calibre}");
UpdateChangedData();
}
// 停止监听Transform变化
currWindow.StopMonitoringSphere();
}
#endregion
#region 值变化
private void OnScaleValueChanged()
{
var realScale = Calibre * scale;
if (sphere != null)
{
sphere.transform.localScale = Vector3.one * realScale;
}
UpdateChangedData();
}
private void OnOffestValueChanged()
{
var realOffestX = offest.x + originalPos.x;
var realOffestZ = offest.y + originalPos.z;
var newPos = new Vector3(realOffestX, 0f, realOffestZ);
if (sphere != null)
{
sphere.transform.position = newPos;
}
UpdateChangedData();
}
private void OnNoteValueChanged()
{
blockSphereInfo.note = note;
}
public void UpdateChangedData()
{
isChanged = offest != Vector2.zero ||
!Mathf.Approximately(1f, scale);
// 如果状态发生变化且不在编辑状态,更新球体颜色
if (!canEditor && sphere != null)
{
SetSphereColor(isChanged ? ChangedSphereColor : Color.white);
}
}
/// <summary>
/// 设置球体颜色
/// </summary>
private void SetSphereColor(Color color)
{
if (sphere == null) return;
var renderer = sphere.GetComponent<Renderer>();
if (renderer != null)
{
if (!canEditor)
{
if (renderer.sharedMaterial != null)
{
var material = new Material(renderer.sharedMaterial);
material.color = color;
renderer.sharedMaterial = material;
}
}
}
}
#endregion
}
[BoxGroup("攻击阻挡球")]
[HorizontalGroup("攻击阻挡球/Block")]
[LabelText("编辑攻击阻挡球"), Indent]
[OnValueChanged("OnCanEditorBlockSphereChanged")]
[LabelWidth(100)]
[SerializeField]
private bool canEditorBlockSphere;
private void OnCanEditorBlockSphereChanged()
{
if (canEditorBlockSphere)
{
showBuildings = false;
HideObjectsExcept();
blockSphereEditorList.Clear();
UpdateBlockSphereInfo();
foreach (var cellIndex in banAttackCells)
{
if (blockSphereInfo.TryGetValue(cellIndex, out var sphereInfo))
{
var sphere = CreateSphere(cellIndex, sphereInfo.offestPos, Vector3.one * sphereInfo.scale);
var blockEditorInfo = new BlockSpereEditorInfo(sphereInfo, sphere);
blockSphereEditorList.Add(blockEditorInfo);
}
else
{
var pos = _curMap.TGSCellIndex2WorldPosition(cellIndex);
var sphere = CreateSphere(cellIndex, pos, Vector3.one * Calibre);
var blockEditorInfo = new BlockSpereEditorInfo(cellIndex, sphere);
blockSphereEditorList.Add(blockEditorInfo);
}
}
editingBlockSphereList.Clear();
foreach (var editorInfo in blockSphereEditorList)
{
if (editorInfo.isChanged)
{
editingBlockSphereList.Add(editorInfo);
}
}
}
else
{
// 清理所有临时材质
foreach (var editorInfo in blockSphereEditorList)
{
if (editorInfo.editingMaterial != null)
{
if (editorInfo.sphere != null)
{
var renderer = editorInfo.sphere.GetComponent<Renderer>();
if (renderer != null)
{
renderer.sharedMaterial = editorInfo.originalSharedMaterial;
}
}
DestroyImmediate(editorInfo.editingMaterial);
}
}
showBuildings = true;
ShowHiddenObjects();
DestroyBlockSphere();
}
}
/// <summary>
/// 更新阻挡球信息
/// </summary>
private void UpdateBlockSphereInfo()
{
blockSphereInfo.Clear();
GetAllBanAttackCell();
2025-09-03 14:43:56 +08:00
foreach (var blockInfo in currentLevelData.BlockSphereInfos)
{
blockSphereInfo[blockInfo.cellIndex] = blockInfo;
}
}
/// <summary>
/// 获取所有禁止攻击地格
/// </summary>
private void GetAllBanAttackCell()
{
banAttackCells.Clear();
GetAllBanAttackBuildings();
}
/// <summary>
/// 获取所有禁止攻击建筑地格
/// </summary>
private void GetAllBanAttackBuildings()
{
AddBanAttackBuildings(currentEnemyNpcInfo);
AddBanAttackBuildings(currentMidNpcInfo);
AddBanAttackBuildings(currentSelfNpcInfo);
}
/// <summary>
/// 获取禁止攻击建筑地格
/// </summary>
private void AddBanAttackBuildings(List<NpcEditorInfo> npcList)
{
foreach (var npcEditorInfo in npcList)
{
if (!MonsterCfg.DataMap.TryGetValue(npcEditorInfo.monsterId, out var dataMonster)) continue;
if (dataMonster.NpcType != EMonsterType.FightBuild) continue;
if (!FightBuildCfg.DataMap.TryGetValue(dataMonster.MonsterClassID, out var dataFight)) continue;
if (!dataFight.IsReplaceBlockAttack || !dataFight.BlockAttack) continue;
var cellIndex = _curMap.BlockPosition2TGSCellIndex(npcEditorInfo.npcInfo.position);
if (!banAttackCells.Contains(cellIndex))
banAttackCells.Add(cellIndex);
DebugUtil.Log($"能阻挡攻击的建筑{dataMonster.MonsterClassID}所在地格是{cellIndex}");
}
}
[LabelText("展示建筑")]
[HorizontalGroup("攻击阻挡球/BlockBuildings"), Indent]
[ShowIf("canEditorBlockSphere")]
[OnValueChanged("OnShowBuildingsChanged")]
public bool showBuildings;
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);
}
}
/// <summary>
/// 创建球体
/// </summary>
private GameObject CreateSphere(int cellIndex, Vector3 pos, Vector3 scale)
{
var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = pos;
sphere.transform.localScale = scale;
if (blockSphereRoot == null)
blockSphereRoot = new GameObject("blockSphereRoot");
sphere.transform.SetParent(blockSphereRoot.transform);
sphere.name = "sphere" + cellIndex;
return sphere;
}
private void DestroyBlockSphere()
{
DestroyImmediate(blockSphereRoot);
}
/// <summary>
/// 保存数据
/// </summary>
private void SaveBlockSphereInfo()
{
2025-09-03 14:43:56 +08:00
currentLevelData.BlockSphereInfos.Clear();
foreach (var blockSpereEditor in editingBlockSphereList)
{
2025-09-03 14:43:56 +08:00
currentLevelData.BlockSphereInfos.Add(blockSpereEditor.blockSphereInfo);
}
}
/// <summary>
/// 加载数据
/// </summary>
private void LoadBlockSphereInfo()
{
blockSphereInfo.Clear();
2025-09-03 14:43:56 +08:00
foreach (var blockInfo in currentLevelData.BlockSphereInfos)
{
blockSphereInfo[blockInfo.cellIndex] = blockInfo;
}
}
#region Sphere物体编辑器监听
/// <summary>
/// 当前正在编辑的球体信息
/// </summary>
[HideInInspector] public BlockSpereEditorInfo currentEditingSphere;
/// <summary>
/// 上次记录的位置
/// </summary>
[HideInInspector] public Vector3 lastPosition;
/// <summary>
/// 上次记录的缩放
/// </summary>
[HideInInspector] public Vector3 lastScale;
/// <summary>
/// 开始监听球体Transform变化
/// </summary>
private void StartMonitoringSphere(BlockSpereEditorInfo editorInfo)
{
currentEditingSphere = editorInfo;
if (editorInfo.sphere != null)
{
lastPosition = editorInfo.sphere.transform.position;
lastScale = editorInfo.sphere.transform.localScale;
// 注册编辑器更新回调
EditorApplication.update += OnEditorUpdate;
}
}
/// <summary>
/// 停止监听球体Transform变化
/// </summary>
private void StopMonitoringSphere()
{
currentEditingSphere = null;
EditorApplication.update -= OnEditorUpdate;
}
/// <summary>
/// 编辑器更新回调
/// </summary>
private void OnEditorUpdate()
{
if (currentEditingSphere?.sphere == null || !currentEditingSphere.canEditor)
{
StopMonitoringSphere();
return;
}
var sphere = currentEditingSphere.sphere;
var transform = sphere.transform;
// 检查位置变化
if (Vector3.Distance(transform.position, lastPosition) > 0.001f)
{
// 锁定Y轴
var newPos = transform.position;
newPos.y = 0f;
transform.position = newPos;
// 更新偏移值
var offsetX = newPos.x - currentEditingSphere.originalPos.x;
var offsetZ = newPos.z - currentEditingSphere.originalPos.z;
currentEditingSphere.offest = new Vector2(offsetX, offsetZ);
lastPosition = newPos;
// 标记为已修改
currentEditingSphere.UpdateChangedData();
}
// 检查缩放变化
if (Vector3.Distance(transform.localScale, lastScale) > 0.001f)
{
var newScale = transform.localScale.x;
transform.localScale = Vector3.one * newScale;
currentEditingSphere.scale = newScale / Calibre;
lastScale = transform.localScale;
currentEditingSphere.UpdateChangedData();
}
}
#endregion
#region 物体隐藏/显示管理
/// <summary>
/// 需要隐藏的物体节点名字
/// </summary>
private readonly List<string> hideObjsRoot = new()
{
2025-08-28 15:12:14 +08:00
"Art", "BackGround", "Buildings", "enemyObjRoot", "midObjRoot", "selfObjRoot"
};
/// <summary>
/// 不需要隐藏的物体节点名字
/// </summary>
private readonly List<string> noHideObjsRoot = new()
{
"Ground", "Ground2", "Lights", "Fog", "Global Volume", "Effects"
};
/// <summary>
/// 隐藏指定节点下的物体(排除白名单中的物体)
/// </summary>
public void HideObjectsExcept()
{
if (hideObjsRoot == null || hideObjsRoot.Count == 0)
{
return;
}
// 清空之前的隐藏物体列表
hideObjs.Clear();
foreach (string nodeName in hideObjsRoot)
{
GameObject node = GameObject.Find(nodeName);
if (node == null)
{
continue;
}
HideChildrenRecursively(node.transform, noHideObjsRoot);
}
}
/// <summary>
/// 递归隐藏子物体
/// </summary>
/// <param name="parent">父级Transform</param>
/// <param name="excludeNames">排除的物体名列表</param>
private void HideChildrenRecursively(Transform parent, List<string> excludeNames)
{
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
GameObject childObj = child.gameObject;
// 检查是否在排除列表中(完全匹配)
bool shouldExclude = false;
if (excludeNames != null)
{
foreach (string excludeName in excludeNames)
{
if (childObj.name.Equals(excludeName, System.StringComparison.OrdinalIgnoreCase))
{
shouldExclude = true;
break;
}
}
}
if (shouldExclude)
{
continue;
}
else
{
// 不在排除列表中,隐藏此物体
if (childObj.activeSelf)
{
childObj.SetActive(false);
hideObjs.Add(childObj);
}
// 继续递归处理子物体
HideChildrenRecursively(child, excludeNames);
}
}
}
/// <summary>
/// 显示之前隐藏的所有物体
/// </summary>
private void ShowHiddenObjects()
{
if (hideObjs == null || hideObjs.Count == 0)
{
return;
}
for (int i = hideObjs.Count - 1; i >= 0; i--)
{
GameObject obj = hideObjs[i];
// 检查物体是否仍然存在(可能已被删除)
if (obj != null)
{
obj.SetActive(true);
}
hideObjs.RemoveAt(i);
}
}
#endregion
2025-06-30 14:51:47 +08:00
#endregion
#region 保存
2024-06-04 16:50:16 +08:00
[Button("保存当前关卡"), Indent]
2023-08-22 19:08:45 +08:00
private void SaveCurrentLevel()
{
CheckCorrectLevel();
// 地区
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
currentLevelData.fallbackRegionId = curRegionData.fallbackRegionId;
currentLevelData.enemyFallbackRegionId = curRegionData.enemyFallbackRegionId;
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
2023-12-26 18:19:05 +08:00
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
2024-11-07 15:50:33 +08:00
2025-06-30 18:46:13 +08:00
#region 敌方NPC
foreach (var npcEditor in currentEnemyNpcInfo)
2024-11-07 13:09:27 +08:00
{
npcEditor.npcInfo.index = npcEditor.id;
}
2024-11-13 17:14:27 +08:00
currentLevelData.npcInfos = currentEnemyNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
2025-06-30 18:46:13 +08:00
#endregion
2024-11-18 16:50:35 +08:00
2025-06-30 18:46:13 +08:00
#region 己方NPC
2024-11-13 17:14:27 +08:00
foreach (var npcFightEditorInfo in currentSelfNpcInfo)
2024-11-13 13:21:36 +08:00
{
npcFightEditorInfo.npcInfo.index = npcFightEditorInfo.id;
}
2024-11-13 17:14:27 +08:00
currentLevelData.selfNpcInfos =
currentSelfNpcInfo.Select(editorFightNpcInfo => editorFightNpcInfo.npcInfo).ToList();
2025-06-30 18:46:13 +08:00
#endregion
2024-11-12 20:31:06 +08:00
2025-06-30 18:46:13 +08:00
#region 中立NPC
2025-06-30 18:46:13 +08:00
foreach (var npcEditor in currentMidNpcInfo)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
npcEditor.npcInfo.index = npcEditor.id;
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
currentLevelData.midNpcInfos = currentMidNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
2025-06-30 18:46:13 +08:00
#endregion
2025-06-30 14:51:47 +08:00
// 占领数据
currentLevelData.CapturePoints.Clear();
foreach (var captureInfo in captureEditorInfo)
{
var capture = new LevelData.CaptureInfo
{
CapturePoint = _curMap.BlockPosition2TGSCellIndex(captureInfo.capturePoint),
CaptureProgress = captureInfo.captureProgress,
};
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
// 撤离数据
currentLevelData.fallbackSinglePoints.Clear();
currentLevelData.fallbackReusablePoints.Clear();
foreach (var fallback in fallbackEditorInfo.fallbackSinglePoints)
{
var cellIndex = _curMap.BlockPosition2TGSCellIndex(fallback);
currentLevelData.fallbackSinglePoints.Add(cellIndex);
}
foreach (var fallback in fallbackEditorInfo.fallbackReusablePoints)
{
var cellIndex = _curMap.BlockPosition2TGSCellIndex(fallback);
currentLevelData.fallbackReusablePoints.Add(cellIndex);
}
2025-02-21 17:03:56 +08:00
// 刷新点位
currentLevelData.refreshPoints.Clear();
currentLevelData.refreshPoints.AddRange(refreshPoints);
// 指定路径
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
// 关卡进度
currentLevelData.progressGuideDatas = progressGuideDatas;
2025-06-10 18:45:59 +08:00
// 立标数据
currentLevelData.setFlagGuideDatas = setFlagEditorInfos.Select(x => x.flagGuideData).ToList();
2025-06-10 18:45:59 +08:00
// 信息板数据
currentLevelData.infoPanelGuideDatas = infoPanelGuideDatas;
2025-07-09 13:12:36 +08:00
currentLevelData.listAIBroadcastData = listAIBroadcastData;
// 处理条件(击杀对象列表)
ProcessCondition();
2025-06-10 18:45:59 +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
private void ProcessCondition()
2024-11-07 15:50:33 +08:00
{
foreach (var condition in currentLevelData.setFlagGuideDatas)
{
ProcessCondition(condition.triggerCondition);
ProcessCondition(condition.finishCondition);
}
foreach (var condition in currentLevelData.progressGuideDatas)
{
ProcessCondition(condition.triggerCondition);
ProcessCondition(condition.finishCondition);
}
foreach (var condition in currentLevelData.infoPanelGuideDatas)
{
ProcessCondition(condition.triggerCondition);
ProcessCondition(condition.finishCondition);
}
2025-07-09 13:12:36 +08:00
foreach (var condition in currentLevelData.listAIBroadcastData)
{
ProcessCondition(condition.triggerCondition);
}
2024-11-07 15:50:33 +08:00
ProcessConditionForList(currentLevelData.starTarget);
ProcessConditionForList(currentLevelData.scoreTarget);
}
2024-11-07 15:50:33 +08:00
private void ProcessConditionForList(IEnumerable<ConditionModifier> conditionModifiers)
{
foreach (var conditionModifier in conditionModifiers)
{
ProcessCondition(conditionModifier);
2024-11-07 15:50:33 +08:00
}
}
2024-11-26 16:58:42 +08:00
private void ProcessCondition(ConditionModifier conditionModifier)
{
// 击杀条件特殊处理
if (conditionModifier.conditionType == ConditionType.CombatKillEnemy)
2024-11-26 16:58:42 +08:00
{
conditionModifier.conditionArgs.Clear();
foreach (var enemy in conditionModifier.killEnemyIDList)
2024-11-26 16:58:42 +08:00
{
conditionModifier.conditionArgs.Add(new Param("", enemy, ""));
2024-11-26 16:58:42 +08:00
}
}
else if (conditionModifier.conditionType == ConditionType.CombatInTargetGridByJob)
{
conditionModifier.conditionArgs.Clear();
conditionModifier.conditionArgs.Add(new Param("职业", conditionModifier.job,
typeof(cfg.CharacterCfg.Ejob).FullName));
conditionModifier.conditionArgs.Add(new Param("是否路过", conditionModifier.isPass, ""));
foreach (var unitID in conditionModifier.unitIDList)
{
conditionModifier.conditionArgs.Add(new Param("地格位置", unitID, ""));
}
}
else if (conditionModifier.conditionType == ConditionType.CombatInTargetGridByCharacterId)
{
conditionModifier.conditionArgs.Clear();
conditionModifier.conditionArgs.Add(new Param("角色ID", conditionModifier.roleID, ""));
conditionModifier.conditionArgs.Add(new Param("是否路过", conditionModifier.isPass, ""));
foreach (var unitID in conditionModifier.unitIDList)
{
conditionModifier.conditionArgs.Add(new Param("地格位置", unitID, ""));
}
}
2025-06-11 18:14:49 +08:00
// 任意角色在目标位置特殊处理
else if (conditionModifier.conditionType == ConditionType.CombatInTargetGrid)
{
conditionModifier.conditionArgs.Clear();
conditionModifier.conditionArgs.Add(new Param("是否路过", conditionModifier.isPass, ""));
2025-06-11 18:14:49 +08:00
foreach (var unitID in conditionModifier.unitIDList)
{
2025-06-11 19:14:38 +08:00
conditionModifier.conditionArgs.Add(new Param("地格位置", unitID, ""));
2025-06-11 18:14:49 +08:00
}
}
// 撤退数量特殊处理
else if (conditionModifier.conditionType == ConditionType.CombatFallBack &&
conditionModifier.conditionArgs.Count > 0)
{
currentLevelData.fallBackCount = (int)conditionModifier.conditionArgs[0].Arg;
}
2024-11-07 15:50:33 +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")]
[OnValueChanged("GetLevelMonsterClass")]
[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-07-02 14:51:53 +08:00
/*
/// <summary>
/// 获取关卡怪物列表
/// </summary>
public void GetLevelMonsterClass()
{
2025-07-01 12:59:20 +08:00
if (!int.TryParse(levelID, out int levelIndex) ||
!LevelCfg.DataMap.TryGetValue(levelIndex, out _))
{
2024-11-18 16:50:35 +08:00
needManualInputLevelID = true;
DebugUtil.LogError("无对应的关卡ID请手动输入关卡ID");
2025-06-30 18:46:13 +08:00
curEnemyMonsterID = 0;
enemyNpcObject = null;
return;
}
2025-06-30 18:46:13 +08:00
enemyMonsterIDs = new List<int>();
2024-11-18 14:34:15 +08:00
selfMonsterIDs = new List<int>();
2025-07-01 12:59:20 +08:00
midMonsterIDs = new List<int>();
2024-11-18 16:50:35 +08:00
foreach (var monster in MonsterCfg.DataMap)
{
2025-07-01 12:59:20 +08:00
string strID = monster.Key.ToString();
string tempID = strID[..6];
2025-07-01 12:59:20 +08:00
// 关卡ID相同
if (!tempID.Equals(levelID))
continue;
switch (monster.Value.NpcType)
{
2025-07-01 12:59:20 +08:00
case EMonsterType.EnemyCharacter:
{
enemyMonsterIDs.Add(monster.Key);
}
break;
case EMonsterType.SelfCharacter:
{
2024-11-18 15:02:49 +08:00
selfMonsterIDs.Add(monster.Key);
2025-07-01 12:59:20 +08:00
}
break;
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
midMonsterIDs.Add(monster.Key);
2025-06-30 18:46:13 +08:00
enemyMonsterIDs.Add(monster.Key);
2025-07-01 12:59:20 +08:00
selfMonsterIDs.Add(monster.Key);
}
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
}
2025-07-01 12:59:20 +08:00
if (enemyMonsterIDs.Count <= 0 && midMonsterIDs.Count <= 0)
DebugUtil.LogError($"请检查Monster表没有{levelID}关卡的怪物数据");
2023-08-22 19:08:45 +08:00
}
2025-07-02 14:51:53 +08:00
*/
2025-05-28 17:49:04 +08:00
#endregion
#region 加载
2023-11-21 15:04:56 +08:00
private void LoadLevel(LevelData levelData)
2023-08-22 19:08:45 +08:00
{
DestroyNpcPrefab();
2025-06-30 18:46:13 +08:00
_enemyNpcObjectWaveDic.Clear();
_midNpcObjectWaveDic.Clear();
2024-11-04 18:19:57 +08:00
_showNpcInfos.Clear();
2024-11-13 17:14:27 +08:00
_selfNpcObjectDic.Clear();
2023-11-21 15:04:56 +08:00
currentLevelData = levelData;
//加载地区信息
curRegionData = new RegionData
{
preparingRegionId = currentLevelData.preparingRegionId,
fallbackRegionId = currentLevelData.fallbackRegionId,
enemyFallbackRegionId = currentLevelData.enemyFallbackRegionId,
preparingRegionToward = currentLevelData.preparingRegionToward,
pvpDefendRegionId = currentLevelData.pvpDefendRegionId,
pvpDefendToward = currentLevelData.pvpDefendToward
};
2024-04-02 16:53:46 +08:00
2023-12-18 19:42:46 +08:00
_mapManager = FindObjectOfType<MapManager>();
_curMap = _mapManager.Map;
2023-11-21 15:04:56 +08:00
_curMap.TerrainGridSystem.OnMouseClickOnGrid += OnCellClick;
// 加载占领数据
captureEditorInfo = new List<CaptureEditorInfo>();
foreach (var captureInfo in currentLevelData.CapturePoints)
{
var captureEditor = new CaptureEditorInfo()
{
capturePoint = _curMap.TGSCellIndex2BlockPosition(captureInfo.CapturePoint),
captureProgress = captureInfo.CaptureProgress,
};
captureEditorInfo.Add(captureEditor);
}
// 加载扛旗数据
flagEditorInfo = new FlagEditorInfo();
foreach (var flagStartPoint in currentLevelData.flagStartPoints)
{
var pos = _curMap.TGSCellIndex2BlockPosition(flagStartPoint);
flagEditorInfo.flagStartPoints.Add(pos);
}
foreach (var flagEndPoint in currentLevelData.flagEndPoints)
{
var pos = _curMap.TGSCellIndex2BlockPosition(flagEndPoint);
flagEditorInfo.flagEndPoints.Add(pos);
}
2024-11-11 13:46:47 +08:00
// 加载撤离数据
fallbackEditorInfo = new FallbackEditorInfo();
foreach (var fallback in currentLevelData.fallbackSinglePoints)
{
var pos = _curMap.TGSCellIndex2BlockPosition(fallback);
fallbackEditorInfo.fallbackSinglePoints.Add(pos);
}
foreach (var fallback in currentLevelData.fallbackReusablePoints)
{
var pos = _curMap.TGSCellIndex2BlockPosition(fallback);
fallbackEditorInfo.fallbackReusablePoints.Add(pos);
}
2025-02-21 17:03:56 +08:00
// 加载刷新点位
refreshPoints = new List<int>();
refreshPoints.AddRange(currentLevelData.refreshPoints);
// 加载指定路线
roadEditorInfos = currentLevelData.patrolRoadData.Select(roadInfo => new PrescribedRoadEditorInfo
2025-02-21 17:03:56 +08:00
{
roadID = roadInfo.id,
roadPoints = roadInfo.patrolInfos,
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
// 加载指定区域
areaEditorInfos = currentLevelData.patrolRegionData.Select(areaInfo => new PrescribedAreaEditorInfo
{
areaID = areaInfo.id,
areaPoints = areaInfo.patrolInfos,
}).ToList();
2025-06-10 18:45:59 +08:00
// 加载关卡进度数据
progressGuideDatas = currentLevelData.progressGuideDatas;
2025-06-10 18:45:59 +08:00
// 加载关卡引导立标数据
setFlagEditorInfos = currentLevelData.setFlagGuideDatas.Select(x => new SetFlagGuideEditorInfo(x)).ToList();
2025-06-10 18:45:59 +08:00
// 加载信息板数据
infoPanelGuideDatas = currentLevelData.infoPanelGuideDatas;
2025-06-10 18:45:59 +08:00
2025-07-09 13:12:36 +08:00
listAIBroadcastData = currentLevelData.listAIBroadcastData;
2025-06-30 18:46:13 +08:00
// 加载敌方NPC到场景中
LoadEnemyNpcInfo();
2025-06-30 18:46:13 +08:00
// 加载中立NPC到场景中
LoadMidNpcInfo();
// 加载己方NPC到场景中
2024-11-18 16:50:35 +08:00
LoadSelfNpcInfo();
// 加载阻挡球
LoadBlockSphereInfo();
}
2024-11-04 18:19:57 +08:00
2025-06-30 18:46:13 +08:00
private void LoadEnemyNpcInfo()
{
2024-11-18 16:50:35 +08:00
var monsterConfigDic = MonsterCfg.DataMap;
currentEnemyNpcInfo = new();
2024-11-04 18:19:57 +08:00
var index = 1;
foreach (var npcInfo in currentLevelData.npcInfos)
{
2024-09-05 13:26:43 +08:00
if (!monsterConfigDic.TryGetValue(npcInfo.id, out var monsterClassData))
2024-06-04 16:50:16 +08:00
{
2024-09-05 13:26:43 +08:00
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID", npcInfo.id);
continue;
}
2024-09-05 12:28:32 +08:00
var npcEditor = new NpcEditorInfo(npcInfo, index, monsterClassData.MonsterLevel, monsterClassData.AIType,
ETroopsId.Enemy);
currentEnemyNpcInfo.Add(npcEditor);
2025-06-30 18:46:13 +08:00
var npcObj = LoadEnemyNpcPrefab(npcInfo.id);
if (npcObj != null)
{
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
var yaw = LevelUtils.SetCharaterToward(npcInfo.npcToward);
2025-08-28 15:12:14 +08:00
var obj = Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0));
if (enemyObjRoot == null)
enemyObjRoot = new GameObject("enemyObjRoot");
if (obj != null)
obj.transform.SetParent(enemyObjRoot.transform);
2025-06-30 18:46:13 +08:00
if (_enemyNpcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
2025-08-28 15:12:14 +08:00
npcObjectDic.Add(npcEditor, obj);
2025-06-30 18:46:13 +08:00
}
else
{
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
2025-08-28 15:12:14 +08:00
{ { npcEditor, obj } };
2025-06-30 18:46:13 +08:00
_enemyNpcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
}
index++;
}
}
private void LoadMidNpcInfo()
{
var monsterConfigDic = MonsterCfg.DataMap;
currentMidNpcInfo = new();
var index = 1;
foreach (var npcInfo in currentLevelData.midNpcInfos)
{
if (!monsterConfigDic.TryGetValue(npcInfo.id, out var monsterClassData))
{
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID", npcInfo.id);
continue;
}
var npcEditor = new NpcEditorInfo(npcInfo, index, monsterClassData.MonsterLevel, monsterClassData.AIType,
ETroopsId.Neutral);
2025-06-30 18:46:13 +08:00
currentMidNpcInfo.Add(npcEditor);
2024-11-18 16:50:35 +08:00
2025-06-30 18:46:13 +08:00
var npcObj = LoadMidNpcPrefab(npcInfo.id);
2024-11-04 18:19:57 +08:00
if (npcObj != null)
2024-09-05 13:26:43 +08:00
{
2024-11-04 18:19:57 +08:00
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
2024-11-04 18:43:29 +08:00
var yaw = LevelUtils.SetCharaterToward(npcInfo.npcToward);
2025-08-28 15:12:14 +08:00
var obj = Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0));
if (midObjRoot == null)
midObjRoot = new GameObject("midObjRoot");
if (obj != null)
obj.transform.SetParent(midObjRoot.transform);
2025-06-30 18:46:13 +08:00
if (_midNpcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
2025-08-28 15:12:14 +08:00
npcObjectDic.Add(npcEditor, obj);
}
else
{
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
2025-08-28 15:12:14 +08:00
{ { npcEditor, obj } };
2025-06-30 18:46:13 +08:00
_midNpcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
2024-04-02 16:53:46 +08:00
}
2024-11-04 18:19:57 +08:00
index++;
}
}
2024-11-18 16:50:35 +08:00
private void LoadSelfNpcInfo()
2024-11-12 20:31:06 +08:00
{
2024-11-18 16:50:35 +08:00
var monsterConfigDic = MonsterCfg.DataMap;
2024-11-13 17:14:27 +08:00
currentSelfNpcInfo = new();
2024-11-13 19:11:46 +08:00
var index = SelfID + 1;
2024-11-18 15:27:53 +08:00
foreach (var selfNpcInfo in currentLevelData.selfNpcInfos)
2024-11-12 20:31:06 +08:00
{
2024-11-18 16:50:35 +08:00
if (!monsterConfigDic.TryGetValue(selfNpcInfo.id, out var monsterClassData))
2024-11-12 20:31:06 +08:00
{
2024-11-18 15:27:53 +08:00
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID, 已经删除对应", selfNpcInfo.id);
2024-11-12 20:31:06 +08:00
continue;
}
var npcEditor = new NpcEditorInfo(selfNpcInfo, index, monsterClassData.MonsterLevel,
monsterClassData.AIType, ETroopsId.Self);
2024-11-18 16:50:35 +08:00
currentSelfNpcInfo.Add(npcEditor);
2024-11-18 15:27:53 +08:00
var npcObj = LoadSelfNpcPrefab(selfNpcInfo.id);
2024-11-12 20:31:06 +08:00
if (npcObj != null)
{
2024-11-18 15:27:53 +08:00
var setPos = _curMap.BlockPosition2WorldPosition(selfNpcInfo.position);
var yaw = LevelUtils.SetCharaterToward(selfNpcInfo.npcToward);
2025-08-28 15:12:14 +08:00
var obj = Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0));
if (selfObjRoot == null)
selfObjRoot = new GameObject("selfObjRoot");
if (obj != null)
obj.transform.SetParent(selfObjRoot.transform);
_selfNpcObjectDic.Add(selfNpcInfo.position, obj);
2024-11-12 20:31:06 +08:00
}
2024-11-13 13:21:36 +08:00
index++;
2024-11-12 20:31:06 +08:00
}
}
#endregion
#region 点击添加事件
2025-05-28 17:49:04 +08:00
private bool ResponseClickOnCell =>
2025-06-30 18:46:13 +08:00
isEditingEnemyNpc || isEditingSelfNpc || isEditingMidNpc || isEditingNpcPos || isEditingFlagStart ||
2025-05-28 17:49:04 +08:00
isEditingFlagEnd || isEditingCapture ||
isEditingFallbackReusable || isEditingFallbackSingle || isEditingRefreshID || isEditingRoadInfo ||
isEditingAreaInfo;
2025-05-28 17:49:04 +08:00
private void OnCellClick(TerrainGridSystem tgs, int cellindex, int buttonindex)
{
2023-12-22 15:26:48 +08:00
if (!ResponseClickOnCell) return;
var clickPosition = _curMap.TGSCellIndex2BlockPosition(cellindex);
2023-11-21 15:04:56 +08:00
int leftButton = 0;
int rightButton = 1;
2023-12-22 15:26:48 +08:00
if (buttonindex != leftButton && buttonindex != rightButton)
return;
2023-12-22 15:26:48 +08:00
bool opTrue = buttonindex == leftButton;
if (isEditingFlagStart)
{
EditingFlagStart(clickPosition, true, opTrue);
}
else if (isEditingFlagEnd)
{
EditingFlagStart(clickPosition, false, opTrue);
}
2024-11-11 13:46:47 +08:00
else if (isEditingFallbackSingle)
{
EditingFallBack(clickPosition, true, opTrue);
}
else if (isEditingFallbackReusable)
{
EditingFallBack(clickPosition, false, opTrue);
}
2024-11-07 18:30:47 +08:00
else if (isEditingCapture)
{
EditingCapture(clickPosition, opTrue);
}
2024-11-04 18:19:57 +08:00
else if (isEditingNpcPos)
{
if (opTrue)
2025-06-30 18:46:13 +08:00
ChangeNpcPos(clickPosition, npcTroopId);
2024-11-04 18:19:57 +08:00
}
2025-06-30 18:46:13 +08:00
else if (isEditingEnemyNpc)
{
EditEnemyNpc(clickPosition, opTrue);
2024-11-12 20:31:06 +08:00
}
2024-11-13 17:14:27 +08:00
else if (isEditingSelfNpc)
2024-11-12 20:31:06 +08:00
{
2025-08-26 16:42:34 +08:00
EditSelfNpc(clickPosition, opTrue);
}
2025-06-30 18:46:13 +08:00
else if (isEditingMidNpc)
2025-06-30 14:51:47 +08:00
{
2025-08-26 16:42:34 +08:00
EditMidNpc(clickPosition, opTrue);
2025-06-30 14:51:47 +08:00
}
2025-02-21 17:03:56 +08:00
else if (isEditingRefreshID)
{
EditRefreshID(cellindex, opTrue);
}
else if (isEditingRoadInfo && isEditingRoad)
{
EditRoad(cellindex, opTrue);
}
2025-06-26 15:25:35 +08:00
else if (isEditingAreaInfo && isEditingArea)
{
EditArea(cellindex, opTrue);
}
}
2024-11-11 13:46:47 +08:00
private void EditingFallBack(Vector2Int clickPosition, bool isEditingSingle, bool isAdd)
{
if (isEditingSingle)
{
if (isAdd && !fallbackEditorInfo.fallbackSinglePoints.Contains(clickPosition))
{
DebugUtil.Log("单次撤离点添加: {0}", clickPosition);
fallbackEditorInfo.fallbackSinglePoints.Add(clickPosition);
}
else if (!isAdd && fallbackEditorInfo.fallbackSinglePoints.Contains(clickPosition))
{
DebugUtil.Log("单次撤离点移除: {0}", clickPosition);
fallbackEditorInfo.fallbackSinglePoints.Remove(clickPosition);
}
}
else
{
if (isAdd && !fallbackEditorInfo.fallbackReusablePoints.Contains(clickPosition))
{
DebugUtil.Log("复用撤离点添加: {0}", clickPosition);
fallbackEditorInfo.fallbackReusablePoints.Add(clickPosition);
}
else if (!isAdd && fallbackEditorInfo.fallbackReusablePoints.Contains(clickPosition))
{
DebugUtil.Log("复用撤离点移除: {0}", clickPosition);
fallbackEditorInfo.fallbackReusablePoints.Remove(clickPosition);
}
}
}
2024-11-07 18:30:47 +08:00
private void EditingFlagStart(Vector2Int clickPosition, bool isEditingStart, bool isAdd)
{
if (isEditingStart)
{
if (isAdd && !flagEditorInfo.flagStartPoints.Contains(clickPosition))
{
DebugUtil.Log("扛旗起点添加: {0}", clickPosition);
flagEditorInfo.flagStartPoints.Add(clickPosition);
}
else if (!isAdd && flagEditorInfo.flagStartPoints.Contains(clickPosition))
{
DebugUtil.Log("扛旗起点移除: {0}", clickPosition);
flagEditorInfo.flagStartPoints.Remove(clickPosition);
}
}
else
{
if (isAdd && !flagEditorInfo.flagEndPoints.Contains(clickPosition))
{
DebugUtil.Log("扛旗终点添加: {0}", clickPosition);
flagEditorInfo.flagEndPoints.Add(clickPosition);
}
else if (!isAdd && flagEditorInfo.flagEndPoints.Contains(clickPosition))
{
DebugUtil.Log("扛旗终点移除: {0}", clickPosition);
flagEditorInfo.flagEndPoints.Remove(clickPosition);
}
2023-12-22 15:26:48 +08:00
}
}
2023-11-21 15:04:56 +08:00
2024-11-07 18:30:47 +08:00
private void EditingCapture(Vector2Int clickPosition, bool isAdd)
{
var isExist = false;
CaptureEditorInfo existCapture = null;
foreach (var capture in captureEditorInfo)
{
if (capture.capturePoint == clickPosition)
{
isExist = true;
existCapture = capture;
}
}
if (isAdd)
{
if (!isExist)
{
DebugUtil.Log("占领点添加: {0}", clickPosition);
captureEditorInfo.Add(new CaptureEditorInfo()
{
capturePoint = clickPosition
});
}
}
else
{
if (existCapture != null)
{
DebugUtil.Log("占领点移除: {0}", clickPosition);
captureEditorInfo.Remove(existCapture);
}
}
}
2025-06-30 18:46:13 +08:00
private void ChangeNpcPos(Vector2Int clickPosition, int npcTroopId)
2024-11-04 18:19:57 +08:00
{
2025-06-30 18:46:13 +08:00
if (null == _currNpcEditorInfo)
return;
var oldPos = _currEditingNpcInfo.position;
if (oldPos == clickPosition)
2025-06-30 18:46:13 +08:00
return;
2024-11-04 18:19:57 +08:00
var newWorldPos = _curMap.BlockPosition2WorldPosition(clickPosition);
if (ETroopsId.Enemy == npcTroopId &&
_enemyNpcObjectWaveDic.TryGetValue(_currEditingNpcInfo.waveIndex, out var enemyNpcObjectDic))
2025-06-30 18:46:13 +08:00
{
if (enemyNpcObjectDic.TryGetValue(_currNpcEditorInfo, out var npcObj))
{
npcObj.transform.position = newWorldPos;
_currEditingNpcInfo.position = clickPosition;
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
}
}
else if (ETroopsId.Neutral == npcTroopId &&
_midNpcObjectWaveDic.TryGetValue(_currEditingNpcInfo.waveIndex, out var midNpcObjectDic))
2024-11-04 18:19:57 +08:00
{
2025-06-30 18:46:13 +08:00
if (midNpcObjectDic.TryGetValue(_currNpcEditorInfo, out var npcObj))
{
npcObj.transform.position = newWorldPos;
_currEditingNpcInfo.position = clickPosition;
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
}
2024-11-04 18:19:57 +08:00
}
else if (ETroopsId.Self == npcTroopId && _selfNpcObjectDic.TryGetValue(oldPos, out var selfNpcObj))
2024-11-18 16:50:35 +08:00
{
selfNpcObj.transform.position = newWorldPos;
_currEditingNpcInfo.position = clickPosition;
_selfNpcObjectDic.Remove(oldPos);
_selfNpcObjectDic.Add(clickPosition, selfNpcObj);
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
}
else
{
DebugUtil.LogError("需要更改的旧位置上没有怪物:{0}", oldPos);
}
2024-11-04 18:19:57 +08:00
}
2025-06-30 18:46:13 +08:00
#region 敌方NPC编辑方法
2025-06-30 18:46:13 +08:00
private void EditEnemyNpc(Vector2Int clickPosition, bool isAdd)
2024-11-12 20:31:06 +08:00
{
if (isAdd)
{
2025-06-30 18:46:13 +08:00
AddEnemyNpc(clickPosition);
2024-11-12 20:31:06 +08:00
}
else
{
2025-06-30 18:46:13 +08:00
RemoveEnemyNpc(clickPosition);
2024-11-12 20:31:06 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void AddEnemyNpc(Vector2Int clickPosition)
2023-12-22 15:26:48 +08:00
{
2025-06-30 18:46:13 +08:00
if (enemyNpcObject == null || curEnemyMonsterID == 0)
2023-12-22 15:26:48 +08:00
{
DebugUtil.LogError("请选择正确的NPC");
return;
}
2023-11-21 15:04:56 +08:00
2025-06-30 18:46:13 +08:00
_enemyNpcObjectWaveDic ??= new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
2025-06-30 18:46:13 +08:00
NPCInfo npcInfo = new()
2023-12-22 15:26:48 +08:00
{
2025-06-30 18:46:13 +08:00
id = curEnemyMonsterID,
position = clickPosition,
index = currentEnemyNpcInfo.Count + 1,
2025-06-30 18:46:13 +08:00
troopId = ETroopsId.Enemy,
2024-11-04 18:19:57 +08:00
};
2023-12-22 15:26:48 +08:00
2025-06-25 12:13:54 +08:00
var level = 0;
var aiType = 0;
2024-11-18 16:50:35 +08:00
var monsterConfigDic = MonsterCfg.DataMap;
2025-06-30 18:46:13 +08:00
if (monsterConfigDic.TryGetValue(curEnemyMonsterID, out var monster))
{
2025-06-25 12:13:54 +08:00
level = monster.MonsterLevel;
aiType = monster.AIType;
}
else
{
2025-06-30 18:46:13 +08:00
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curEnemyMonsterID);
}
var npcEditor = new NpcEditorInfo(npcInfo, currentEnemyNpcInfo.Count + 1, level, aiType, ETroopsId.Enemy);
currentEnemyNpcInfo.Add(npcEditor);
2024-11-04 18:19:57 +08:00
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
2025-06-30 18:46:13 +08:00
if (_enemyNpcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
2025-06-30 18:46:13 +08:00
var obj = Instantiate(enemyNpcObject, pos, enemyNpcObject.transform.rotation);
npcObjectDic.Add(npcEditor, obj);
}
else
{
2025-06-30 18:46:13 +08:00
var obj = Instantiate(enemyNpcObject, pos, enemyNpcObject.transform.rotation);
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
{ { npcEditor, obj } };
2025-06-30 18:46:13 +08:00
_enemyNpcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
DebugUtil.Log(
2025-06-30 18:46:13 +08:00
$"添加了第[ {npcInfo.waveIndex} ]波的[ {npcInfo.index} ]怪物到 [ {npcInfo.position} ]位置上, 其预制体为: {enemyNpcObject.name}");
2023-12-22 15:26:48 +08:00
}
2025-06-30 18:46:13 +08:00
private void RemoveEnemyNpc(Vector2Int clickPosition)
2023-12-22 15:26:48 +08:00
{
var npc = currentEnemyNpcInfo.LastOrDefault(npc => npc.npcInfo.position == clickPosition);
if (npc != null)
{
2025-06-30 18:46:13 +08:00
if (_enemyNpcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(npc, out var obj))
{
DebugUtil.Log(
$"从[ {clickPosition} ]位置上移除了[ {npc.npcInfo.waveIndex} ]波的[{npc.id}]NPC, 其预制体名字为:{obj.name}");
DestroyImmediate(obj);
npcObjectDic.Remove(npc);
}
else
{
DebugUtil.LogError($"波次{npc.npcInfo.waveIndex}中没有怪物{npc.id}");
}
}
else
{
DebugUtil.LogError("没有波次{0}的怪物信息", npc.npcInfo.waveIndex);
}
currentEnemyNpcInfo.Remove(npc);
}
2024-11-04 18:19:57 +08:00
2025-06-30 18:46:13 +08:00
ReorderEnemyNpcID();
}
2025-06-30 18:46:13 +08:00
#endregion
2025-06-30 18:46:13 +08:00
#region 已放NPC编辑方法
2024-11-13 17:14:27 +08:00
private void EditSelfNpc(Vector2Int clickPosition, bool isAdd)
2024-11-12 20:31:06 +08:00
{
if (isAdd)
{
2024-11-13 17:14:27 +08:00
AddSelfNpc(clickPosition);
2024-11-12 20:31:06 +08:00
}
else
{
2024-11-13 17:14:27 +08:00
RemoveSelfNpc(clickPosition);
2024-11-12 20:31:06 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void AddSelfNpc(Vector2Int clickPosition)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
if (selfNpcObject == null || curSelfNpcID == 0)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
DebugUtil.LogError("请选择正确的己方NPC");
2025-06-30 14:51:47 +08:00
return;
}
2025-06-30 18:46:13 +08:00
_selfNpcObjectDic ??= new Dictionary<Vector2Int, GameObject>();
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
if (_selfNpcObjectDic.ContainsKey(clickPosition))
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
DebugUtil.LogError("该位置已有NPC存在请重新选");
2025-06-30 14:51:47 +08:00
return;
}
2025-06-30 18:46:13 +08:00
NPCInfo npcInfo = new()
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
id = curSelfNpcID,
2025-06-30 14:51:47 +08:00
position = clickPosition,
2025-06-30 18:46:13 +08:00
troopId = ETroopsId.Self,
2025-06-30 14:51:47 +08:00
};
2025-06-30 18:46:13 +08:00
var level = 0;
var aiType = 0;
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curSelfNpcID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
}
2025-06-30 14:51:47 +08:00
else
2025-06-30 18:46:13 +08:00
{
DebugUtil.LogError("获取己方Npc[{0}]配置数据错误", curSelfNpcID);
}
currentSelfNpcInfo.Add(new NpcEditorInfo(npcInfo, SelfID + currentSelfNpcInfo.Count + 1, level, aiType,
ETroopsId.Self));
2025-06-30 18:46:13 +08:00
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_selfNpcObjectDic.Add(npcInfo.position, Instantiate(selfNpcObject, pos, selfNpcObject.transform.rotation));
DebugUtil.Log("添加了己方Npc: [ {0} ] 到 [ {1} ]位置上, 其预制体为: {2}", npcInfo.id, npcInfo.position, selfNpcObject.name);
}
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
private void RemoveSelfNpc(Vector2Int clickPosition)
{
if (_selfNpcObjectDic.TryGetValue(clickPosition, out var npcObj))
{
var npc = currentSelfNpcInfo.FirstOrDefault(npcFight => npcFight.npcInfo.position == clickPosition);
if (npc != null)
{
currentSelfNpcInfo.Remove(npc);
DebugUtil.Log("从[ {0} ]位置上移除了[{1}] 己方NPC", clickPosition, npcObj.name);
DestroyImmediate(npcObj);
_selfNpcObjectDic.Remove(clickPosition);
}
}
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
ReorderSelfNpcID();
}
2025-06-30 18:46:13 +08:00
#endregion
2025-06-30 14:51:47 +08:00
2025-06-30 18:46:13 +08:00
#region 中立NPC编辑方法
2025-06-30 18:46:13 +08:00
private void EditMidNpc(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
AddMidNpc(clickPosition);
else
RemoveMidNpc(clickPosition);
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
private void AddMidNpc(Vector2Int clickPosition)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
if (midNpcObject == null || curMidMonsterID == 0)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
DebugUtil.LogError("请选择正确的NPC");
2025-06-30 14:51:47 +08:00
return;
}
2025-06-30 18:46:13 +08:00
_midNpcObjectWaveDic ??= new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
NPCInfo npcInfo = new()
{
id = curMidMonsterID,
position = clickPosition,
index = currentMidNpcInfo.Count + 1,
troopId = ETroopsId.Neutral,
isOpenInvestigate = false,
2025-06-30 18:46:13 +08:00
};
var level = 0;
var aiType = 0;
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curMidMonsterID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
}
else
{
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curMidMonsterID);
}
2025-06-30 19:57:08 +08:00
var npcEditor = new NpcEditorInfo(npcInfo, currentMidNpcInfo.Count + 1, level, aiType, ETroopsId.Neutral);
2025-06-30 18:46:13 +08:00
currentMidNpcInfo.Add(npcEditor);
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
if (_midNpcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
var obj = Instantiate(midNpcObject, pos, midNpcObject.transform.rotation);
npcObjectDic.Add(npcEditor, obj);
2025-06-30 14:51:47 +08:00
}
else
{
2025-06-30 18:46:13 +08:00
var obj = Instantiate(midNpcObject, pos, midNpcObject.transform.rotation);
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
{ { npcEditor, obj } };
_midNpcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
DebugUtil.Log(
$"添加了第[ {npcInfo.waveIndex} ]波的[ {npcInfo.index} ]怪物到 [ {npcInfo.position} ]位置上, 其预制体为: {midNpcObject.name}");
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
private void RemoveMidNpc(Vector2Int clickPosition)
{
var npc = currentMidNpcInfo.LastOrDefault(npc => npc.npcInfo.position == clickPosition);
if (npc != null)
{
if (_midNpcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(npc, out var obj))
{
DebugUtil.Log(
$"从[ {clickPosition} ]位置上移除了[ {npc.npcInfo.waveIndex} ]波的[{npc.id}]NPC, 其预制体名字为:{obj.name}");
DestroyImmediate(obj);
npcObjectDic.Remove(npc);
}
else
{
DebugUtil.LogError($"波次{npc.npcInfo.waveIndex}中没有怪物{npc.id}");
}
}
else
{
DebugUtil.LogError("没有波次{0}的怪物信息", npc.npcInfo.waveIndex);
}
currentMidNpcInfo.Remove(npc);
}
ReorderMidNpcID();
}
2025-06-30 18:46:13 +08:00
#endregion
2025-02-21 17:03:56 +08:00
private void EditRefreshID(int clickPosition, bool isAdd)
{
if (isAdd && !refreshPoints.Contains(clickPosition))
{
refreshPoints.Add(clickPosition);
_curMap.TerrainGridSystem.CellToggleRegionSurface(clickPosition, true, RegionColor);
}
else if (!isAdd && refreshPoints.Contains(clickPosition))
{
refreshPoints.Remove(clickPosition);
_curMap.TerrainGridSystem.CellHideRegionSurface(clickPosition);
}
}
2025-06-26 15:25:35 +08:00
/// <summary>
/// 编辑路线
/// </summary>
/// <param name="clickPosition"></param>
/// <param name="isAdd"></param>
2025-02-21 17:03:56 +08:00
private void EditRoad(int clickPosition, bool isAdd)
{
if (_currEditingRoadInfo == null) return;
if (isAdd && !_currEditingRoadInfo.roadPoints.Any(x => x.cellIndex == clickPosition))
2025-02-21 17:03:56 +08:00
{
_currEditingRoadInfo.roadPoints.Add(new PatrolInfo()
{
cellIndex = clickPosition,
waitTime = 0f,
});
2025-02-21 17:03:56 +08:00
}
else if (!isAdd && _currEditingRoadInfo.roadPoints.Any(x => x.cellIndex == clickPosition))
2025-02-21 17:03:56 +08:00
{
_currEditingRoadInfo.roadPoints =
_currEditingRoadInfo.roadPoints.Where(x => x.cellIndex != clickPosition).ToList();
2025-02-21 17:03:56 +08:00
}
}
2025-06-26 15:25:35 +08:00
/// <summary>
/// 编辑区域
/// </summary>
/// <param name="clickPosition"></param>
/// <param name="isAdd"></param>
private void EditArea(int clickPosition, bool isAdd)
{
if (null == _currEditingAreaInfo)
return;
if (isAdd && !_currEditingAreaInfo.areaPoints.Any(x => x.cellIndex == clickPosition))
{
_currEditingAreaInfo.areaPoints.Add(new PatrolInfo()
{
cellIndex = clickPosition,
waitTime = 0f,
});
}
else if (!isAdd && _currEditingAreaInfo.areaPoints.Any(x => x.cellIndex == clickPosition))
{
_currEditingAreaInfo.areaPoints =
_currEditingAreaInfo.areaPoints.Where(x => x.cellIndex != clickPosition).ToList();
2025-06-26 15:25:35 +08:00
}
}
2025-06-30 18:46:13 +08:00
#endregion
2025-06-26 15:25:35 +08:00
2025-06-30 18:46:13 +08:00
#region 敌方Npc某些值改变时响应事件
2024-11-12 20:31:06 +08:00
2025-06-30 18:46:13 +08:00
private void ReorderEnemyNpcID()
{
for (var i = 0; i < currentEnemyNpcInfo.Count; i++)
2025-06-25 12:13:54 +08:00
{
currentEnemyNpcInfo[i].id = i + 1;
currentEnemyNpcInfo[i].npcInfo.index = currentEnemyNpcInfo[i].id;
2025-06-25 12:13:54 +08:00
}
2024-11-12 20:31:06 +08:00
}
2025-06-30 18:46:13 +08:00
private void ReorderMidNpcID()
2024-11-12 20:31:06 +08:00
{
2025-06-30 18:46:13 +08:00
for (var i = 0; i < currentMidNpcInfo.Count; i++)
2024-11-12 20:31:06 +08:00
{
2025-06-30 18:46:13 +08:00
currentMidNpcInfo[i].id = i + 1;
currentMidNpcInfo[i].npcInfo.index = currentMidNpcInfo[i].id;
2024-11-12 20:31:06 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void ReorderSelfNpcID()
2024-11-04 18:19:57 +08:00
{
2025-06-30 18:46:13 +08:00
for (var i = 0; i < currentSelfNpcInfo.Count; i++)
2024-11-04 18:19:57 +08:00
{
2025-06-30 18:46:13 +08:00
currentSelfNpcInfo[i].id = SelfID + i + 1;
2024-11-04 18:19:57 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void ChangeEnemyNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
2024-11-13 13:21:36 +08:00
{
2025-06-30 18:46:13 +08:00
if (_enemyNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
2024-11-13 13:21:36 +08:00
{
2025-06-30 18:46:13 +08:00
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var newObj = LoadEnemyNpcPrefab(newMonsterID);
if (newObj != null)
{
2025-08-28 15:12:14 +08:00
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);
2025-06-30 18:46:13 +08:00
npcEditorInfo.npcInfo.id = newMonsterID;
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
2025-08-28 15:12:14 +08:00
npcObjectDic[npcEditorInfo] = obj;
2025-06-30 18:46:13 +08:00
DestroyImmediate(npcObj);
DebugUtil.Log(
$"从[ {npcEditorInfo.npcInfo.position} ]的怪物ID改为:[ {npcEditorInfo.npcInfo.id} ]");
}
}
2024-11-13 13:21:36 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void ChangeMidNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
2024-11-04 18:19:57 +08:00
{
2025-06-30 18:46:13 +08:00
if (_midNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
2024-11-04 18:19:57 +08:00
{
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
2024-11-04 18:19:57 +08:00
{
2025-06-30 18:46:13 +08:00
var newObj = LoadMidNpcPrefab(newMonsterID);
if (newObj != null)
{
2025-08-28 15:12:14 +08:00
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
if (midObjRoot == null)
midObjRoot = new GameObject("midObjRoot");
if (obj != null)
obj.transform.SetParent(midObjRoot.transform);
2025-06-13 12:49:47 +08:00
npcEditorInfo.npcInfo.id = newMonsterID;
2025-06-25 12:13:54 +08:00
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
2025-08-28 15:12:14 +08:00
npcObjectDic[npcEditorInfo] = obj;
DestroyImmediate(npcObj);
DebugUtil.Log(
2025-06-13 12:49:47 +08:00
$"从[ {npcEditorInfo.npcInfo.position} ]的怪物ID改为:[ {npcEditorInfo.npcInfo.id} ]");
}
2024-11-04 18:19:57 +08:00
}
}
}
2025-06-30 18:46:13 +08:00
private void ChangeSelfNpcID(NPCInfo npcInfoInfo, int newMonsterID)
2024-11-12 20:31:06 +08:00
{
2024-11-13 17:14:27 +08:00
if (_selfNpcObjectDic.TryGetValue(npcInfoInfo.position, out var npcObj))
2024-11-12 20:31:06 +08:00
{
2024-11-13 17:14:27 +08:00
var newObj = LoadSelfNpcPrefab(newMonsterID);
2024-11-12 20:31:06 +08:00
if (newObj != null)
{
2025-08-28 15:12:14 +08:00
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
if (selfObjRoot == null)
selfObjRoot = new GameObject("selfObjRoot");
if (obj != null)
obj.transform.SetParent(selfObjRoot.transform);
2024-11-12 20:31:06 +08:00
npcInfoInfo.id = newMonsterID;
2025-08-28 15:12:14 +08:00
_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
#region 检查关卡
private const string PreparingRegionErrorMessage = "关卡出战区设置错误,该地图没有:<{0}>号地区。\n";
private const string FallbackRegionErrorMessage = "关卡撤退区设置错误,该地图没有:<{0}>号地区。\n";
private const string EnemyFallbackRegionErrorMessage = "关卡敌方撤退区设置错误,该地图没有:<{0}>号地区。\n";
private const string FixedMessage = "已将错误区域设置为默认<0>号地区。";
private const string CaptureErrorMessage = "占领条件参数大于配置的占领区域。";
private void CheckCorrectLevel()
{
if (_curMap == null)
{
return;
}
var errorMessage = string.Empty;
if (!_curMap.MapData.IsRegionExist(curRegionData.preparingRegionId))
{
errorMessage += string.Format(PreparingRegionErrorMessage,
curRegionData.preparingRegionId);
curRegionData.preparingRegionId = 0;
}
if (!_curMap.MapData.IsRegionExist(curRegionData.fallbackRegionId))
{
errorMessage += string.Format(FallbackRegionErrorMessage,
curRegionData.fallbackRegionId);
curRegionData.fallbackRegionId = 0;
}
if (!_curMap.MapData.IsRegionExist(curRegionData.enemyFallbackRegionId))
{
errorMessage += string.Format(EnemyFallbackRegionErrorMessage,
curRegionData.enemyFallbackRegionId);
curRegionData.enemyFallbackRegionId = 0;
}
// 检查占领条件相关
/*
if (!CheckLevelCondition())
{
CustomPopUpWindow.PopUp(CaptureErrorMessage);
}
*/
if (!string.IsNullOrEmpty(errorMessage))
{
CustomPopUpWindow.PopUp(errorMessage + FixedMessage);
}
}
/*private bool CheckLevelCondition()
{
if (currentLevelData.stages.Any(stage => stage.successCondition.conditionType == ConditionType.CombatLeastOccupy
2024-11-13 13:21:36 +08:00
&& stage.successCondition.conditionArgs[0].Arg >
captureEditorInfo.Count))
{
return false;
}
if (currentLevelData.starTarget.Any(modifier => modifier.conditionType == ConditionType.CombatLeastOccupy
&& modifier.conditionArgs[0].Arg > captureEditorInfo.Count))
{
return false;
}
if (currentLevelData.scoreTarget.Any(modifier => modifier.conditionType == ConditionType.CombatLeastOccupy
&& modifier.conditionArgs[0].Arg > captureEditorInfo.Count))
{
return false;
}
return true;
}*/
#endregion
#region 内部方法
/// <summary>
/// 关卡加载时 加载敌方预制体
/// </summary>
/// <param name="monsterID">Monster表ID</param>
/// <returns></returns>
2025-06-30 18:46:13 +08:00
private GameObject LoadEnemyNpcPrefab(int monsterID)
2024-11-04 18:19:57 +08:00
{
GameObject obj = null;
2024-11-18 15:02:49 +08:00
var curMonsterClassID = 0;
2024-11-18 16:50:35 +08:00
if (MonsterCfg.DataMap.TryGetValue(monsterID, out var monster))
2024-11-04 18:19:57 +08:00
{
2024-11-18 15:02:49 +08:00
curMonsterClassID = monster.MonsterClassID;
2024-11-04 18:19:57 +08:00
}
else
{
return null;
}
switch (monster.NpcType)
{
2025-06-30 14:58:00 +08:00
case EMonsterType.Vehicle:
2024-11-04 18:19:57 +08:00
{
2024-11-18 16:50:35 +08:00
if (VehicleCfg.DataMap.TryGetValue(curMonsterClassID, out var vehicle))
2024-11-04 18:19:57 +08:00
{
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查敌方载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
2024-11-04 18:19:57 +08:00
}
}
else
{
DebugUtil.LogError("请检查敌方载具类: {0}的配置是否存在", curMonsterClassID);
2024-11-04 18:19:57 +08:00
}
return obj;
}
2025-06-04 15:23:36 +08:00
case EMonsterType.EnemyCharacter:
2024-11-04 18:19:57 +08:00
{
if (MonsterClassCfg.DataMap.TryGetValue(curMonsterClassID, out var monsterClass))
2024-11-04 18:19:57 +08:00
{
var prefabPath = PathEx.GetCharacterFightModelPath(monsterClass.NameId, monsterClass.WeaponId);
2024-11-04 18:19:57 +08:00
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查敌方怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
}
}
else
{
DebugUtil.LogError("请检查敌方怪物类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
2025-06-30 14:58:00 +08:00
case EMonsterType.FightBuild:
{
if (FightBuildCfg.DataMap.TryGetValue(curMonsterClassID, out var buildData))
{
var prefabPath = PathEx.GetFightBuildingPath(buildData.ModelPath);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查敌方建筑类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
2024-11-04 18:19:57 +08:00
}
}
else
{
DebugUtil.LogError("请检查敌方建筑类: {0}的配置是否存在", curMonsterClassID);
2024-11-04 18:19:57 +08:00
}
return obj;
}
default: return null;
}
}
2025-06-30 18:46:13 +08:00
/// <summary>
/// 关卡加载时 加载中立预制体
/// </summary>
/// <param name="monsterID">Monster表ID</param>
/// <returns></returns>
private GameObject LoadMidNpcPrefab(int monsterID)
{
GameObject obj = null;
var curMonsterClassID = 0;
if (MonsterCfg.DataMap.TryGetValue(monsterID, out var monster))
{
curMonsterClassID = monster.MonsterClassID;
}
else
{
return null;
}
switch (monster.NpcType)
{
case EMonsterType.Vehicle:
{
if (VehicleCfg.DataMap.TryGetValue(curMonsterClassID, out var vehicle))
2025-06-30 18:46:13 +08:00
{
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
2025-06-30 18:46:13 +08:00
{
DebugUtil.LogError("请检查敌方载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
2025-06-30 18:46:13 +08:00
}
}
else
{
DebugUtil.LogError("请检查敌方载具类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
2025-06-30 18:46:13 +08:00
case EMonsterType.EnemyCharacter:
{
if (MonsterClassCfg.DataMap.TryGetValue(curMonsterClassID, out var monsterClass))
2025-06-30 18:46:13 +08:00
{
var prefabPath = PathEx.GetCharacterFightModelPath(monsterClass.NameId, monsterClass.WeaponId);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
2025-06-30 18:46:13 +08:00
{
DebugUtil.LogError("请检查敌方怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
2025-06-30 18:46:13 +08:00
}
}
else
{
DebugUtil.LogError("请检查敌方怪物类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
2025-06-30 18:46:13 +08:00
case EMonsterType.FightBuild:
{
if (FightBuildCfg.DataMap.TryGetValue(curMonsterClassID, out var buildData))
2025-06-30 18:46:13 +08:00
{
var prefabPath = PathEx.GetFightBuildingPath(buildData.ModelPath);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
2025-06-30 18:46:13 +08:00
{
DebugUtil.LogError("请检查敌方建筑类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
2025-06-30 18:46:13 +08:00
}
}
else
{
DebugUtil.LogError("请检查敌方建筑类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
2025-06-30 18:46:13 +08:00
default: return null;
}
}
/// <summary>
/// 关卡加载时 加载己方预制体
/// </summary>
/// <param name="monsterID">Monster表ID</param>
/// <returns></returns>
2024-11-13 17:14:27 +08:00
private GameObject LoadSelfNpcPrefab(int monsterID)
2024-11-12 20:31:06 +08:00
{
2024-11-18 15:02:49 +08:00
GameObject obj = null;
var curFightNpcID = 0;
2024-11-18 16:50:35 +08:00
if (MonsterCfg.DataMap.TryGetValue(monsterID, out var monster))
2024-11-18 15:02:49 +08:00
{
curFightNpcID = monster.MonsterClassID;
}
else
{
2024-11-12 20:31:06 +08:00
return null;
2024-11-18 15:02:49 +08:00
}
2024-11-12 20:31:06 +08:00
2024-11-18 15:02:49 +08:00
switch (monster.NpcType)
2024-11-12 20:31:06 +08:00
{
2025-06-30 14:58:00 +08:00
case EMonsterType.Vehicle:
2024-11-18 15:02:49 +08:00
{
2024-11-18 16:50:35 +08:00
if (VehicleCfg.DataMap.TryGetValue(curFightNpcID, out var vehicle))
2024-11-18 15:02:49 +08:00
{
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查己方载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curFightNpcID, prefabPath);
2024-11-18 15:02:49 +08:00
}
}
else
{
DebugUtil.LogError("请检查己方载具类: {0}的配置是否存在", curFightNpcID);
2024-11-18 15:02:49 +08:00
}
2024-11-12 20:31:06 +08:00
2024-11-18 15:02:49 +08:00
return obj;
}
2025-06-04 15:23:36 +08:00
case EMonsterType.SelfCharacter:
2024-11-18 15:02:49 +08:00
{
2024-11-18 16:50:35 +08:00
if (FightNpcCfg.DataMap.TryGetValue(curFightNpcID, out var fightNpc))
2024-11-18 15:02:49 +08:00
{
var prefabPath = PathEx.GetCharacterFightModelPath(fightNpc.NameId, fightNpc.WeaponId);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查己方NPC类: {0}的预制体路径是否存在,对应的完整路径: {1}", curFightNpcID, prefabPath);
}
}
else
{
DebugUtil.LogError("请检查己方NPC类: {0}的配置是否存在", curFightNpcID);
}
return obj;
}
2025-06-30 14:58:00 +08:00
case EMonsterType.FightBuild:
{
if (FightBuildCfg.DataMap.TryGetValue(curFightNpcID, out var buildData))
{
var prefabPath = PathEx.GetFightBuildingPath(buildData.ModelPath);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查己方建筑类: {0}的预制体路径是否存在,对应的完整路径: {1}", curFightNpcID, prefabPath);
2024-11-18 15:02:49 +08:00
}
}
else
{
DebugUtil.LogError("请检查己方建筑类: {0}的配置是否存在", curFightNpcID);
2024-11-18 15:02:49 +08:00
}
return obj;
}
default: return null;
}
2024-11-12 20:31:06 +08:00
}
2025-06-30 18:46:13 +08:00
private void DestroyNpcPrefab()
2025-06-30 14:51:47 +08:00
{
2025-08-28 15:12:14 +08:00
if (selfObjRoot != null)
DestroyImmediate(selfObjRoot);
if (midObjRoot != null)
DestroyImmediate(midObjRoot);
if (enemyObjRoot != null)
DestroyImmediate(enemyObjRoot);
/*foreach (var npcData in _enemyNpcObjectWaveDic.Values)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
foreach (var npc in npcData.Values)
{
DestroyImmediate(npc);
}
2025-06-30 14:51:47 +08:00
}
2025-06-30 18:46:13 +08:00
foreach (var npcData in _midNpcObjectWaveDic.Values)
{
foreach (var npc in npcData.Values)
{
DestroyImmediate(npc);
}
}
2024-11-12 20:31:06 +08:00
2024-11-13 17:14:27 +08:00
foreach (var npc in _selfNpcObjectDic)
2024-11-12 20:31:06 +08:00
{
DestroyImmediate(npc.Value);
2025-08-28 15:12:14 +08:00
}*/
2023-08-22 19:08:45 +08:00
}
2023-12-22 15:26:48 +08:00
2025-06-30 18:46:13 +08:00
private void ChangeEnemyNpcToward(NpcEditorInfo npcEditorInfo, CharacterToward npcToward)
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
if (_enemyNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var yaw = LevelUtils.SetCharaterToward(npcToward);
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
}
2025-06-30 14:51:47 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void ChangeMidNpcToward(NpcEditorInfo npcEditorInfo, CharacterToward npcToward)
2024-11-04 18:43:29 +08:00
{
2025-06-30 18:46:13 +08:00
if (_midNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
2024-11-04 18:43:29 +08:00
{
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var yaw = LevelUtils.SetCharaterToward(npcToward);
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
}
2024-11-04 18:43:29 +08:00
}
}
2025-06-30 18:46:13 +08:00
private void ChangeSelfNpcToward(Vector2Int pos, CharacterToward npcToward)
2024-11-12 20:31:06 +08:00
{
2024-11-13 17:14:27 +08:00
if (_selfNpcObjectDic.TryGetValue(pos, out var npcObj))
2024-11-12 20:31:06 +08:00
{
var yaw = LevelUtils.SetCharaterToward(npcToward);
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
}
}
private bool CheckConditionSame(ConditionType conditionType)
{
if (currentLevelData.starTarget.Any(modifier => modifier.conditionType == conditionType))
{
return true;
}
if (currentLevelData.scoreTarget.Any(modifier => modifier.conditionType == conditionType))
{
return true;
}
return false;
}
#endregion
#region MainLife
private void Awake()
{
SceneView.duringSceneGui += OnSceneGUI;
}
protected override void OnEnable()
{
TerrainTypeConfig.Load();
2025-06-30 18:46:13 +08:00
_enemyNpcObjectWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
_midNpcObjectWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
2024-11-13 17:14:27 +08:00
_selfNpcObjectDic = new Dictionary<Vector2Int, GameObject>();
2025-06-30 18:46:13 +08:00
_showNpcInfos = new List<NpcEditorInfo>();
base.OnEnable();
}
protected override void OnDisable()
{
StopMonitoringSphere();
ShowHiddenObjects();
SaveBlockSphereInfo();
DestroyBlockSphere();
currWindow = null;
DestroyNpcPrefab();
2025-06-30 18:46:13 +08:00
_enemyNpcObjectWaveDic = null;
_midNpcObjectWaveDic = null;
2024-11-13 17:14:27 +08:00
_selfNpcObjectDic = null;
2025-06-30 14:51:47 +08:00
base.OnDisable();
}
protected override void OnDestroy()
{
StopMonitoringSphere();
ShowHiddenObjects();
SaveBlockSphereInfo();
DestroyBlockSphere();
base.OnDestroy();
if (_curMap != null)
_curMap.TerrainGridSystem.OnMouseClickOnGrid -= OnCellClick;
SaveCurrentLevel();
SceneView.duringSceneGui -= OnSceneGUI;
}
2023-12-22 15:26:48 +08:00
protected override void OnGUI()
{
base.OnGUI();
if (_levelEditor == null || _mapManager == null || _mapManager.Map != _curMap ||
_levelEditor.LevelData != currentLevelData)
{
Debug.LogError("数据已变更,请重新打开关卡编辑器");
Close();
}
}
#endregion
#region Draw
2025-05-28 17:49:04 +08:00
private bool IsShowNpcID => _showNpcInfos != null && _showNpcInfos.Count > 0;
private List<NpcEditorInfo> _showNpcInfos;
2023-12-22 15:26:48 +08:00
private void OnSceneGUI(SceneView sceneView)
{
2025-02-21 17:03:56 +08:00
DrawRoadPath();
2025-06-26 15:25:35 +08:00
DrawAreaPath();
2024-11-04 18:19:57 +08:00
DrawNpcID();
DrawSphereID();
2023-12-22 15:26:48 +08:00
}
2025-02-21 17:03:56 +08:00
private void DrawRoadPath()
{
if (null == _currEditingRoadInfo)
2025-06-26 15:25:35 +08:00
return;
2025-02-21 17:03:56 +08:00
Vector3 lastWorldPos = Vector3.zero;
for (int i = 0; i < _currEditingRoadInfo.roadPoints.Count; i++)
{
var gridPos = _currEditingRoadInfo.roadPoints[i];
var worldPos = _curMap.TGSCellIndex2WorldPosition(gridPos.cellIndex);
2025-02-21 17:03:56 +08:00
Handles.color = Color.blue;
Handles.DrawSolidDisc(worldPos, Vector3.up, 0.4f);
if (i > 0)
{
Handles.color = Color.yellow;
EditorUtil.DrawArrowInScene(lastWorldPos, worldPos, 0.5f);
}
//Handles.color = Color.black;
Handles.Label(worldPos, i.ToString());
lastWorldPos = worldPos;
}
}
2025-06-26 15:25:35 +08:00
private void DrawAreaPath()
{
if (null == _currEditingAreaInfo)
return;
for (int i = 0; i < _currEditingAreaInfo.areaPoints.Count; ++i)
{
var gridPos = _currEditingAreaInfo.areaPoints[i];
var worldPos = _curMap.TGSCellIndex2WorldPosition(gridPos.cellIndex);
Handles.color = Color.blue;
Handles.DrawSolidDisc(worldPos, Vector3.up, 1.4f);
}
}
2024-11-04 18:19:57 +08:00
private GUIStyle labelStyle;
2024-11-18 16:50:35 +08:00
private GUIStyle labelStyleSelf;
private GUIStyle labelStyleSphere;
2024-11-04 18:19:57 +08:00
private void DrawNpcID()
{
if (!IsShowNpcID)
2025-06-30 18:46:13 +08:00
return;
2024-11-04 18:19:57 +08:00
2024-11-18 16:50:35 +08:00
labelStyle ??= new GUIStyle
2024-11-04 18:19:57 +08:00
{
2024-11-18 16:50:35 +08:00
fontSize = 38,
fontStyle = FontStyle.Bold,
normal =
2024-11-04 18:19:57 +08:00
{
2024-11-18 16:50:35 +08:00
textColor = Color.red
}
};
labelStyleSelf ??= new GUIStyle
{
fontSize = 38,
fontStyle = FontStyle.Bold,
normal =
{
textColor = Color.green
}
};
2024-11-04 18:19:57 +08:00
foreach (var npc in _showNpcInfos)
{
if (isShowAllEnemyNpcID &&
_enemyNpcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var enemyNpcObjectDic))
2024-11-04 18:19:57 +08:00
{
var waveID = npc.npcInfo.waveIndex;
2025-06-30 18:46:13 +08:00
if (enemyNpcObjectDic.TryGetValue(npc, out var npcObj))
{
var content = $"{waveID},{npc.id}";
Handles.Label(npcObj.transform.position, content, labelStyle);
}
2024-11-04 18:19:57 +08:00
}
else if (isShowAllMidNpcID &&
_midNpcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var midNpcObjectDic))
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
var waveID = npc.npcInfo.waveIndex;
if (midNpcObjectDic.TryGetValue(npc, out var npcObj))
{
var content = $"{waveID},{npc.id}";
Handles.Label(npcObj.transform.position, content, labelStyle);
}
2025-06-30 14:51:47 +08:00
}
else if (isShowAllSelfNpcID && _selfNpcObjectDic.TryGetValue(npc.npcInfo.position, out var selfNpcObj))
2025-06-30 14:51:47 +08:00
{
2025-06-30 18:46:13 +08:00
Handles.Label(selfNpcObj.transform.position, npc.id.ToString(), labelStyleSelf);
2025-06-30 14:51:47 +08:00
}
}
}
private void DrawSphereID()
{
if (!canEditorBlockSphere)
return;
labelStyleSphere ??= new GUIStyle
{
fontSize = 30,
fontStyle = FontStyle.Bold,
normal =
{
textColor = Color.black
}
};
foreach (var blockSpereEditor in blockSphereEditorList)
{
if (blockSpereEditor.sphere != null)
{
var pos = new Vector3(blockSpereEditor.sphere.transform.position.x, Calibre,
blockSpereEditor.sphere.transform.position.z);
Handles.Label(pos, blockSpereEditor.cellIndex.ToString(),
labelStyleSphere);
}
}
}
#endregion
2023-08-22 19:08:45 +08:00
}