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

2516 lines
81 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using TGS;
using System;
using Gameplay;
using Framework;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;
using Gameplay.Utils;
using Gameplay.Level;
using Sirenix.Utilities;
using Sirenix.OdinInspector;
using Sirenix.Utilities.Editor;
using System.Collections.Generic;
using cfg;
using cfg.AICfg;
using cfg.FightCfg;
using cfg.GuideCfg;
using cfg.LevelCfg;
using cfg.MonsterCfg;
using cfg.VehicleCfg;
using Sirenix.OdinInspector.Editor;
using Level = cfg.LevelCfg.Level;
using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment;
using static Gameplay.Level.LevelData;
using static LevelEditorWindow;
using NPOI.SS.Formula.Functions;
public class LevelEditorWindow : OdinEditorWindow
{
[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);
currWindow.GetLevelMonsterClass();
DebugUtil.Log("关卡数据:{0}", currWindow.levelID);
}
private static LevelEditorWindow currWindow;
private MapManager _mapManager;
private Map _curMap;
private LevelEditor _levelEditor;
#region 配置表
private Level LevelCfg => EditorTableManager.instance.tables.Level;
private Monster MonsterCfg => EditorTableManager.instance.tables.Monster;
private MonsterClass MonsterClassCfg => EditorTableManager.instance.tables.MonsterClass;
private VehicleConfig VehicleCfg => EditorTableManager.instance.tables.VehicleConfig;
private FightNPCConfig FightNpcCfg => EditorTableManager.instance.tables.FightNPCConfig;
private BuildConfig FightBuildCfg => EditorTableManager.instance.tables.BuildConfig;
#endregion
#region 地块颜色
private static readonly Color RegionColor = MapUtils.GetRGBAColor("FF960072");
#endregion
#region 关卡数据
[BoxGroup("当前关卡数据")] [LabelText("当前关卡数据"), Indent]
public LevelData currentLevelData = null;
#endregion
#region 关卡进度
[BoxGroup("关卡引导")] [LabelText("关卡进度"), Indent]
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 关卡进度
[BoxGroup("关卡引导")] [LabelText("信息板数据"), Indent]
public List<LevelData.InfoPanelGuideData> infoPanelGuideDatas = new();
#endregion
#region 占领相关
[Serializable]
public class CaptureEditorInfo
{
[LabelText("占领点位")] public Vector2Int capturePoint;
[LabelText("占领时间")] public int captureProgress;
}
[BoxGroup("占领相关")] [VerticalGroup("占领相关/数据")] [LabelText("当前占领数据"), Indent]
public List<CaptureEditorInfo> captureEditorInfo = new();
[BoxGroup("占领相关")] [VerticalGroup("占领相关/编辑")] [LabelText("编辑占领数据"), Indent]
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;
}
}
}
private bool isEditingFlagStart;
private bool isEditingFlagEnd;
[BoxGroup("扛棋相关")] [LabelText("当前扛旗数据"), Indent]
public FlagEditorInfo flagEditorInfo = new();
#endregion
#region 撤离相关
[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;
}
}
}
private bool isEditingFallbackSingle;
private bool isEditingFallbackReusable;
[BoxGroup("撤离相关")] [LabelText("当前撤离数据"), Indent]
public FallbackEditorInfo fallbackEditorInfo = new();
#endregion
#region 地区相关
[Serializable]
public class RegionData
{
[LabelText("出战区")] [OnValueChanged("OnRegionChanged")]
public int preparingRegionId;
[LabelText("出战区朝向")] public LevelData.CharacterToward preparingRegionToward;
[LabelText("撤退区")] public int fallbackRegionId;
[LabelText("敌方撤退区")] public int enemyFallbackRegionId;
[LabelText("PVP防守区")] public int pvpDefendRegionId;
[LabelText("PVP防守方朝向")] public LevelData.CharacterToward pvpDefendToward;
private void OnRegionChanged()
{
var regionsList = currWindow._curMap.MapData.regions;
for (int i = 0; i < regionsList.Count; i++)
{
currWindow._curMap.SetRegionColor(i, false, RegionColor);
}
currWindow._curMap.SetRegionColor(preparingRegionId, true, RegionColor);
}
}
[BoxGroup("地区相关")] [LabelText("当前地区数据"), Indent]
public RegionData curRegionData = null;
#endregion
#region NPC刷新点位相关
[HideInInspector] [BoxGroup("刷新点位")] [LabelText("编辑刷新点"), Indent, OnValueChanged("OnIsEditingRefreshIDChanged")]
public bool isEditingRefreshID;
[HideInInspector] [BoxGroup("刷新点位")] [LabelText("刷新点位"), Indent] [ShowIf("isEditingRefreshID")]
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);
}
}
}
#endregion
#region 指定路线
[Serializable]
public class PrescribedRoadEditorInfo
{
[LabelText("路线ID")] public int roadID;
[LabelText("路线点位")] public List<PatrolInfo> roadPoints = new();
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();
}
}
[BoxGroup("制定路线")] [LabelText("编辑指定路径"), Indent]
public bool isEditingRoad;
[BoxGroup("制定路线")] [LabelText("编辑指定路线"), Indent] [ShowIf("isEditingRoad")]
public List<PrescribedRoadEditorInfo> roadEditorInfos = new();
private bool isEditingRoadInfo;
private PrescribedRoadEditorInfo _currEditingRoadInfo;
private void StartEditRoadInfo(PrescribedRoadEditorInfo roadInfo)
{
isEditingRoadInfo = true;
_currEditingRoadInfo = roadInfo;
}
private void FinishEditRoadInfo()
{
isEditingRoadInfo = false;
_currEditingRoadInfo = null;
}
#endregion
#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]
public bool isEditingArea;
[BoxGroup("制定区域")]
[LabelText("编辑指定区域"), Indent]
[ShowIf("isEditingArea")]
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
#region 显示地图索引
[BoxGroup("辅助功能")]
[LabelText("显示索引地图"), Indent]
[LabelWidth(100)]
[OnValueChanged("ShowCellCoordinates")]
[SerializeField]
public bool isShowCellCoordinates;
private void ShowCellCoordinates()
{
if (_curMap == null || _curMap.TerrainGridSystem == null) return;
_curMap.TerrainGridSystem.displayCellDebugInfo =
isShowCellCoordinates ? CellDebugInfo.CellCoordinates : CellDebugInfo.Nothing;
var obj = FindObjectOfType<TerrainGridSystem>().gameObject;
Selection.activeGameObject = obj;
}
#endregion
#region NPC编辑器类
[Serializable]
public class NpcEditorInfo
{
private AITypeConfig AITypeCfg => EditorTableManager.instance.tables.AITypeConfig;
[HideInInspector] public bool selfNpc;
[ReadOnly] [LabelText("序号ID")] public int id;
[FoldoutGroup("详细信息")] [LabelText("MonsterID")] [ValueDropdown("GetMonsterIDs")] [OnValueChanged("ChangeNpcID")]
public int monsterId;
[FoldoutGroup("详细信息")] [LabelText("等级")] [ReadOnly]
public int level;
private IEnumerable<int> GetMonsterIDs()
{
if (!selfNpc)
return currWindow.GetMonsterIDs();
return currWindow.GetSelfNpcIDs();
}
private void ChangeNpcID()
{
if (!selfNpc)
currWindow.ChangeNpcID(this, monsterId);
else
currWindow.ChangeFightNpcID(npcInfo, monsterId);
}
[FoldoutGroup("详细信息")] [LabelText("朝向")] [OnValueChanged("NpcTowardOnChange")]
public LevelData.CharacterToward npcToward;
private void NpcTowardOnChange()
{
npcInfo.npcToward = npcToward;
if (!selfNpc)
currWindow.ChangeNpcToward(this, npcToward);
else
currWindow.ChangeSelfNpcToward(npcInfo.position, npcToward);
}
[FoldoutGroup("详细信息")] [HideLabel] public LevelData.NPCInfo npcInfo;
[FoldoutGroup("详细信息")] [LabelText("行为树")] [ValueDropdown(nameof(GetFilesFromFolder))]
public string aiConfigName;
[FoldoutGroup("详细信息")] [LabelText("AI预设")] [ReadOnly]
public string aiType;
private IEnumerable<string> GetFilesFromFolder()
{
string rootPath = "Assets/Config/AI/";
return new string[] { "" }.Concat(Directory.GetFiles(rootPath, "*.asset", SearchOption.AllDirectories)
.Select(Path.GetFileNameWithoutExtension));
}
public NpcEditorInfo(LevelData.NPCInfo npcInfo, int index, int level, int aiType, bool isSelfNpc = false)
{
this.npcInfo = npcInfo;
this.level = level;
this.npcInfo.aiTypeID = aiType;
this.aiType = GetAITypeData(aiType);
monsterId = npcInfo.id;
id = index;
selfNpc = isSelfNpc;
npcToward = this.npcInfo.npcToward;
aiConfigName = npcInfo.configName;
}
[FoldoutGroup("详细信息")] [LabelText("位置调整")] [OnValueChanged("ChangeNpcPos")]
public bool isChangePos;
private void ChangeNpcPos()
{
if (isChangePos)
{
if (currWindow._currEditingNpcInfo != null)
DebugUtil.LogWarning("检查其他怪物是否处于位置调整或编辑巡逻信息状态");
}
currWindow._currNpcEditorInfo = isChangePos ? this : null;
currWindow.isEditingNpcPos = isChangePos;
currWindow._currEditingNpcInfo = isChangePos ? npcInfo : null;
}
[FoldoutGroup("详细信息")] [LabelText("显示该怪物序号")] [OnValueChanged("ShowNpcID")]
public bool isShowNpcID;
private void ShowNpcID()
{
if (isShowNpcID && !currWindow._showNpcInfos.Contains(this))
currWindow._showNpcInfos.Add(this);
else if (!isShowNpcID)
{
currWindow._showNpcInfos.Remove(this);
}
}
private string GetAITypeData(int aiTypeID)
{
if (AITypeCfg.DataMap.TryGetValue(aiTypeID, out var dataAIType))
{
return dataAIType.Name;
}
return $"无效AI类型: {aiTypeID},请检查配置表";
}
}
private LevelData.NPCInfo _currEditingNpcInfo;
private NpcEditorInfo _currNpcEditorInfo;
private bool isEditingNpcPos;
#endregion
#region 敌方Npc
/// <summary>
/// 波次/怪物ID对应的NPC预制体
/// </summary>
private Dictionary<int, Dictionary<NpcEditorInfo, GameObject>> _npcObjectWaveDic;
// private Dictionary<Vector2Int, GameObject> _npcObjectDic;
[BoxGroup("敌方Npc")]
[LabelText("编辑NPC"), Indent]
[LabelWidth(100)]
[SerializeField]
[OnValueChanged("OnIsEditingNpcChanged")]
public bool isEditingNpc;
[BoxGroup("敌方Npc")] [LabelText("显示所有怪物序号ID"), Indent] [OnValueChanged("ShowAllNpcId")] [SerializeField]
public bool isShowAllNpcID;
[BoxGroup("敌方Npc")]
[LabelText("怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
[OnValueChanged("MonsterIDChanged")]
[ValueDropdown("GetMonsterIDs")]
[ShowIf("isEditingNpc")]
public int curMonsterID;
[BoxGroup("敌方Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
[LabelText("NPC预制体预览图"), ShowIf("isEditingNpc")]
public GameObject npcObject;
[BoxGroup("敌方Npc")]
[LabelText("当前怪物列表"), Indent, ShowIf("isEditingNpc")]
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
public List<NpcEditorInfo> currentNpcInfo = null;
/// <summary>
/// 该关卡的敌方NPCID
/// </summary>
[HideInInspector] public List<int> monsterIDs;
private IEnumerable<int> GetMonsterIDs()
{
return monsterIDs;
}
private void MonsterIDChanged()
{
var obj = LoadNpcPrefab(curMonsterID);
if (obj != null)
npcObject = obj;
}
private void OnIsEditingNpcChanged()
{
if (isEditingNpc && isEditingSelfNpc)
isEditingSelfNpc = false;
}
private void ShowAllNpcId()
{
foreach (var npc in currentNpcInfo)
{
npc.isShowNpcID = isShowAllNpcID;
if (isShowAllNpcID)
{
if (!_showNpcInfos.Contains(npc))
{
_showNpcInfos.Add(npc);
}
}
else
{
_showNpcInfos.Remove(npc);
}
}
}
#endregion
#region 己方Npc
private const int SelfID = 200;
private Dictionary<Vector2Int, GameObject> _selfNpcObjectDic;
[BoxGroup("己方Npc")]
[LabelText("编辑己方NPC"), Indent]
[LabelWidth(100)]
[OnValueChanged("OnIsEditingSelfNpcChanged")]
[SerializeField]
public bool isEditingSelfNpc;
[BoxGroup("己方Npc")] [LabelText("显示所有己方序号ID"), Indent] [OnValueChanged("ShowAllSelfNpcId")] [SerializeField]
public bool isShowAllSelfNpcID;
[BoxGroup("己方Npc")]
[LabelText("己方NpcID"), Indent, LabelWidth(100)]
[SerializeField]
[OnValueChanged("SelfNpcIDChanged")]
[ValueDropdown("GetSelfNpcIDs")]
[ShowIf("isEditingSelfNpc")]
public int curSelfNpcID;
[BoxGroup("己方Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
[LabelText("己方NPC预制体预览图"), ShowIf("isEditingSelfNpc")]
public GameObject selfNpcObject;
[BoxGroup("己方Npc")]
[LabelText("当前己方NPC列表"), Indent, ShowIf("isEditingSelfNpc")]
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true)]
public List<NpcEditorInfo> currentSelfNpcInfo = null;
/// <summary>
/// 该关卡的己方NPCID
/// </summary>
[HideInInspector] public List<int> selfMonsterIDs;
private IEnumerable<int> GetSelfNpcIDs()
{
return selfMonsterIDs;
}
private void SelfNpcIDChanged()
{
var obj = LoadSelfNpcPrefab(curSelfNpcID);
if (obj != null)
selfNpcObject = obj;
}
private void OnIsEditingSelfNpcChanged()
{
if (isEditingNpc && isEditingSelfNpc)
isEditingNpc = false;
}
private void ShowAllSelfNpcId()
{
foreach (var npc in currentSelfNpcInfo)
{
npc.isShowNpcID = isShowAllSelfNpcID;
if (isShowAllSelfNpcID)
{
if (!_showNpcInfos.Contains(npc))
{
_showNpcInfos.Add(npc);
}
}
else
{
_showNpcInfos.Remove(npc);
}
}
}
#endregion
#region 建筑编辑器类
[Serializable]
public class BuildEditorInfo
{
private AITypeConfig AITypeCfg => EditorTableManager.instance.tables.AITypeConfig;
[HideInInspector] public int camp;
[ReadOnly][LabelText("序号ID")] public int id;
[FoldoutGroup("详细信息")]
[LabelText("BuildID")]
[ValueDropdown("GetBuildIDs")]
[OnValueChanged("ChangeBuildID")]
public int buildId;
[FoldoutGroup("详细信息")]
[LabelText("等级")]
[ReadOnly]
public int level;
private IEnumerable<int> GetBuildIDs()
{
return currWindow.GetBuildIDs();
}
private void ChangeBuildID()
{
currWindow.ChangeBuildID(this, buildId);
}
[FoldoutGroup("详细信息")]
[LabelText("朝向")]
[OnValueChanged("BuildTowardOnChange")]
public CharacterToward buildToward;
private void BuildTowardOnChange()
{
buildInfo.buildToward = buildToward;
currWindow.ChangeBuildToward(this, buildToward);
}
[FoldoutGroup("详细信息")][HideLabel] public BuildInfo buildInfo;
[FoldoutGroup("详细信息")]
[LabelText("行为树")]
[ValueDropdown(nameof(GetFilesFromFolder))]
public string aiConfigName;
[FoldoutGroup("详细信息")]
[LabelText("AI预设")]
[ReadOnly]
public string aiType;
private IEnumerable<string> GetFilesFromFolder()
{
string rootPath = "Assets/Config/AI/";
return new string[] { "" }.Concat(Directory.GetFiles(rootPath, "*.asset", SearchOption.AllDirectories)
.Select(Path.GetFileNameWithoutExtension));
}
public BuildEditorInfo(BuildInfo buildInfo, int index, int level, int aiType, int camp = 0)
{
this.buildInfo = buildInfo;
this.level = level;
this.buildInfo.aiTypeID = aiType;
this.aiType = GetAITypeData(aiType);
buildId = buildInfo.id;
id = index;
this.camp = camp;
buildToward = this.buildInfo.buildToward;
aiConfigName = buildInfo.configName;
}
[FoldoutGroup("详细信息")]
[LabelText("位置调整")]
[OnValueChanged("ChangeBuildPos")]
public bool isChangePos;
private void ChangeBuildPos()
{
if (isChangePos)
{
if (currWindow._currEditingBuildInfo != null)
DebugUtil.LogWarning("检查其他建筑是否处于位置调整状态");
}
currWindow._currBuildEditorInfo = isChangePos ? this : null;
currWindow.isEditingBuildPos = isChangePos;
currWindow._currEditingBuildInfo = isChangePos ? buildInfo : null;
}
[FoldoutGroup("详细信息")]
[LabelText("显示该建筑序号")]
[OnValueChanged("ShowBuildID")]
public bool isShowBuildID;
private void ShowBuildID()
{
if (isShowBuildID && !currWindow._showBuildInfos.Contains(this))
currWindow._showBuildInfos.Add(this);
else if (!isShowBuildID)
{
currWindow._showBuildInfos.Remove(this);
}
}
private string GetAITypeData(int aiTypeID)
{
if (AITypeCfg.DataMap.TryGetValue(aiTypeID, out var dataAIType))
{
return dataAIType.Name;
}
return $"无效AI类型: {aiTypeID},请检查配置表";
}
}
private BuildInfo _currEditingBuildInfo;
private BuildEditorInfo _currBuildEditorInfo;
private bool isEditingBuildPos;
#endregion
#region 建筑
/// <summary>
/// 建筑ID对应的建筑预制体
/// </summary>
private Dictionary<BuildEditorInfo, GameObject> _buildObjectDic;
[BoxGroup("建筑")]
[LabelText("编辑建筑"), Indent]
[LabelWidth(100)]
[SerializeField]
[OnValueChanged("OnIsEditingBuildChanged")]
public bool isEditingBuild;
[BoxGroup("建筑")]
[LabelText("显示所有建筑序号ID"), Indent]
[OnValueChanged("ShowAllBuildId")]
[SerializeField]
public bool isShowAllBuildID;
[BoxGroup("建筑")]
[LabelText("建筑ID"), Indent, LabelWidth(100)]
[SerializeField]
[OnValueChanged("BuildIDChanged")]
[ValueDropdown("GetBuildIDs")]
[ShowIf("isEditingBuild")]
public int curBuildID;
[BoxGroup("建筑")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
[LabelText("建筑预制体预览图"), ShowIf("isEditingBuild")]
public GameObject buildObject;
[BoxGroup("建筑")]
[LabelText("当前建筑列表"), Indent, ShowIf("isEditingBuild")]
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
public List<BuildEditorInfo> currentBuildInfo = null;
/// <summary>
/// 该关卡的建筑ID
/// </summary>
[HideInInspector] public List<int> buildIDs;
private IEnumerable<int> GetBuildIDs()
{
return buildIDs;
}
private void BuildIDChanged()
{
GameObject obj = LoadBuildPrefab(curBuildID);
if (null != obj)
npcObject = obj;
}
private void OnIsEditingBuildChanged()
{
if (isEditingNpc && isEditingSelfNpc && isEditingBuild)
isEditingSelfNpc = false;
}
private void ShowAllBuildId()
{
foreach (var build in currentBuildInfo)
{
build.isShowBuildID = isShowAllBuildID;
if (isShowAllBuildID)
{
if (!_showBuildInfos.Contains(build))
_showBuildInfos.Add(build);
}
else
_showBuildInfos.Remove(build);
}
}
#endregion
#region 保存
[Button("保存当前关卡"), Indent]
private void SaveCurrentLevel()
{
CheckCorrectLevel();
// 地区
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
currentLevelData.fallbackRegionId = curRegionData.fallbackRegionId;
currentLevelData.enemyFallbackRegionId = curRegionData.enemyFallbackRegionId;
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
// NPC
foreach (var npcEditor in currentNpcInfo)
{
npcEditor.npcInfo.index = npcEditor.id;
npcEditor.npcInfo.configName = npcEditor.aiConfigName;
}
currentLevelData.npcInfos = currentNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
// 己方NPC
foreach (var npcFightEditorInfo in currentSelfNpcInfo)
{
npcFightEditorInfo.npcInfo.index = npcFightEditorInfo.id;
npcFightEditorInfo.npcInfo.configName = npcFightEditorInfo.aiConfigName;
}
currentLevelData.selfNpcInfos =
currentSelfNpcInfo.Select(editorFightNpcInfo => editorFightNpcInfo.npcInfo).ToList();
// 建筑
/*foreach (var buildEditor in currentBuildInfo)
{
buildEditor.buildInfo.index = buildEditor.id;
buildEditor.buildInfo.configName = buildEditor.aiConfigName;
}
currentLevelData.buildInfos =
currentBuildInfo.Select(editorFightBuildInfo => editorFightBuildInfo.buildInfo).ToList();*/
// 占领数据
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);
}
// 撤离数据
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);
}
// 刷新点位
currentLevelData.refreshPoints.Clear();
currentLevelData.refreshPoints.AddRange(refreshPoints);
// 指定路径
currentLevelData.patrolRoadData = roadEditorInfos.Select(editorInfo => new PatrolData
{
id = editorInfo.roadID,
patrolInfos = editorInfo.roadPoints,
}).ToList();
// 指定区域
currentLevelData.patrolRegionData = areaEditorInfos.Select(editorInfo => new PatrolData
{
id = editorInfo.areaID,
patrolInfos = editorInfo.areaPoints,
}).ToList();
// 关卡进度
currentLevelData.progressGuideDatas = progressGuideDatas;
// 立标数据
currentLevelData.setFlagGuideDatas = setFlagEditorInfos.Select(x => x.flagGuideData).ToList();
// 信息板数据
currentLevelData.infoPanelGuideDatas = infoPanelGuideDatas;
// 处理条件(击杀对象列表)
ProcessCondition();
_levelEditor.SaveLevelData();
}
private void ProcessCondition()
{
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);
}
ProcessConditionForList(currentLevelData.starTarget);
ProcessConditionForList(currentLevelData.scoreTarget);
}
private void ProcessConditionForList(IEnumerable<ConditionModifier> conditionModifiers)
{
foreach (var conditionModifier in conditionModifiers)
{
ProcessCondition(conditionModifier);
}
}
private void ProcessCondition(ConditionModifier conditionModifier)
{
// 击杀条件特殊处理
if (conditionModifier.conditionType == ConditionType.CombatKillEnemy)
{
conditionModifier.conditionArgs.Clear();
foreach (var enemy in conditionModifier.killEnemyIDList)
{
conditionModifier.conditionArgs.Add(new Param("", enemy, ""));
}
}
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, ""));
}
}
// 任意角色在目标位置特殊处理
else if (conditionModifier.conditionType == ConditionType.CombatInTargetGrid)
{
conditionModifier.conditionArgs.Clear();
conditionModifier.conditionArgs.Add(new Param("是否路过", conditionModifier.isPass, ""));
foreach (var unitID in conditionModifier.unitIDList)
{
conditionModifier.conditionArgs.Add(new Param("地格位置", unitID, ""));
}
}
// 撤退数量特殊处理
else if (conditionModifier.conditionType == ConditionType.CombatFallBack &&
conditionModifier.conditionArgs.Count > 0)
{
currentLevelData.fallBackCount = (int)conditionModifier.conditionArgs[0].Arg;
}
}
#endregion
#region 关卡ID相关
/// <summary>
/// 关卡ID 通过关卡数据 json文件名 获得
/// </summary>
[LabelText("手动指定关卡ID"), Indent, LabelWidth(100), ShowIf("needManualInputLevelID")]
[OnValueChanged("GetLevelMonsterClass")]
[InfoBox("无法正确获得关卡ID,请手动指定")]
[SerializeField]
public string levelID;
/// <summary>
/// 需要手动输入关卡ID
/// </summary>
[HideInInspector] public bool needManualInputLevelID;
/// <summary>
/// 获取关卡怪物列表
/// </summary>
public void GetLevelMonsterClass()
{
if (!int.TryParse(levelID, out var levelIndex) ||
!LevelCfg.DataMap.TryGetValue(levelIndex, out var level))
{
needManualInputLevelID = true;
DebugUtil.LogError("无对应的关卡ID请手动输入关卡ID");
curMonsterID = 0;
npcObject = null;
return;
}
monsterIDs = new List<int>();
selfMonsterIDs = new List<int>();
foreach (var monster in MonsterCfg.DataMap)
{
var strID = monster.Key.ToString();
var tempID = strID.Substring(0, 6);
//关卡ID相同
if (tempID.Equals(levelID))
{
switch (monster.Value.NpcType)
{
case EMonsterType.SelfCharacter:
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
selfMonsterIDs.Add(monster.Key);
break;
default:
monsterIDs.Add(monster.Key);
break;
}
}
}
if (monsterIDs.Count <= 0)
{
DebugUtil.LogError("请检查Monster表,没有{0}关卡的怪物数据", levelID);
}
}
#endregion
#region 加载
private void LoadLevel(LevelData levelData)
{
DestroyNpcPrefab();
//DestoryBuildPrefab();
// _npcObjectDic.Clear();
_npcObjectWaveDic.Clear();
_showNpcInfos.Clear();
_selfNpcObjectDic.Clear();
//_buildObjectDic.Clear();
//_showBuildInfos.Clear();
currentLevelData = levelData;
//加载地区信息
curRegionData = new RegionData
{
preparingRegionId = currentLevelData.preparingRegionId,
fallbackRegionId = currentLevelData.fallbackRegionId,
enemyFallbackRegionId = currentLevelData.enemyFallbackRegionId,
preparingRegionToward = currentLevelData.preparingRegionToward,
pvpDefendRegionId = currentLevelData.pvpDefendRegionId,
pvpDefendToward = currentLevelData.pvpDefendToward
};
_mapManager = FindObjectOfType<MapManager>();
_curMap = _mapManager.Map;
_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);
}
// 加载撤离数据
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);
}
// 加载刷新点位
refreshPoints = new List<int>();
refreshPoints.AddRange(currentLevelData.refreshPoints);
// 加载指定路线
roadEditorInfos = currentLevelData.patrolRoadData.Select(roadInfo => new PrescribedRoadEditorInfo
{
roadID = roadInfo.id,
roadPoints = roadInfo.patrolInfos,
}).ToList();
// 加载指定区域
areaEditorInfos = currentLevelData.patrolRegionData.Select(areaInfo => new PrescribedAreaEditorInfo
{
areaID = areaInfo.id,
areaPoints = areaInfo.patrolInfos,
}).ToList();
// 加载关卡进度数据
progressGuideDatas = currentLevelData.progressGuideDatas;
// 加载关卡引导立标数据
setFlagEditorInfos = currentLevelData.setFlagGuideDatas.Select(x => new SetFlagGuideEditorInfo(x)).ToList();
// 加载信息板数据
infoPanelGuideDatas = currentLevelData.infoPanelGuideDatas;
// 加载NPC到场景中
LoadNpcInfo();
// 加载己方NPC
LoadSelfNpcInfo();
}
private void LoadNpcInfo()
{
var monsterConfigDic = MonsterCfg.DataMap;
currentNpcInfo = new();
var index = 1;
foreach (var npcInfo in currentLevelData.npcInfos)
{
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);
currentNpcInfo.Add(npcEditor);
var npcObj = LoadNpcPrefab(npcInfo.id);
if (npcObj != null)
{
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
var yaw = LevelUtils.SetCharaterToward(npcInfo.npcToward);
if (_npcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
npcObjectDic.Add(npcEditor, Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0)));
}
else
{
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
{ { npcEditor, Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0)) } };
_npcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
}
index++;
}
}
private void LoadSelfNpcInfo()
{
var monsterConfigDic = MonsterCfg.DataMap;
currentSelfNpcInfo = new();
var index = SelfID + 1;
foreach (var selfNpcInfo in currentLevelData.selfNpcInfos)
{
if (!monsterConfigDic.TryGetValue(selfNpcInfo.id, out var monsterClassData))
{
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID, 已经删除对应", selfNpcInfo.id);
continue;
}
var npcEditor = new NpcEditorInfo(selfNpcInfo, index, monsterClassData.MonsterLevel,
monsterClassData.AIType, true);
currentSelfNpcInfo.Add(npcEditor);
var npcObj = LoadSelfNpcPrefab(selfNpcInfo.id);
if (npcObj != null)
{
var setPos = _curMap.BlockPosition2WorldPosition(selfNpcInfo.position);
var yaw = LevelUtils.SetCharaterToward(selfNpcInfo.npcToward);
_selfNpcObjectDic.Add(selfNpcInfo.position, Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0)));
}
index++;
}
}
#endregion
#region 点击添加事件
private bool ResponseClickOnCell =>
isEditingNpc || isEditingSelfNpc || isEditingBuild || isEditingNpcPos || isEditingBuildPos || isEditingFlagStart ||
isEditingFlagEnd || isEditingCapture ||
isEditingFallbackReusable || isEditingFallbackSingle || isEditingRefreshID || isEditingRoadInfo || isEditingAreaInfo;
private void OnCellClick(TerrainGridSystem tgs, int cellindex, int buttonindex)
{
if (!ResponseClickOnCell) return;
var clickPosition = _curMap.TGSCellIndex2BlockPosition(cellindex);
int leftButton = 0;
int rightButton = 1;
if (buttonindex != leftButton && buttonindex != rightButton)
return;
bool opTrue = buttonindex == leftButton;
if (isEditingFlagStart)
{
EditingFlagStart(clickPosition, true, opTrue);
}
else if (isEditingFlagEnd)
{
EditingFlagStart(clickPosition, false, opTrue);
}
else if (isEditingFallbackSingle)
{
EditingFallBack(clickPosition, true, opTrue);
}
else if (isEditingFallbackReusable)
{
EditingFallBack(clickPosition, false, opTrue);
}
else if (isEditingCapture)
{
EditingCapture(clickPosition, opTrue);
}
else if (isEditingNpcPos)
{
if (opTrue)
ChangeNpcPos(clickPosition);
}
else if (isEditingNpc)
{
EditNpc(clickPosition, opTrue);
}
else if (isEditingSelfNpc)
{
EditSelfNpc(clickPosition, opTrue);
}
else if (isEditingBuildPos)
{
if (opTrue)
ChangeBuildPos(clickPosition);
}
else if (isEditingBuild)
{
EditBuild(clickPosition, opTrue);
}
else if (isEditingRefreshID)
{
EditRefreshID(cellindex, opTrue);
}
else if (isEditingRoadInfo && isEditingRoad)
{
EditRoad(cellindex, opTrue);
}
else if (isEditingAreaInfo && isEditingArea)
{
EditArea(cellindex, opTrue);
}
}
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);
}
}
}
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);
}
}
}
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);
}
}
}
private void ChangeNpcPos(Vector2Int clickPosition)
{
if (_currNpcEditorInfo == null) return;
var oldPos = _currEditingNpcInfo.position;
if (oldPos == clickPosition) return;
var index = _currEditingNpcInfo.index;
var newWorldPos = _curMap.BlockPosition2WorldPosition(clickPosition);
if (_npcObjectWaveDic.TryGetValue(_currEditingNpcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(_currNpcEditorInfo, out var npcObj))
{
npcObj.transform.position = newWorldPos;
_currEditingNpcInfo.position = clickPosition;
/*npcObjectDic.Remove(oldPos);
npcObjectDic.Add(clickPosition, npcObj);*/
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
}
}
else if (_selfNpcObjectDic.TryGetValue(oldPos, out var selfNpcObj))
{
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);
}
}
private void EditNpc(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
{
AddNpc(clickPosition);
}
else
{
RemoveNpc(clickPosition);
}
}
private void AddNpc(Vector2Int clickPosition)
{
if (npcObject == null || curMonsterID == 0)
{
DebugUtil.LogError("请选择正确的NPC!!");
return;
}
_npcObjectWaveDic ??= new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
/*_npcObjectDic ??= new Dictionary<Vector2Int, GameObject>();
if (_npcObjectDic.ContainsKey(clickPosition))
{
DebugUtil.LogError("该位置已有NPC存在,请重新选!!!");
return;
}*/
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo
{
id = curMonsterID,
position = clickPosition,
index = currentNpcInfo.Count + 1
};
var level = 0;
var aiType = 0;
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curMonsterID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
}
else
{
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curMonsterID);
}
var npcEditor = new NpcEditorInfo(npcInfo, currentNpcInfo.Count + 1, level, aiType);
currentNpcInfo.Add(npcEditor);
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
if (_npcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
var obj = Instantiate(npcObject, pos, npcObject.transform.rotation);
npcObjectDic.Add(npcEditor, obj);
}
else
{
var obj = Instantiate(npcObject, pos, npcObject.transform.rotation);
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
{ { npcEditor, obj } };
_npcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
DebugUtil.Log(
$"添加了第[ {npcInfo.waveIndex} ]波的[ {npcInfo.index} ]怪物到 [ {npcInfo.position} ]位置上, 其预制体为: {npcObject.name}");
}
private void RemoveNpc(Vector2Int clickPosition)
{
var npc = currentNpcInfo.LastOrDefault(npc => npc.npcInfo.position == clickPosition);
if (npc != null)
{
if (_npcObjectWaveDic.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);
}
currentNpcInfo.Remove(npc);
}
ReorderNpcID();
}
private void EditSelfNpc(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
{
AddSelfNpc(clickPosition);
}
else
{
RemoveSelfNpc(clickPosition);
}
}
/// <summary>
/// 编辑建筑
/// </summary>
/// <param name="clickPosition"></param>
/// <param name="isAdd"></param>
private void EditBuild(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
AddBuild(clickPosition);
else
RemoveBuild(clickPosition);
}
private void ChangeBuildPos(Vector2Int clickPosition)
{
if (null == _currBuildEditorInfo)
return;
Vector2Int oldPos = _currEditingBuildInfo.position;
if (oldPos == clickPosition)
return;
Vector3 newWorldPos = _curMap.BlockPosition2WorldPosition(clickPosition);
if (!_buildObjectDic.TryGetValue(_currBuildEditorInfo, out GameObject buildObject))
{
DebugUtil.LogError($"需要更改的旧位置上没有建筑:{oldPos}");
return;
}
buildObject.transform.position = newWorldPos;
_currEditingBuildInfo.position = clickPosition;
DebugUtil.Log("建筑: [ {0} ] 移动到 [ {1} ]位置上", _currEditingBuildInfo.id, clickPosition);
}
/// <summary>
/// 添加建筑
/// </summary>
/// <param name="clickPosition"></param>
private void AddBuild(Vector2Int clickPosition)
{
if (null == buildObject || 0 == curBuildID)
{
DebugUtil.LogError("请选择正确的建筑!!");
return;
}
_buildObjectDic ??= new Dictionary<BuildEditorInfo, GameObject>();
BuildInfo buildInfo = new()
{
id = curBuildID,
position = clickPosition,
index = currentBuildInfo.Count + 1
};
int level = 0;
int aiType = 0;
var buildConfigDic = FightBuildCfg.DataMap;
if (buildConfigDic.TryGetValue(curBuildID, out DataBuild build))
level = build.FightLevel;
else
DebugUtil.LogError("获取建筑[{0}]配置数据错误", curBuildID);
BuildEditorInfo buildEditor = new(buildInfo, currentBuildInfo.Count + 1, level, aiType);
currentBuildInfo.Add(buildEditor);
Vector3 pos = _curMap.BlockPosition2WorldPosition(buildInfo.position);
GameObject obj = Instantiate(buildObject, pos, buildObject.transform.rotation);
_buildObjectDic.Add(buildEditor, obj);
DebugUtil.Log($"添加了{buildInfo.index} ]建筑到 [ {buildInfo.position} ]位置上, 其预制体为: {buildObject.name}");
}
/// <summary>
/// 移除建筑
/// </summary>
/// <param name="clickPosition"></param>
private void RemoveBuild(Vector2Int clickPosition)
{
var build = currentBuildInfo.LastOrDefault(build => build.buildInfo.position == clickPosition);
if (null == build)
{
ReorderBuildID();
return;
}
if (_buildObjectDic.TryGetValue(build, out GameObject buildObject))
{
DebugUtil.Log($"从[ {clickPosition} ]位置上移除了[{build.id}]建筑, 其预制体名字为:{buildObject.name}");
DestroyImmediate(buildObject);
currentBuildInfo.Remove(build);
}
else
{
DebugUtil.LogError($"没有建筑{build.id}");
}
ReorderBuildID();
}
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);
}
}
/// <summary>
/// 编辑路线
/// </summary>
/// <param name="clickPosition"></param>
/// <param name="isAdd"></param>
private void EditRoad(int clickPosition, bool isAdd)
{
if (_currEditingRoadInfo == null) return;
if (isAdd && !_currEditingRoadInfo.roadPoints.Any(x => x.cellIndex == clickPosition))
{
_currEditingRoadInfo.roadPoints.Add(new PatrolInfo()
{
cellIndex = clickPosition,
waitTime = 0f,
});
}
else if (!isAdd && _currEditingRoadInfo.roadPoints.Any(x => x.cellIndex == clickPosition))
{
_currEditingRoadInfo.roadPoints = _currEditingRoadInfo.roadPoints.Where(x => x.cellIndex != clickPosition).ToList();
}
}
/// <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();
}
}
private void AddSelfNpc(Vector2Int clickPosition)
{
if (selfNpcObject == null || curSelfNpcID == 0)
{
DebugUtil.LogError("请选择正确的己方NPC!!");
return;
}
_selfNpcObjectDic ??= new Dictionary<Vector2Int, GameObject>();
if (_selfNpcObjectDic.ContainsKey(clickPosition))
{
DebugUtil.LogError("该位置已有NPC存在,请重新选!!!");
return;
}
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo
{
id = curSelfNpcID,
position = clickPosition
};
var level = 0;
var aiType = 0;
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curSelfNpcID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
}
else
{
DebugUtil.LogError("获取己方Npc[{0}]配置数据错误", curSelfNpcID);
}
currentSelfNpcInfo.Add(new NpcEditorInfo(npcInfo, SelfID + currentSelfNpcInfo.Count + 1, level, aiType, true));
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);
}
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);
}
}
ReorderSelfNpcID();
}
#endregion
#region 敌方Npc某些值改变时响应事件
private void ReorderNpcID()
{
for (var i = 0; i < currentNpcInfo.Count; i++)
{
currentNpcInfo[i].id = i + 1;
currentNpcInfo[i].npcInfo.index = currentNpcInfo[i].id;
}
}
private void ReorderSelfNpcID()
{
for (var i = 0; i < currentSelfNpcInfo.Count; i++)
{
currentSelfNpcInfo[i].id = SelfID + i + 1;
}
}
private void ChangeNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
{
if (_npcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var newObj = LoadNpcPrefab(newMonsterID);
if (newObj != null)
{
npcEditorInfo.npcInfo.id = newMonsterID;
npcEditorInfo.npcInfo.aiTypeID = MonsterCfg.DataMap[newMonsterID].AIType;
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
npcObjectDic[npcEditorInfo] =
Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
DestroyImmediate(npcObj);
DebugUtil.Log(
$"从[ {npcEditorInfo.npcInfo.position} ]的怪物ID改为:[ {npcEditorInfo.npcInfo.id} ]");
}
}
}
}
private void ChangeFightNpcID(LevelData.NPCInfo npcInfoInfo, int newMonsterID)
{
if (_selfNpcObjectDic.TryGetValue(npcInfoInfo.position, out var npcObj))
{
var newObj = LoadSelfNpcPrefab(newMonsterID);
if (newObj != null)
{
npcInfoInfo.id = newMonsterID;
npcInfoInfo.aiTypeID = MonsterCfg.DataMap[newMonsterID].AIType;
_selfNpcObjectDic[npcInfoInfo.position] =
Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
DestroyImmediate(npcObj);
DebugUtil.Log("位置上[ {0} ]的fight怪物ID改为: [ {1} ] ", npcInfoInfo.position, npcInfoInfo.id);
}
}
}
#endregion
#region 建筑某些值改变时响应事件
private void ReorderBuildID()
{
for (int i = 0; i < currentBuildInfo.Count; ++i)
{
currentBuildInfo[i].id = i + 1;
currentBuildInfo[i].buildInfo.index = currentBuildInfo[i].id;
}
}
private void ChangeBuildID(BuildEditorInfo buildEditorInfo, int newBuildID)
{
if (!_buildObjectDic.TryGetValue(buildEditorInfo, out GameObject buildObj))
return;
GameObject newObj = LoadBuildPrefab(newBuildID);
if (null == newObj)
return;
buildEditorInfo.buildInfo.id = newBuildID;
buildEditorInfo.level = FightBuildCfg.DataMap[newBuildID].FightLevel;
_buildObjectDic[buildEditorInfo] = Instantiate(newObj, buildObj.transform.position, buildObj.transform.rotation);
DestroyImmediate(buildObj);
DebugUtil.Log($"从[ {buildEditorInfo.buildInfo.position} ]的建筑ID改为:[ {buildEditorInfo.buildInfo.id} ]");
}
#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
&& 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>
private GameObject LoadNpcPrefab(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))
{
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查敌方载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
}
}
else
{
DebugUtil.LogError("请检查敌方载具类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
case EMonsterType.EnemyCharacter:
{
if (MonsterClassCfg.DataMap.TryGetValue(curMonsterClassID, out var monsterClass))
{
var prefabPath = PathEx.GetCharacterFightModelPath(monsterClass.NameId, monsterClass.WeaponId);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查敌方怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
}
}
else
{
DebugUtil.LogError("请检查敌方怪物类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
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);
}
}
else
{
DebugUtil.LogError("请检查敌方建筑类: {0}的配置是否存在", curMonsterClassID);
}
return obj;
}
default: return null;
}
}
/// <summary>
/// 关卡加载时 加载己方预制体
/// </summary>
/// <param name="monsterID">Monster表ID</param>
/// <returns></returns>
private GameObject LoadSelfNpcPrefab(int monsterID)
{
GameObject obj = null;
var curFightNpcID = 0;
if (MonsterCfg.DataMap.TryGetValue(monsterID, out var monster))
{
curFightNpcID = monster.MonsterClassID;
}
else
{
return null;
}
switch (monster.NpcType)
{
case EMonsterType.Vehicle:
{
if (VehicleCfg.DataMap.TryGetValue(curFightNpcID, out var vehicle))
{
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (obj == null)
{
DebugUtil.LogError("请检查己方载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curFightNpcID, prefabPath);
}
}
else
{
DebugUtil.LogError("请检查己方载具类: {0}的配置是否存在", curFightNpcID);
}
return obj;
}
case EMonsterType.SelfCharacter:
{
if (FightNpcCfg.DataMap.TryGetValue(curFightNpcID, out var fightNpc))
{
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;
}
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);
}
}
else
{
DebugUtil.LogError("请检查己方建筑类: {0}的配置是否存在", curFightNpcID);
}
return obj;
}
default: return null;
}
}
/// <summary>
/// 关卡加载时 加载建筑预制体
/// </summary>
/// <param name="buildID"></param>
/// <returns></returns>
private GameObject LoadBuildPrefab(int buildID)
{
if (!FightBuildCfg.DataMap.TryGetValue(buildID, out DataBuild buildData))
{
DebugUtil.LogError($"请检查建筑类: {buildID}的配置是否存在");
return null;
}
string prefabPath = PathEx.GetFightBuildingPath(buildData.ModelPath);
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (null == obj)
DebugUtil.LogError($"请检查敌方建筑类: {buildID}的预制体路径是否存在,对应的完整路径: {prefabPath}");
return obj;
}
private void DestroyNpcPrefab()
{
foreach (var npcData in _npcObjectWaveDic.Values)
{
foreach (var npc in npcData.Values)
{
DestroyImmediate(npc);
}
}
foreach (var npc in _selfNpcObjectDic)
{
DestroyImmediate(npc.Value);
}
}
private void DestoryBuildPrefab()
{
foreach (var build in _buildObjectDic.Values)
{
DestroyImmediate(build);
}
}
private void ChangeNpcToward(NpcEditorInfo npcEditorInfo, LevelData.CharacterToward npcToward)
{
if (_npcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var yaw = LevelUtils.SetCharaterToward(npcToward);
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
}
}
}
private void ChangeSelfNpcToward(Vector2Int pos, LevelData.CharacterToward npcToward)
{
if (_selfNpcObjectDic.TryGetValue(pos, out var npcObj))
{
var yaw = LevelUtils.SetCharaterToward(npcToward);
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
}
}
private void ChangeBuildToward(BuildEditorInfo buildEditorInfo, CharacterToward buildToward)
{
if (!_buildObjectDic.TryGetValue(buildEditorInfo, out GameObject buildObject))
return;
float yaw = LevelUtils.SetCharaterToward(buildToward);
buildObject.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();
_npcObjectWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
_showNpcInfos = new List<NpcEditorInfo>();
_selfNpcObjectDic = new Dictionary<Vector2Int, GameObject>();
base.OnEnable();
}
protected override void OnDisable()
{
currWindow = null;
DestroyNpcPrefab();
//DestoryBuildPrefab();
_npcObjectWaveDic = null;
_selfNpcObjectDic = null;
_buildObjectDic = null;
base.OnDisable();
}
protected override void OnDestroy()
{
base.OnDestroy();
if (_curMap != null)
_curMap.TerrainGridSystem.OnMouseClickOnGrid -= OnCellClick;
SaveCurrentLevel();
SceneView.duringSceneGui -= OnSceneGUI;
}
protected override void OnGUI()
{
base.OnGUI();
if (_levelEditor == null || _mapManager == null || _mapManager.Map != _curMap ||
_levelEditor.LevelData != currentLevelData)
{
Debug.LogError("数据已变更,请重新打开关卡编辑器");
Close();
}
}
#endregion
#region Draw
private bool IsShowNpcID => _showNpcInfos != null && _showNpcInfos.Count > 0;
private bool IsShowBuildID => null != _showBuildInfos && _showBuildInfos.Count > 0;
private List<NpcEditorInfo> _showNpcInfos;
private List<BuildEditorInfo> _showBuildInfos;
private void OnSceneGUI(SceneView sceneView)
{
DrawRoadPath();
DrawAreaPath();
DrawNpcID();
DrawBuildID();
}
private void DrawRoadPath()
{
if (null == _currEditingRoadInfo)
return;
Vector3 lastWorldPos = Vector3.zero;
for (int i = 0; i < _currEditingRoadInfo.roadPoints.Count; i++)
{
var gridPos = _currEditingRoadInfo.roadPoints[i];
var worldPos = _curMap.TGSCellIndex2WorldPosition(gridPos.cellIndex);
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;
}
}
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);
}
}
private GUIStyle labelStyle;
private GUIStyle labelStyleSelf;
private void DrawNpcID()
{
if (!IsShowNpcID) return;
labelStyle ??= new GUIStyle
{
fontSize = 38,
fontStyle = FontStyle.Bold,
normal =
{
textColor = Color.red
}
};
labelStyleSelf ??= new GUIStyle
{
fontSize = 38,
fontStyle = FontStyle.Bold,
normal =
{
textColor = Color.green
}
};
foreach (var npc in _showNpcInfos)
{
if (_npcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var npcObjectDic))
{
var waveID = npc.npcInfo.waveIndex;
if (npcObjectDic.TryGetValue(npc, out var npcObj))
{
var content = $"{waveID},{npc.id}";
Handles.Label(npcObj.transform.position, content, labelStyle);
}
}
else if (_selfNpcObjectDic.TryGetValue(npc.npcInfo.position, out var selfNpcObj))
{
Handles.Label(selfNpcObj.transform.position, npc.id.ToString(), labelStyleSelf);
}
}
}
private void DrawBuildID()
{
if (!IsShowBuildID)
return;
labelStyle ??= new GUIStyle
{
fontSize = 38,
fontStyle = FontStyle.Bold,
normal =
{
textColor = Color.red
}
};
labelStyleSelf ??= new GUIStyle
{
fontSize = 38,
fontStyle = FontStyle.Bold,
normal =
{
textColor = Color.green
}
};
foreach (var build in _showBuildInfos)
{
if (_buildObjectDic.TryGetValue(build, out GameObject buildObject))
Handles.Label(buildObject.transform.position, build.id.ToString(), labelStyle);
}
}
#endregion
}