1468 lines
46 KiB
C#
1468 lines
46 KiB
C#
using TGS;
|
||
using Framework;
|
||
using System.IO;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
using System.Linq;
|
||
using Gameplay.Level;
|
||
using Sirenix.Utilities;
|
||
using Sirenix.OdinInspector;
|
||
using Sirenix.Utilities.Editor;
|
||
using System.Collections.Generic;
|
||
using cfg.FightCfg;
|
||
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;
|
||
|
||
public partial 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");
|
||
|
||
private static readonly Color ShowRegionColor = Color.red;
|
||
|
||
private static readonly Color CaptureRegionColor = Color.yellow;
|
||
|
||
private static readonly Color RetreatRegionColor = Color.cyan;
|
||
|
||
#endregion
|
||
|
||
#region 任务相关
|
||
|
||
[BoxGroup("任务列表")] [LabelText("任务列表"), Indent]
|
||
public List<TaskInfoEditor> taskInfos = new List<TaskInfoEditor>();
|
||
|
||
#endregion
|
||
|
||
/*#region 胜利失败星级条件
|
||
|
||
private int successTaskID;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")]
|
||
[HorizontalGroup("胜利失败星级条件/1")]
|
||
[LabelText("胜利条件"), Indent]
|
||
[ReadOnly]
|
||
[InfoBox("胜利条件任务无效,请在任务列表中检查配置。", InfoMessageType.Error, "@!IsTaskInvalid(successTaskID)")]
|
||
public string successTask;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")]
|
||
[HorizontalGroup("胜利失败星级条件/1")]
|
||
[Button("搜索/选择胜利任务", ButtonSizes.Small)]
|
||
[InfoBox("胜利条件任务无效,请在任务列表中检查配置。", InfoMessageType.Error, "@!IsTaskInvalid(successTaskID)")]
|
||
private void OpenSuccessTaskSelector()
|
||
{
|
||
ShowTaskSelector("选择胜利条件任务", taskName => successTask = taskName, id => successTaskID = id);
|
||
}
|
||
|
||
private int failTaskID;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/2")] [LabelText("失败条件"), Indent] [ReadOnly]
|
||
public string failTask;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")]
|
||
[HorizontalGroup("胜利失败星级条件/2")]
|
||
[Button("搜索/选择失败任务", ButtonSizes.Small)]
|
||
private void OpenFailTaskSelector()
|
||
{
|
||
ShowTaskSelector("选择失败条件任务", taskName => failTask = taskName, id => failTaskID = id);
|
||
}
|
||
|
||
private List<int> starTaskIDs = new List<int>() { 0, 0, 0 };
|
||
|
||
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/3")] [LabelText("1星条件"), Indent] [ReadOnly]
|
||
public string oneStarTask;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")]
|
||
[HorizontalGroup("胜利失败星级条件/3")]
|
||
[Button("搜索/选择1星任务", ButtonSizes.Small)]
|
||
private void OpenOneStarTaskSelector()
|
||
{
|
||
ShowTaskSelector("选择1星条件任务", taskName => oneStarTask = taskName, id => starTaskIDs[0] = id);
|
||
}
|
||
|
||
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/4")] [LabelText("2星条件"), Indent] [ReadOnly]
|
||
public string twoStarTask;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")]
|
||
[HorizontalGroup("胜利失败星级条件/4")]
|
||
[Button("搜索/选择2星任务", ButtonSizes.Small)]
|
||
private void OpenTwoStarTaskSelector()
|
||
{
|
||
ShowTaskSelector("选择2星条件任务", taskName => twoStarTask = taskName, id => starTaskIDs[1] = id);
|
||
}
|
||
|
||
[FoldoutGroup("胜利失败星级条件")] [HorizontalGroup("胜利失败星级条件/5")] [LabelText("3星条件"), Indent] [ReadOnly]
|
||
public string threeStarTask;
|
||
|
||
[FoldoutGroup("胜利失败星级条件")]
|
||
[HorizontalGroup("胜利失败星级条件/5")]
|
||
[Button("搜索/选择3星任务", ButtonSizes.Small)]
|
||
private void OpenThreeStarTaskSelector()
|
||
{
|
||
ShowTaskSelector("选择3星条件任务", taskName => threeStarTask = taskName, id => starTaskIDs[2] = id);
|
||
}
|
||
|
||
#endregion*/
|
||
|
||
#region 关卡数据
|
||
|
||
[FoldoutGroup("当前关卡数据")] [BoxGroup("当前关卡数据/数据")] [HideLabel]
|
||
public LevelData currentLevelData = null;
|
||
|
||
#endregion
|
||
|
||
#region 战役关卡
|
||
|
||
[FoldoutGroup("当前关卡数据")]
|
||
[BoxGroup("当前关卡数据/支线(战役)")]
|
||
[LabelText("设置该关卡为评分关卡"), Indent]
|
||
[OnValueChanged(nameof(OnScoreLevelChanged))]
|
||
public bool scoreLevel;
|
||
|
||
private void OnScoreLevelChanged()
|
||
{
|
||
currentLevelData.scoreLevel = scoreLevel;
|
||
}
|
||
|
||
[FoldoutGroup("当前关卡数据")]
|
||
[BoxGroup("当前关卡数据/支线(战役)")]
|
||
[Indent, ShowIf("@currentLevelData.scoreLevel")]
|
||
[LabelText("评分条件")]
|
||
public List<ScoreTaskEditor> scoreTasks = new List<ScoreTaskEditor>();
|
||
|
||
#endregion
|
||
|
||
#region 触发器
|
||
|
||
[FoldoutGroup("当前关卡数据")] [BoxGroup("当前关卡数据/触发器列表")] [Indent, LabelText("触发器")]
|
||
public List<LevelTriggerDataEditor> levelTriggerData = new List<LevelTriggerDataEditor>();
|
||
|
||
#endregion
|
||
|
||
#region 关卡引导
|
||
|
||
[FoldoutGroup("关卡引导")] [BoxGroup("关卡引导/关卡进度")] [LabelText("关卡进度"), Indent]
|
||
public List<ProgressGuideDataEditor> progressGuideDatas = new();
|
||
|
||
[FoldoutGroup("关卡引导")] [BoxGroup("关卡引导/立标数据")] [LabelText("立标数据"), Indent]
|
||
public List<SetFlagGuideDataEditor> setFlagEditorInfos = new();
|
||
|
||
[FoldoutGroup("关卡引导")] [BoxGroup("关卡引导/信息板数据")] [LabelText("信息板数据"), Indent]
|
||
public List<InfoPanelGuideDataEditor> infoPanelGuideDatas = new();
|
||
|
||
#endregion
|
||
|
||
#region 关卡AI广播
|
||
|
||
[FoldoutGroup("关卡AI广播")] [BoxGroup("关卡AI广播/数据")] [LabelText("AI广播数据"), Indent]
|
||
public List<AIBroadcastDataEditor> listAIBroadcastData = new();
|
||
|
||
#endregion
|
||
|
||
#region 地区相关
|
||
|
||
/// <summary>
|
||
/// 每种地区对应的显示颜色
|
||
/// </summary>
|
||
private static readonly Dictionary<ShowRegionType, Color> ShowRegionTypeColors =
|
||
new Dictionary<ShowRegionType, Color>
|
||
{
|
||
{ ShowRegionType.CaptureRegion, CaptureRegionColor },
|
||
{ ShowRegionType.RetreatRegion, RetreatRegionColor },
|
||
{ ShowRegionType.EnemyRetreatRegion, Color.green },
|
||
{ ShowRegionType.FlagStratRegion, new Color(1f, 0.5f, 0f) },
|
||
{ ShowRegionType.FlagEndRegion, new Color(1f, 0.3f, 0.3f) },
|
||
{ ShowRegionType.MinesRegion, Color.black },
|
||
{ ShowRegionType.DefenseRegion, Color.magenta },
|
||
{ ShowRegionType.BlockRegion, Color.blue },
|
||
};
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[LabelText("显示地区颜色")]
|
||
[EnumToggleButtons]
|
||
[OnValueChanged(nameof(OnShowRegionTypeChanged))]
|
||
public ShowRegionType showRegionType;
|
||
|
||
/// <summary>
|
||
/// 根据当前选择的地区类型集合,高亮对应的地区格子,每种地区使用独立颜色。
|
||
/// </summary>
|
||
private void OnShowRegionTypeChanged()
|
||
{
|
||
if (_curMap == null || currentLevelData == null)
|
||
return;
|
||
|
||
ClearShowRegionColor();
|
||
|
||
if (showRegionType == ShowRegionType.None)
|
||
{
|
||
SceneView.RepaintAll();
|
||
return;
|
||
}
|
||
|
||
var mask = showRegionType;
|
||
if (mask.HasFlag(ShowRegionType.All))
|
||
{
|
||
mask |= ShowRegionType.All;
|
||
}
|
||
|
||
foreach (var kv in ShowRegionTypeColors)
|
||
{
|
||
var type = kv.Key;
|
||
var color = kv.Value;
|
||
|
||
if (!mask.HasFlag(type))
|
||
continue;
|
||
|
||
var points = GetRegionPoints(type);
|
||
if (points == null || points.Count == 0)
|
||
continue;
|
||
|
||
_curMap.SetBlocksColor(points, true, color);
|
||
}
|
||
|
||
SceneView.RepaintAll();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按地区类型获取需要高亮的格子索引列表
|
||
/// </summary>
|
||
private List<int> GetRegionPoints(ShowRegionType type)
|
||
{
|
||
var points = new HashSet<int>();
|
||
|
||
switch (type)
|
||
{
|
||
case ShowRegionType.CaptureRegion:
|
||
if (captureEditorInfos != null)
|
||
{
|
||
foreach (var capture in captureEditorInfos)
|
||
{
|
||
if (capture?.capturePointEditorInfos == null) continue;
|
||
foreach (var p in capture.capturePointEditorInfos)
|
||
{
|
||
points.Add(p.capturePoint);
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.RetreatRegion:
|
||
if (retreatEditorInfo != null)
|
||
{
|
||
foreach (var info in retreatEditorInfo)
|
||
{
|
||
points.Add(info.retreatPoint);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.EnemyRetreatRegion:
|
||
if (enemyRetreatEditorInfo?.fallbackReusablePoints != null)
|
||
{
|
||
foreach (var pos in enemyRetreatEditorInfo.fallbackReusablePoints)
|
||
{
|
||
points.Add(_curMap.BlockPosition2TGSCellIndex(pos));
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.FlagStratRegion:
|
||
if (flagEditorInfo?.flagStartPoints != null)
|
||
{
|
||
foreach (var pos in flagEditorInfo.flagStartPoints)
|
||
{
|
||
points.Add(_curMap.BlockPosition2TGSCellIndex(pos));
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.FlagEndRegion:
|
||
if (flagEditorInfo?.flagEndPoints != null)
|
||
{
|
||
foreach (var pos in flagEditorInfo.flagEndPoints)
|
||
{
|
||
points.Add(_curMap.BlockPosition2TGSCellIndex(pos));
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.MinesRegion:
|
||
if (minesRegionList != null)
|
||
{
|
||
foreach (var area in minesRegionList)
|
||
{
|
||
if (area?.Positions == null) continue;
|
||
foreach (var cell in area.Positions)
|
||
{
|
||
points.Add(cell);
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.DefenseRegion:
|
||
if (defenseRegionList != null)
|
||
{
|
||
foreach (var area in defenseRegionList)
|
||
{
|
||
if (area?.Positions == null) continue;
|
||
foreach (var cell in area.Positions)
|
||
{
|
||
points.Add(cell);
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ShowRegionType.BlockRegion:
|
||
if (blockRegionList != null)
|
||
{
|
||
foreach (var area in blockRegionList)
|
||
{
|
||
if (area?.Positions == null) continue;
|
||
foreach (var cell in area.Positions)
|
||
{
|
||
points.Add(cell);
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
return points.ToList();
|
||
}
|
||
|
||
#region 撤离相关
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/撤离相关")]
|
||
[VerticalGroup("地区相关/撤离相关/编辑")]
|
||
[LabelText("编辑撤离数据"), Indent]
|
||
[OnValueChanged("OnIsEditingRetreatChanged")]
|
||
public bool isEditingRetreat;
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/撤离相关")]
|
||
[LabelText("当前撤离数据"), Indent]
|
||
[ShowIf("isEditingRetreat")]
|
||
[ListDrawerSettings(CustomRemoveIndexFunction = "CustomRemoveRetreatPoint",
|
||
DraggableItems = false)]
|
||
public List<RetreatEditorInfo> retreatEditorInfo = new();
|
||
|
||
private void CustomRemoveRetreatPoint(int index)
|
||
{
|
||
if (index >= retreatEditorInfo.Count) return;
|
||
var point = retreatEditorInfo[index].retreatPoint;
|
||
_curMap.TerrainGridSystem.CellHideRegionSurface(point);
|
||
retreatEditorInfo.RemoveAt(index);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 敌人撤离相关
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/敌人撤离相关")]
|
||
[LabelText("编辑敌人撤离数据"), Indent]
|
||
[OnValueChanged("OnIsEditingEnemyRetreatChanged")]
|
||
public bool isEditingEnemyRetreat;
|
||
|
||
private void OnIsEditingEnemyRetreatChanged()
|
||
{
|
||
if (isEditingEnemyRetreat)
|
||
return;
|
||
isEditingFallbackReusable = false;
|
||
}
|
||
|
||
private bool isEditingFallbackReusable;
|
||
|
||
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/敌人撤离相关")] [LabelText("当前撤离数据"), Indent] [ShowIf("isEditingEnemyRetreat")]
|
||
public EnemyRetreatEditorInfo enemyRetreatEditorInfo = new();
|
||
|
||
#endregion
|
||
|
||
#region 出战防守区
|
||
|
||
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/出战防守")] [LabelText("当前地区数据"), Indent]
|
||
public RegionData curRegionData = null;
|
||
|
||
#endregion
|
||
|
||
#region 占领相关
|
||
|
||
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/占领相关")] [VerticalGroup("地区相关/占领相关/编辑")] [LabelText("编辑占领区"), Indent]
|
||
public bool isEditingCapture = false;
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/占领相关")]
|
||
[VerticalGroup("地区相关/占领相关/编辑")]
|
||
[LabelText("编辑占领区"), Indent]
|
||
[ShowIf("isEditingCapture")]
|
||
public List<CaptureEditorInfo> captureEditorInfos = new();
|
||
|
||
#endregion
|
||
|
||
#region 扛旗相关
|
||
|
||
[FoldoutGroup("地区相关")] [BoxGroup("地区相关/扛棋相关")] [LabelText("当前扛旗数据"), Indent]
|
||
public FlagEditorInfo flagEditorInfo = new();
|
||
|
||
#endregion
|
||
|
||
#region 雷区
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/雷区信息")]
|
||
[HorizontalGroup("地区相关/雷区信息/Region")]
|
||
[LabelText("编辑雷区"), Indent]
|
||
[OnValueChanged("OnCanEditorMinesAreaTypeChanged")]
|
||
[LabelWidth(100)]
|
||
[SerializeField]
|
||
private bool canEditorMinesArea;
|
||
|
||
private void OnCanEditorMinesAreaTypeChanged()
|
||
{
|
||
if (canEditorMinesArea)
|
||
{
|
||
canEditorBlockArea = false;
|
||
canEditorDefenseArea = false;
|
||
_isEditorSingleBlockRegion = false;
|
||
_isEditorSingleDefenseRegion = false;
|
||
ClearDefenseRegionColor();
|
||
ClearBlockRegionColor();
|
||
}
|
||
else
|
||
{
|
||
ClearMinesRegionColor();
|
||
SceneView.RepaintAll();
|
||
_isEditorSingleMinesRegion = false;
|
||
_currEditMinesRegionArea = null;
|
||
}
|
||
}
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[VerticalGroup("地区相关/雷区信息/RegionInfo"), Indent]
|
||
[LabelText("雷区列表")]
|
||
[ShowIf("canEditorMinesArea")]
|
||
[ListDrawerSettings(CustomAddFunction = "CustomAddMinesRegion",
|
||
CustomRemoveIndexFunction = "CustomRemoveMinesRegion",
|
||
DraggableItems = false)]
|
||
public List<MinesRegionArea> minesRegionList = new();
|
||
|
||
private void CustomAddMinesRegion()
|
||
{
|
||
var region = new LevelData.Region();
|
||
currentLevelData.minesRegions.Add(region);
|
||
UpdateMinesRegion();
|
||
}
|
||
|
||
private void CustomRemoveMinesRegion(int index)
|
||
{
|
||
ClearMinesRegionColor();
|
||
currentLevelData.minesRegions.RemoveAt(index);
|
||
UpdateMinesRegion();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 阻挡区信息
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/阻挡区信息")]
|
||
[HorizontalGroup("地区相关/阻挡区信息/Region")]
|
||
[LabelText("编辑阻挡区"), Indent]
|
||
[OnValueChanged("OnCanEditorBlockAreaChanged")]
|
||
[LabelWidth(100)]
|
||
[SerializeField]
|
||
private bool canEditorBlockArea;
|
||
|
||
private void OnCanEditorBlockAreaChanged()
|
||
{
|
||
if (canEditorBlockArea)
|
||
{
|
||
canEditorMinesArea = false;
|
||
canEditorDefenseArea = false;
|
||
_isEditorSingleDefenseRegion = false;
|
||
ClearDefenseRegionColor();
|
||
ClearMinesRegionColor();
|
||
}
|
||
else
|
||
{
|
||
ClearBlockRegionColor();
|
||
SceneView.RepaintAll();
|
||
_currEditBlockRegion = null;
|
||
_isEditorSingleBlockRegion = false;
|
||
}
|
||
}
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[LabelText("阻挡区列表")]
|
||
[ShowIf("canEditorBlockArea")]
|
||
[VerticalGroup("地区相关/阻挡区信息/RegionInfo"), Indent]
|
||
[ListDrawerSettings(CustomAddFunction = "CustomAddBlockRegion",
|
||
CustomRemoveIndexFunction = "CustomRemoveBlockRegionIndex",
|
||
DraggableItems = false)]
|
||
public List<BlockRegionArea> blockRegionList = new();
|
||
|
||
private void CustomAddBlockRegion()
|
||
{
|
||
var region = new BlockRegion();
|
||
currentLevelData.blockRegions.Add(region);
|
||
UpdateBlockRegion();
|
||
}
|
||
|
||
private void CustomRemoveBlockRegionIndex(int index)
|
||
{
|
||
if (index < blockRegionList.Count)
|
||
{
|
||
if (blockRegionList[index].obj != null)
|
||
{
|
||
DebugUtil.LogError($"删除{blockRegionList[index].id}的指示");
|
||
DestroyImmediate(blockRegionList[index].obj);
|
||
}
|
||
}
|
||
|
||
ClearBlockRegionColor();
|
||
currentLevelData.blockRegions.RemoveAt(index);
|
||
UpdateBlockRegion();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 刷怪触发区
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[BoxGroup("地区相关/刷怪触发区")]
|
||
[HorizontalGroup("地区相关/刷怪触发区/Region")]
|
||
[LabelText("编辑触发区"), Indent]
|
||
[OnValueChanged("OnCanEditorDefenseAreaChanged")]
|
||
[LabelWidth(100)]
|
||
[SerializeField]
|
||
private bool canEditorDefenseArea;
|
||
|
||
private void OnCanEditorDefenseAreaChanged()
|
||
{
|
||
if (canEditorDefenseArea)
|
||
{
|
||
canEditorBlockArea = false;
|
||
canEditorMinesArea = false;
|
||
_isEditorSingleBlockRegion = false;
|
||
ClearBlockRegionColor();
|
||
ClearMinesRegionColor();
|
||
}
|
||
else
|
||
{
|
||
ClearDefenseRegionColor();
|
||
SceneView.RepaintAll();
|
||
_currEditDefenseRegion = null;
|
||
_isEditorSingleDefenseRegion = false;
|
||
}
|
||
}
|
||
|
||
[FoldoutGroup("地区相关")]
|
||
[LabelText("刷怪触发区列表")]
|
||
[ShowIf("canEditorDefenseArea")]
|
||
[VerticalGroup("地区相关/刷怪触发区/RegionInfo"), Indent]
|
||
[ListDrawerSettings(CustomAddFunction = "CustomAddDefenseRegion",
|
||
CustomRemoveIndexFunction = "CustomRemoveDefenseRegion",
|
||
DraggableItems = false)]
|
||
public List<DefenseRegionArea> defenseRegionList = new();
|
||
|
||
private void CustomAddDefenseRegion()
|
||
{
|
||
var region = new LevelData.Region();
|
||
currentLevelData.defenseRegions.Add(region);
|
||
UpdateDefenseRegion();
|
||
}
|
||
|
||
private void CustomRemoveDefenseRegion(int index)
|
||
{
|
||
ClearDefenseRegionColor();
|
||
currentLevelData.defenseRegions.RemoveAt(index);
|
||
UpdateDefenseRegion();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region 指定路线
|
||
|
||
[BoxGroup("制定路线")] [LabelText("编辑指定路径"), Indent]
|
||
public bool isEditingRoad;
|
||
|
||
[BoxGroup("制定路线")] [LabelText("编辑指定路线"), Indent] [ShowIf("isEditingRoad")]
|
||
public List<PrescribedRoadEditorInfo> roadEditorInfos = new();
|
||
|
||
#endregion
|
||
|
||
#region 指定区域
|
||
|
||
[BoxGroup("巡逻区域")] [LabelText("编辑巡逻区域"), Indent]
|
||
public bool isEditingArea;
|
||
|
||
[BoxGroup("巡逻区域")] [LabelText("编辑巡逻区域"), Indent] [ShowIf("isEditingArea")]
|
||
public List<PrescribedAreaEditorInfo> areaEditorInfos = new();
|
||
|
||
#endregion
|
||
|
||
#region 显示地图索引
|
||
|
||
[BoxGroup("显示地格索引")]
|
||
[LabelText("显示类型"), Indent]
|
||
[OnValueChanged("ShowCellIndex")]
|
||
[LabelWidth(100)]
|
||
[SerializeField]
|
||
private CellDebugInfo cellDebugInfo = CellDebugInfo.Nothing;
|
||
|
||
private void ShowCellIndex()
|
||
{
|
||
if (_curMap == null || _curMap.TerrainGridSystem == null) return;
|
||
_curMap.TerrainGridSystem.displayCellDebugInfo = cellDebugInfo;
|
||
var obj = FindObjectOfType<TerrainGridSystem>().gameObject;
|
||
Selection.activeGameObject = obj;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 敌方Npc
|
||
|
||
private GameObject enemyObjRoot;
|
||
|
||
/// <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 string selectEnemyMonsterId;
|
||
|
||
[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;
|
||
|
||
/// <summary>
|
||
/// 真实敌人列表
|
||
/// </summary>
|
||
[HideInInspector] public List<NpcEditorInfo> currentEnemyNpcInfo = null;
|
||
|
||
/// <summary>
|
||
/// 该关卡的敌方NPCID
|
||
/// </summary>
|
||
[HideInInspector] public List<int> enemyMonsterIDs;
|
||
|
||
private IEnumerable<int> GetEnemyMonsterIDs()
|
||
{
|
||
enemyMonsterIDs ??= new List<int>();
|
||
enemyMonsterIDs.Clear();
|
||
|
||
if (null == selectEnemyMonsterId)
|
||
return enemyMonsterIDs;
|
||
|
||
foreach (var monster in MonsterCfg.DataMap)
|
||
{
|
||
string strID = monster.Key.ToString();
|
||
if (!strID.StartsWith(selectEnemyMonsterId))
|
||
continue;
|
||
|
||
switch (monster.Value.NpcType)
|
||
{
|
||
case EMonsterType.EnemyCharacter:
|
||
case EMonsterType.Vehicle:
|
||
case EMonsterType.FightBuild:
|
||
{
|
||
enemyMonsterIDs.Add(monster.Key);
|
||
}
|
||
break;
|
||
case EMonsterType.SelfCharacter:
|
||
break;
|
||
default:
|
||
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
|
||
break;
|
||
}
|
||
}
|
||
|
||
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 currentEnemyNpcInfo)
|
||
{
|
||
npc.isShowNpcID = isShowAllEnemyNpcID;
|
||
if (isShowAllEnemyNpcID)
|
||
{
|
||
if (!_showNpcInfos.Contains(npc))
|
||
{
|
||
_showNpcInfos.Add(npc);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_showNpcInfos.Remove(npc);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 敌方 NPC 的分组展示数据
|
||
/// </summary>
|
||
[BoxGroup("敌方Npc")]
|
||
[LabelText("按组查看怪物"), Indent, ShowIf("isEditingEnemyNpc")]
|
||
[ShowInInspector]
|
||
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, DraggableItems = false, ShowFoldout = true)]
|
||
public List<EnemyNpcGroupView> enemyNpcGroups = new();
|
||
|
||
#endregion
|
||
|
||
#region 己方Npc
|
||
|
||
private const int SelfID = 200;
|
||
|
||
private GameObject selfObjRoot;
|
||
|
||
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 string selectSelfMonsterId;
|
||
|
||
[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()
|
||
{
|
||
selfMonsterIDs ??= new List<int>();
|
||
selfMonsterIDs.Clear();
|
||
|
||
if (null == selectSelfMonsterId)
|
||
return selfMonsterIDs;
|
||
|
||
foreach (var monster in MonsterCfg.DataMap)
|
||
{
|
||
string strID = monster.Key.ToString();
|
||
if (!strID.StartsWith(selectSelfMonsterId))
|
||
continue;
|
||
|
||
switch (monster.Value.NpcType)
|
||
{
|
||
case EMonsterType.SelfCharacter:
|
||
case EMonsterType.Vehicle:
|
||
case EMonsterType.FightBuild:
|
||
{
|
||
selfMonsterIDs.Add(monster.Key);
|
||
}
|
||
break;
|
||
case EMonsterType.EnemyCharacter:
|
||
break;
|
||
default:
|
||
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
|
||
break;
|
||
}
|
||
}
|
||
|
||
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
|
||
|
||
private GameObject midObjRoot;
|
||
|
||
/// <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 string selectMidMonsterId;
|
||
|
||
[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()
|
||
{
|
||
midMonsterIDs ??= new List<int>();
|
||
midMonsterIDs.Clear();
|
||
|
||
if (null == selectMidMonsterId)
|
||
return midMonsterIDs;
|
||
|
||
foreach (var monster in MonsterCfg.DataMap)
|
||
{
|
||
string strID = monster.Key.ToString();
|
||
if (!strID.StartsWith(selectMidMonsterId))
|
||
continue;
|
||
|
||
switch (monster.Value.NpcType)
|
||
{
|
||
case EMonsterType.Vehicle:
|
||
case EMonsterType.FightBuild:
|
||
{
|
||
midMonsterIDs.Add(monster.Key);
|
||
}
|
||
break;
|
||
case EMonsterType.EnemyCharacter:
|
||
case EMonsterType.SelfCharacter:
|
||
break;
|
||
default:
|
||
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
|
||
break;
|
||
}
|
||
}
|
||
|
||
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 阻挡球编辑
|
||
|
||
[BoxGroup("攻击阻挡球")]
|
||
[HorizontalGroup("攻击阻挡球/Block")]
|
||
[LabelText("编辑攻击阻挡球"), Indent]
|
||
[OnValueChanged("OnCanEditorBlockSphereChanged")]
|
||
[LabelWidth(100)]
|
||
[SerializeField]
|
||
private bool canEditorBlockSphere;
|
||
|
||
private void OnCanEditorBlockSphereChanged()
|
||
{
|
||
if (canEditorBlockSphere)
|
||
{
|
||
showBuildings = false;
|
||
HideObjectsExcept();
|
||
|
||
blockSphereEditorList.Clear();
|
||
UpdateBlockSphereInfo();
|
||
foreach (var cellIndex in banAttackCells)
|
||
{
|
||
if (blockSphereInfo.TryGetValue(cellIndex, out var sphereInfo))
|
||
{
|
||
var sphere = CreateSphere(cellIndex, sphereInfo.offestPos, Vector3.one * sphereInfo.scale);
|
||
var blockEditorInfo = new BlockSpereEditorInfo(sphereInfo, sphere);
|
||
blockSphereEditorList.Add(blockEditorInfo);
|
||
}
|
||
else
|
||
{
|
||
var pos = _curMap.TGSCellIndex2WorldPosition(cellIndex);
|
||
var sphere = CreateSphere(cellIndex, pos, Vector3.one * Calibre);
|
||
var blockEditorInfo = new BlockSpereEditorInfo(cellIndex, sphere);
|
||
blockSphereEditorList.Add(blockEditorInfo);
|
||
}
|
||
}
|
||
|
||
editingBlockSphereList.Clear();
|
||
foreach (var editorInfo in blockSphereEditorList)
|
||
{
|
||
if (editorInfo.isChanged)
|
||
{
|
||
editingBlockSphereList.Add(editorInfo);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 清理所有临时材质
|
||
foreach (var editorInfo in blockSphereEditorList)
|
||
{
|
||
if (editorInfo.editingMaterial != null)
|
||
{
|
||
if (editorInfo.sphere != null)
|
||
{
|
||
var renderer = editorInfo.sphere.GetComponent<Renderer>();
|
||
if (renderer != null)
|
||
{
|
||
renderer.sharedMaterial = editorInfo.originalSharedMaterial;
|
||
}
|
||
}
|
||
|
||
DestroyImmediate(editorInfo.editingMaterial);
|
||
}
|
||
}
|
||
|
||
showBuildings = true;
|
||
ShowHiddenObjects();
|
||
DestroyBlockSphere();
|
||
}
|
||
}
|
||
|
||
|
||
[LabelText("展示建筑")]
|
||
[HorizontalGroup("攻击阻挡球/BlockBuildings"), Indent]
|
||
[ShowIf("canEditorBlockSphere")]
|
||
[OnValueChanged("OnShowBuildingsChanged")]
|
||
public bool showBuildings;
|
||
|
||
private void OnShowBuildingsChanged()
|
||
{
|
||
if (showBuildings)
|
||
{
|
||
ShowHiddenObjects();
|
||
}
|
||
else
|
||
{
|
||
HideObjectsExcept();
|
||
}
|
||
}
|
||
|
||
[LabelText("添加地格")] [HorizontalGroup("攻击阻挡球/新数据"), Indent] [ShowIf("canEditorBlockSphere")]
|
||
public int addCellIndex;
|
||
|
||
[Button("添加编辑")]
|
||
[HorizontalGroup("攻击阻挡球/新数据/Add"), Indent]
|
||
[ShowIf("canEditorBlockSphere")]
|
||
public void AddBlockSphere()
|
||
{
|
||
if (!banAttackCells.Contains(addCellIndex))
|
||
{
|
||
EditorUtility.DisplayDialog("错误", $"地格 {addCellIndex} 不是攻击阻挡地格!", "确定");
|
||
return;
|
||
}
|
||
|
||
foreach (var blockSpereEditor in editingBlockSphereList)
|
||
{
|
||
if (blockSpereEditor.cellIndex == addCellIndex)
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
foreach (var blockSpereEditor in blockSphereEditorList)
|
||
{
|
||
if (blockSpereEditor.cellIndex == addCellIndex)
|
||
{
|
||
editingBlockSphereList.Add(blockSpereEditor);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
[LabelText("阻挡球列表")]
|
||
[HorizontalGroup("攻击阻挡球/EditList"), Indent]
|
||
[ShowIf("canEditorBlockSphere")]
|
||
[ListDrawerSettings(HideAddButton = true, CustomRemoveIndexFunction = "CustomRemoveBlockSphereIndex")]
|
||
public List<BlockSpereEditorInfo> editingBlockSphereList = new();
|
||
|
||
[HideInInspector] public List<BlockSpereEditorInfo> blockSphereEditorList = new();
|
||
|
||
private void CustomRemoveBlockSphereIndex(int index)
|
||
{
|
||
if (index < editingBlockSphereList.Count)
|
||
{
|
||
editingBlockSphereList[index].Revert();
|
||
DebugUtil.Log($"删除并还原{editingBlockSphereList[index].cellIndex}的阻挡球编辑数据");
|
||
editingBlockSphereList.RemoveAt(index);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 保存
|
||
|
||
[Button("保存当前关卡"), Indent]
|
||
private void SaveCurrentLevel()
|
||
{
|
||
CheckCorrectLevel();
|
||
|
||
if (!CheckTask())
|
||
return;
|
||
|
||
// 条件
|
||
currentLevelData.taskInfos = taskInfos.Select(t => t.taskInfo).ToList();
|
||
|
||
/*// 胜利失败星级条件
|
||
currentLevelData.successTaskID = successTaskID;
|
||
currentLevelData.failTaskID = failTaskID;
|
||
for (var i = 0; i < starTaskIDs.Count; i++)
|
||
{
|
||
currentLevelData.starTaskIDs[i] = starTaskIDs[i];
|
||
}*/
|
||
|
||
// 地区
|
||
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
|
||
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
|
||
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
|
||
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
|
||
|
||
// 评分关卡
|
||
currentLevelData.scoreTaskID = scoreTasks.Select(s => s.scoreTaskID).ToList();
|
||
|
||
//触发器
|
||
currentLevelData.levelTriggerDatas = levelTriggerData.Select(e => e.levelTriggerData).ToList();
|
||
|
||
#region 敌方NPC
|
||
|
||
foreach (var npcEditor in currentEnemyNpcInfo)
|
||
{
|
||
npcEditor.npcInfo.index = npcEditor.id;
|
||
}
|
||
|
||
currentLevelData.npcInfos = currentEnemyNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
|
||
|
||
#endregion
|
||
|
||
#region 己方NPC
|
||
|
||
foreach (var npcFightEditorInfo in currentSelfNpcInfo)
|
||
{
|
||
npcFightEditorInfo.npcInfo.index = npcFightEditorInfo.id;
|
||
}
|
||
|
||
currentLevelData.selfNpcInfos =
|
||
currentSelfNpcInfo.Select(editorFightNpcInfo => editorFightNpcInfo.npcInfo).ToList();
|
||
|
||
#endregion
|
||
|
||
#region 中立NPC
|
||
|
||
foreach (var npcEditor in currentMidNpcInfo)
|
||
{
|
||
npcEditor.npcInfo.index = npcEditor.id;
|
||
}
|
||
|
||
currentLevelData.midNpcInfos = currentMidNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
|
||
|
||
#endregion
|
||
|
||
// 占领数据
|
||
currentLevelData.CapturePoints.Clear();
|
||
foreach (var captureInfo in captureEditorInfos)
|
||
{
|
||
var points = captureInfo.capturePointEditorInfos.Select(x => x.capturePoint).ToList();
|
||
var flagPoint = 0;
|
||
|
||
foreach (var pointData in captureInfo.capturePointEditorInfos)
|
||
{
|
||
if (pointData.captureFlag)
|
||
flagPoint = pointData.capturePoint;
|
||
}
|
||
|
||
var capture = new CaptureInfo
|
||
{
|
||
captureRegionID = captureInfo.captureRegionID,
|
||
capturePoints = points,
|
||
captureFlag = flagPoint,
|
||
CaptureProgress = captureInfo.captureProgress,
|
||
captureEffectID = captureInfo.captureEffectID,
|
||
captureEffectPoint = captureInfo.captureEffectPoint,
|
||
};
|
||
currentLevelData.CapturePoints.Add(capture);
|
||
}
|
||
|
||
// 扛旗数据
|
||
currentLevelData.flagStartPoints.Clear();
|
||
currentLevelData.flagEndPoints.Clear();
|
||
foreach (var flag in flagEditorInfo.flagStartPoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(flag);
|
||
currentLevelData.flagStartPoints.Add(cellIndex);
|
||
}
|
||
|
||
foreach (var flag in flagEditorInfo.flagEndPoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(flag);
|
||
currentLevelData.flagEndPoints.Add(cellIndex);
|
||
}
|
||
|
||
// 撤离数据
|
||
currentLevelData.retreatPoints.retreatPoints.Clear();
|
||
currentLevelData.retreatPoints.retreatFlag = -1;
|
||
foreach (var retreatPoint in retreatEditorInfo)
|
||
{
|
||
if (retreatPoint.retreatFlag)
|
||
currentLevelData.retreatPoints.retreatFlag = retreatPoint.retreatPoint;
|
||
currentLevelData.retreatPoints.retreatPoints.Add(retreatPoint.retreatPoint);
|
||
}
|
||
|
||
// 撤离数据
|
||
currentLevelData.enemyRetreatReusablePoints.Clear();
|
||
foreach (var fallback in enemyRetreatEditorInfo.fallbackReusablePoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(fallback);
|
||
currentLevelData.enemyRetreatReusablePoints.Add(cellIndex);
|
||
}
|
||
|
||
// 指定路径
|
||
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.Select(p => p.progressGuideData).ToList();
|
||
|
||
// 立标数据
|
||
currentLevelData.setFlagGuideDatas = setFlagEditorInfos.Select(f => f.flagGuideData).ToList();
|
||
|
||
// 信息板数据
|
||
currentLevelData.infoPanelGuideDatas = infoPanelGuideDatas.Select(i => i.infoPanelGuideData).ToList();
|
||
|
||
// 关卡广播
|
||
currentLevelData.listAIBroadcastData = listAIBroadcastData.Select(a => a.aiBroadcastData).ToList();
|
||
|
||
// 处理条件
|
||
ProcessCondition();
|
||
|
||
// 阻挡球
|
||
SaveBlockSphereInfo();
|
||
|
||
_levelEditor.SaveLevelData();
|
||
_mapManager.SaveMapData();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 关卡ID相关
|
||
|
||
/// <summary>
|
||
/// 关卡ID 通过关卡数据 json文件名 获得
|
||
/// </summary>
|
||
[LabelText("手动指定关卡ID"), Indent, LabelWidth(100), ShowIf("needManualInputLevelID")]
|
||
[InfoBox("无法正确获得关卡ID,请手动指定")]
|
||
[SerializeField]
|
||
public string levelID;
|
||
|
||
/// <summary>
|
||
/// 需要手动输入关卡ID
|
||
/// </summary>
|
||
[HideInInspector] public bool needManualInputLevelID;
|
||
|
||
#endregion
|
||
|
||
#region Npc某些值改变时响应事件
|
||
|
||
private void ReorderEnemyNpcID()
|
||
{
|
||
for (var i = 0; i < currentEnemyNpcInfo.Count; i++)
|
||
{
|
||
currentEnemyNpcInfo[i].id = i + 1;
|
||
currentEnemyNpcInfo[i].npcInfo.index = currentEnemyNpcInfo[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)
|
||
{
|
||
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
|
||
if (enemyObjRoot == null)
|
||
enemyObjRoot = new GameObject("enemyObjRoot");
|
||
if (obj != null)
|
||
obj.transform.SetParent(enemyObjRoot.transform);
|
||
|
||
npcEditorInfo.npcInfo.id = newMonsterID;
|
||
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
|
||
npcObjectDic[npcEditorInfo] = obj;
|
||
|
||
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)
|
||
{
|
||
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
|
||
|
||
if (midObjRoot == null)
|
||
midObjRoot = new GameObject("midObjRoot");
|
||
|
||
if (obj != null)
|
||
obj.transform.SetParent(midObjRoot.transform);
|
||
|
||
npcEditorInfo.npcInfo.id = newMonsterID;
|
||
npcEditorInfo.level = MonsterCfg.DataMap[newMonsterID].MonsterLevel;
|
||
npcObjectDic[npcEditorInfo] = obj;
|
||
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)
|
||
{
|
||
var obj = Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
|
||
|
||
if (selfObjRoot == null)
|
||
selfObjRoot = new GameObject("selfObjRoot");
|
||
|
||
if (obj != null)
|
||
obj.transform.SetParent(selfObjRoot.transform);
|
||
|
||
npcInfoInfo.id = newMonsterID;
|
||
_selfNpcObjectDic[npcInfoInfo.position] = obj;
|
||
DestroyImmediate(npcObj);
|
||
DebugUtil.Log("位置上[ {0} ]的fight怪物ID改为: [ {1} ] ", npcInfoInfo.position, npcInfoInfo.id);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
} |