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

2579 lines
85 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;
using Gameplay.Character;
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 int npcTroopId;
[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()
{
return npcTroopId switch
{
ETroopsId.Neutral => currWindow.GetMidMonsterIDs(), // 中立
ETroopsId.Self => currWindow.GetSelfNpcIDs(), // 友方
ETroopsId.Enemy => currWindow.GetEnemyMonsterIDs(), // 敌人
_ => null
};
}
private void ChangeNpcID()
{
switch (npcTroopId)
{
case 0: // 中立
currWindow.ChangeMidNpcID(this, monsterId);
break;
case 1: // 友方
currWindow.ChangeSelfNpcID(npcInfo, monsterId);
break;
case 2: // 敌人
currWindow.ChangeEnemyNpcID(this, monsterId);
break;
default:
DebugUtil.LogError($"未处理类型:{npcTroopId}");
break;
}
}
[FoldoutGroup("详细信息")] [LabelText("朝向")] [OnValueChanged("NpcTowardOnChange")]
public CharacterToward npcToward;
private void NpcTowardOnChange()
{
npcInfo.npcToward = npcToward;
switch (npcTroopId)
{
case 0: // 中立
currWindow.ChangeMidNpcToward(this, npcToward);
break;
case 1: // 友方
currWindow.ChangeSelfNpcToward(npcInfo.position, npcToward);
break;
case 2: // 敌人
currWindow.ChangeEnemyNpcToward(this, npcToward);
break;
default:
DebugUtil.LogError($"未处理类型:{npcTroopId}");
break;
}
}
[FoldoutGroup("详细信息")] [HideLabel] public 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(NPCInfo npcInfo, int index, int level, int aiType, int npcTroopId)
{
this.npcInfo = npcInfo;
this.level = level;
this.npcInfo.aiTypeID = aiType;
this.aiType = GetAITypeData(aiType);
monsterId = npcInfo.id;
id = index;
this.npcTroopId = npcTroopId;
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.npcTroopId = npcTroopId;
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 NPCInfo _currEditingNpcInfo;
private NpcEditorInfo _currNpcEditorInfo;
private bool isEditingNpcPos;
private int npcTroopId;
#endregion
#region 敌方Npc
/// <summary>
/// 波次/怪物ID对应的NPC预制体
/// </summary>
private Dictionary<int, Dictionary<NpcEditorInfo, GameObject>> _enemyNpcObjectWaveDic;
[BoxGroup("敌方Npc")]
[LabelText("编辑NPC"), Indent]
[LabelWidth(100)]
[SerializeField]
[OnValueChanged("OnIsEditingEnemyNpcChanged")]
public bool isEditingEnemyNpc;
[BoxGroup("敌方Npc")]
[LabelText("显示所有怪物序号ID"), Indent]
[OnValueChanged("ShowAllEnemyNpcId")]
[SerializeField]
public bool isShowAllEnemyNpcID;
[BoxGroup("敌方Npc")]
[LabelText("添加怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
[ShowIf("isEditingEnemyNpc")]
public int addEnemyMonsterId;
[BoxGroup("敌方Npc")]
[Button("添加怪物id"), Indent, ShowIf("isEditingEnemyNpc")]
private void AddEnemyMonsterId()
{
if (!MonsterCfg.DataMap.ContainsKey(addEnemyMonsterId))
{
DebugUtil.LogError($"没有该怪物id:{addEnemyMonsterId}");
return;
}
enemyMonsterIDs.Add(addEnemyMonsterId);
DebugUtil.LogError($"添加怪物id:{addEnemyMonsterId}成功");
}
[BoxGroup("敌方Npc")]
[LabelText("怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
[OnValueChanged("EnemyMonsterIDChanged")]
[ValueDropdown("GetEnemyMonsterIDs")]
[ShowIf("isEditingEnemyNpc")]
public int curEnemyMonsterID;
[BoxGroup("敌方Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
[LabelText("NPC预制体预览图"), ShowIf("isEditingEnemyNpc")]
public GameObject enemyNpcObject;
[BoxGroup("敌方Npc")]
[LabelText("当前怪物列表"), Indent, ShowIf("isEditingEnemyNpc")]
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
public List<NpcEditorInfo> currentEenemyNpcInfo = null;
/// <summary>
/// 该关卡的敌方NPCID
/// </summary>
[HideInInspector] public List<int> enemyMonsterIDs;
private IEnumerable<int> GetEnemyMonsterIDs()
{
return enemyMonsterIDs;
}
private void EnemyMonsterIDChanged()
{
var obj = LoadEnemyNpcPrefab(curEnemyMonsterID);
if (obj != null)
enemyNpcObject = obj;
}
private void OnIsEditingEnemyNpcChanged()
{
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
{
isEditingSelfNpc = false;
isEditingMidNpc = false;
}
}
private void ShowAllEnemyNpcId()
{
foreach (var npc in currentEenemyNpcInfo)
{
npc.isShowNpcID = isShowAllEnemyNpcID;
if (isShowAllEnemyNpcID)
{
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("添加怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
[ShowIf("isEditingSelfNpc")]
public int addSelfMonsterId;
[BoxGroup("己方Npc")]
[Button("添加怪物id"), Indent, ShowIf("isEditingSelfNpc")]
private void AddSelfMonsterId()
{
if (!MonsterCfg.DataMap.ContainsKey(addSelfMonsterId))
{
DebugUtil.LogError($"没有该怪物id:{addSelfMonsterId}");
return;
}
selfMonsterIDs.Add(addSelfMonsterId);
DebugUtil.LogError($"添加怪物id:{addSelfMonsterId}成功");
}
[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 (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
{
isEditingEnemyNpc = false;
isEditingMidNpc = 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 中立Npc
/// <summary>
/// 中立 波次/怪物ID对应的NPC预制体
/// </summary>
private Dictionary<int, Dictionary<NpcEditorInfo, GameObject>> _midNpcObjectWaveDic;
[BoxGroup("中立Npc")]
[LabelText("编辑NPC"), Indent]
[LabelWidth(100)]
[SerializeField]
[OnValueChanged("OnIsEditingMidNpcChanged")]
public bool isEditingMidNpc;
[BoxGroup("中立Npc")]
[LabelText("显示所有怪物序号ID"), Indent]
[OnValueChanged("ShowAllMidNpcId")]
[SerializeField]
public bool isShowAllMidNpcID;
[BoxGroup("中立Npc")]
[LabelText("添加怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
[ShowIf("isEditingMidNpc")]
public int addMidMonsterId;
[BoxGroup("中立Npc")]
[Button("添加怪物id"), Indent, ShowIf("isEditingMidNpc")]
private void AddMidMonsterId()
{
if (!MonsterCfg.DataMap.ContainsKey(addMidMonsterId))
{
DebugUtil.LogError($"没有该怪物id:{addMidMonsterId}");
return;
}
midMonsterIDs.Add(addMidMonsterId);
DebugUtil.LogError($"添加怪物id:{addMidMonsterId}成功");
}
[BoxGroup("中立Npc")]
[LabelText("怪物ID"), Indent, LabelWidth(100)]
[SerializeField]
[OnValueChanged("MidMonsterIDChanged")]
[ValueDropdown("GetMidMonsterIDs")]
[ShowIf("isEditingMidNpc")]
public int curMidMonsterID;
[BoxGroup("中立Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
[LabelText("NPC预制体预览图"), ShowIf("isEditingMidNpc")]
public GameObject midNpcObject;
[BoxGroup("中立Npc")]
[LabelText("当前怪物列表"), Indent, ShowIf("isEditingMidNpc")]
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
public List<NpcEditorInfo> currentMidNpcInfo = null;
/// <summary>
/// 该关卡的中立NPCID
/// </summary>
[HideInInspector] public List<int> midMonsterIDs;
private IEnumerable<int> GetMidMonsterIDs()
{
return midMonsterIDs;
}
private void MidMonsterIDChanged()
{
var obj = LoadMidNpcPrefab(curMidMonsterID);
if (obj != null)
midNpcObject = obj;
}
private void OnIsEditingMidNpcChanged()
{
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
{
isEditingEnemyNpc = false;
isEditingSelfNpc = false;
}
}
private void ShowAllMidNpcId()
{
foreach (var npc in currentMidNpcInfo)
{
npc.isShowNpcID = isShowAllMidNpcID;
if (isShowAllMidNpcID)
{
if (!_showNpcInfos.Contains(npc))
{
_showNpcInfos.Add(npc);
}
}
else
{
_showNpcInfos.Remove(npc);
}
}
}
#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;
#region 敌方NPC
foreach (var npcEditor in currentEenemyNpcInfo)
{
npcEditor.npcInfo.index = npcEditor.id;
npcEditor.npcInfo.configName = npcEditor.aiConfigName;
}
currentLevelData.npcInfos = currentEenemyNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
#endregion
#region 己方NPC
foreach (var npcFightEditorInfo in currentSelfNpcInfo)
{
npcFightEditorInfo.npcInfo.index = npcFightEditorInfo.id;
npcFightEditorInfo.npcInfo.configName = npcFightEditorInfo.aiConfigName;
}
currentLevelData.selfNpcInfos =
currentSelfNpcInfo.Select(editorFightNpcInfo => editorFightNpcInfo.npcInfo).ToList();
#endregion
#region 中立NPC
foreach (var npcEditor in currentMidNpcInfo)
{
npcEditor.npcInfo.index = npcEditor.id;
npcEditor.npcInfo.configName = npcEditor.aiConfigName;
}
currentLevelData.midNpcInfos = currentMidNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
#endregion
// 占领数据
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 int levelIndex) ||
!LevelCfg.DataMap.TryGetValue(levelIndex, out _))
{
needManualInputLevelID = true;
DebugUtil.LogError("无对应的关卡ID请手动输入关卡ID");
curEnemyMonsterID = 0;
enemyNpcObject = null;
return;
}
enemyMonsterIDs = new List<int>();
selfMonsterIDs = new List<int>();
midMonsterIDs = new List<int>();
foreach (var monster in MonsterCfg.DataMap)
{
string strID = monster.Key.ToString();
string tempID = strID[..6];
// 关卡ID相同
if (!tempID.Equals(levelID))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.EnemyCharacter:
{
enemyMonsterIDs.Add(monster.Key);
}
break;
case EMonsterType.SelfCharacter:
{
selfMonsterIDs.Add(monster.Key);
}
break;
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
midMonsterIDs.Add(monster.Key);
enemyMonsterIDs.Add(monster.Key);
selfMonsterIDs.Add(monster.Key);
}
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
}
if (enemyMonsterIDs.Count <= 0 && midMonsterIDs.Count <= 0)
DebugUtil.LogError($"请检查Monster表没有{levelID}关卡的怪物数据");
}
#endregion
#region 加载
private void LoadLevel(LevelData levelData)
{
DestroyNpcPrefab();
_enemyNpcObjectWaveDic.Clear();
_midNpcObjectWaveDic.Clear();
_showNpcInfos.Clear();
_selfNpcObjectDic.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到场景中
LoadEnemyNpcInfo();
// 加载中立NPC到场景中
LoadMidNpcInfo();
// 加载己方NPC到场景中
LoadSelfNpcInfo();
}
private void LoadEnemyNpcInfo()
{
var monsterConfigDic = MonsterCfg.DataMap;
currentEenemyNpcInfo = 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, ETroopsId.Enemy);
currentEenemyNpcInfo.Add(npcEditor);
var npcObj = LoadEnemyNpcPrefab(npcInfo.id);
if (npcObj != null)
{
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
var yaw = LevelUtils.SetCharaterToward(npcInfo.npcToward);
if (_enemyNpcObjectWaveDic.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)) } };
_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);
currentMidNpcInfo.Add(npcEditor);
var npcObj = LoadMidNpcPrefab(npcInfo.id);
if (npcObj != null)
{
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
var yaw = LevelUtils.SetCharaterToward(npcInfo.npcToward);
if (_midNpcObjectWaveDic.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)) } };
_midNpcObjectWaveDic.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, ETroopsId.Self);
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 =>
isEditingEnemyNpc || isEditingSelfNpc || isEditingMidNpc || isEditingNpcPos || 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, npcTroopId);
}
else if (isEditingEnemyNpc)
{
EditEnemyNpc(clickPosition, opTrue);
}
else if (isEditingSelfNpc)
{
EditSelfNpc(clickPosition, opTrue);
}
else if (isEditingMidNpc)
{
EditMidNpc(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, int npcTroopId)
{
if (null == _currNpcEditorInfo)
return;
var oldPos = _currEditingNpcInfo.position;
if (oldPos == clickPosition)
return;
var newWorldPos = _curMap.BlockPosition2WorldPosition(clickPosition);
if (2 == npcTroopId && _enemyNpcObjectWaveDic.TryGetValue(_currEditingNpcInfo.waveIndex, out var enemyNpcObjectDic))
{
if (enemyNpcObjectDic.TryGetValue(_currNpcEditorInfo, out var npcObj))
{
npcObj.transform.position = newWorldPos;
_currEditingNpcInfo.position = clickPosition;
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
}
}
else if (0 == npcTroopId && _enemyNpcObjectWaveDic.TryGetValue(_currEditingNpcInfo.waveIndex, out var midNpcObjectDic))
{
if (midNpcObjectDic.TryGetValue(_currNpcEditorInfo, out var npcObj))
{
npcObj.transform.position = newWorldPos;
_currEditingNpcInfo.position = clickPosition;
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
}
}
else if (1 == npcTroopId && _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);
}
}
#region 敌方NPC编辑方法
private void EditEnemyNpc(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
{
AddEnemyNpc(clickPosition);
}
else
{
RemoveEnemyNpc(clickPosition);
}
}
private void AddEnemyNpc(Vector2Int clickPosition)
{
if (enemyNpcObject == null || curEnemyMonsterID == 0)
{
DebugUtil.LogError("请选择正确的NPC");
return;
}
_enemyNpcObjectWaveDic ??= new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
NPCInfo npcInfo = new()
{
id = curEnemyMonsterID,
position = clickPosition,
index = currentEenemyNpcInfo.Count + 1,
troopId = ETroopsId.Enemy,
};
var level = 0;
var aiType = 0;
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curEnemyMonsterID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
}
else
{
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curEnemyMonsterID);
}
var npcEditor = new NpcEditorInfo(npcInfo, currentEenemyNpcInfo.Count + 1, level, aiType, ETroopsId.Enemy);
currentEenemyNpcInfo.Add(npcEditor);
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
if (_enemyNpcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
var obj = Instantiate(enemyNpcObject, pos, enemyNpcObject.transform.rotation);
npcObjectDic.Add(npcEditor, obj);
}
else
{
var obj = Instantiate(enemyNpcObject, pos, enemyNpcObject.transform.rotation);
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
{ { npcEditor, obj } };
_enemyNpcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
DebugUtil.Log(
$"添加了第[ {npcInfo.waveIndex} ]波的[ {npcInfo.index} ]怪物到 [ {npcInfo.position} ]位置上, 其预制体为: {enemyNpcObject.name}");
}
private void RemoveEnemyNpc(Vector2Int clickPosition)
{
var npc = currentEenemyNpcInfo.LastOrDefault(npc => npc.npcInfo.position == clickPosition);
if (npc != null)
{
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);
}
currentEenemyNpcInfo.Remove(npc);
}
ReorderEnemyNpcID();
}
#endregion
#region 已放NPC编辑方法
private void EditSelfNpc(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
{
AddSelfNpc(clickPosition);
}
else
{
RemoveSelfNpc(clickPosition);
}
}
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;
}
NPCInfo npcInfo = new()
{
id = curSelfNpcID,
position = clickPosition,
troopId = ETroopsId.Self,
};
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, ETroopsId.Self));
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 EditMidNpc(Vector2Int clickPosition, bool isAdd)
{
if (isAdd)
AddMidNpc(clickPosition);
else
RemoveMidNpc(clickPosition);
}
private void AddMidNpc(Vector2Int clickPosition)
{
if (midNpcObject == null || curMidMonsterID == 0)
{
DebugUtil.LogError("请选择正确的NPC");
return;
}
_midNpcObjectWaveDic ??= new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
NPCInfo npcInfo = new()
{
id = curMidMonsterID,
position = clickPosition,
index = currentMidNpcInfo.Count + 1,
troopId = ETroopsId.Neutral,
};
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);
}
var npcEditor = new NpcEditorInfo(npcInfo, currentMidNpcInfo.Count + 1, level, aiType, ETroopsId.Neutral);
currentMidNpcInfo.Add(npcEditor);
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
if (_midNpcObjectWaveDic.TryGetValue(npcInfo.waveIndex, out var npcObjectDic))
{
var obj = Instantiate(midNpcObject, pos, midNpcObject.transform.rotation);
npcObjectDic.Add(npcEditor, obj);
}
else
{
var obj = Instantiate(midNpcObject, pos, midNpcObject.transform.rotation);
npcObjectDic = new Dictionary<NpcEditorInfo, GameObject>
{ { npcEditor, obj } };
_midNpcObjectWaveDic.Add(npcInfo.waveIndex, npcObjectDic);
}
DebugUtil.Log(
$"添加了第[ {npcInfo.waveIndex} ]波的[ {npcInfo.index} ]怪物到 [ {npcInfo.position} ]位置上, 其预制体为: {midNpcObject.name}");
}
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();
}
#endregion
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();
}
}
#endregion
#region 敌方Npc某些值改变时响应事件
private void ReorderEnemyNpcID()
{
for (var i = 0; i < currentEenemyNpcInfo.Count; i++)
{
currentEenemyNpcInfo[i].id = i + 1;
currentEenemyNpcInfo[i].npcInfo.index = currentEenemyNpcInfo[i].id;
}
}
private void ReorderMidNpcID()
{
for (var i = 0; i < currentMidNpcInfo.Count; i++)
{
currentMidNpcInfo[i].id = i + 1;
currentMidNpcInfo[i].npcInfo.index = currentMidNpcInfo[i].id;
}
}
private void ReorderSelfNpcID()
{
for (var i = 0; i < currentSelfNpcInfo.Count; i++)
{
currentSelfNpcInfo[i].id = SelfID + i + 1;
}
}
private void ChangeEnemyNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
{
if (_enemyNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var newObj = LoadEnemyNpcPrefab(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 ChangeMidNpcID(NpcEditorInfo npcEditorInfo, int newMonsterID)
{
if (_midNpcObjectWaveDic.TryGetValue(npcEditorInfo.npcInfo.waveIndex, out var npcObjectDic))
{
if (npcObjectDic.TryGetValue(npcEditorInfo, out var npcObj))
{
var newObj = LoadMidNpcPrefab(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 ChangeSelfNpcID(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 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 LoadEnemyNpcPrefab(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 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))
{
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;
}
}
private void DestroyNpcPrefab()
{
foreach (var npcData in _enemyNpcObjectWaveDic.Values)
{
foreach (var npc in npcData.Values)
{
DestroyImmediate(npc);
}
}
foreach (var npcData in _midNpcObjectWaveDic.Values)
{
foreach (var npc in npcData.Values)
{
DestroyImmediate(npc);
}
}
foreach (var npc in _selfNpcObjectDic)
{
DestroyImmediate(npc.Value);
}
}
private void ChangeEnemyNpcToward(NpcEditorInfo npcEditorInfo, CharacterToward npcToward)
{
if (_enemyNpcObjectWaveDic.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 ChangeMidNpcToward(NpcEditorInfo npcEditorInfo, CharacterToward npcToward)
{
if (_midNpcObjectWaveDic.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, CharacterToward npcToward)
{
if (_selfNpcObjectDic.TryGetValue(pos, out var npcObj))
{
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();
_enemyNpcObjectWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
_midNpcObjectWaveDic = new Dictionary<int, Dictionary<NpcEditorInfo, GameObject>>();
_selfNpcObjectDic = new Dictionary<Vector2Int, GameObject>();
_showNpcInfos = new List<NpcEditorInfo>();
base.OnEnable();
}
protected override void OnDisable()
{
currWindow = null;
DestroyNpcPrefab();
//DestoryBuildPrefab();
_enemyNpcObjectWaveDic = null;
_midNpcObjectWaveDic = null;
_selfNpcObjectDic = 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 List<NpcEditorInfo> _showNpcInfos;
private void OnSceneGUI(SceneView sceneView)
{
DrawRoadPath();
DrawAreaPath();
DrawNpcID();
}
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 (_enemyNpcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var enemyNpcObjectDic))
{
var waveID = npc.npcInfo.waveIndex;
if (enemyNpcObjectDic.TryGetValue(npc, out var npcObj))
{
var content = $"{waveID},{npc.id}";
Handles.Label(npcObj.transform.position, content, labelStyle);
}
}
else if (_midNpcObjectWaveDic.TryGetValue(npc.npcInfo.waveIndex, out var midNpcObjectDic))
{
var waveID = npc.npcInfo.waveIndex;
if (midNpcObjectDic.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);
}
}
}
#endregion
}