using Gameplay; using Sirenix.OdinInspector; using Sirenix.OdinInspector.Editor; using Sirenix.Utilities; using Sirenix.Utilities.Editor; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using TGS; using UnityEditor; using UnityEngine; using UnityEngine.InputSystem.EnhancedTouch; using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment; namespace MapEditor { public class MapGridWindow : OdinEditorWindow { #region Fields And Properties private static MapGridWindow thisWindow; private static Dictionary _terrainTypeConfig; private MapData _currentMapData; private MapManager _currMapManager; private Map _map; #endregion #region 刷地块信息 [BoxGroup("地块信息")] [LabelText("刷地块"), Indent] [OnValueChanged("OnCanBrushTerrainTypeChanged")] [LabelWidth(100)] [SerializeField] [ShowIf("@!canEditorArea")] private bool canBrushTerrainType; private void OnCanBrushTerrainTypeChanged() { if (canBrushTerrainType && _map != null) { canEditorArea = false; canEditorBlockArea = false; canEditorDefenseArea = false; ClearBlockRegionColor(); ClearRegionColor(); ClearDefenseRegionColor(); } } [HorizontalGroup("地块信息/Territory")] [ValueDropdown("GetTerrainTypeProperties")] [Indent] [LabelText("选择地块")] [ShowIf("canBrushTerrainType")] public int TerrainTypeIndex = 0; private static IEnumerable GetTerrainTypeProperties() { ValueDropdownList list = new(); foreach (TerrainTypeProperty terrainTypeProperty in TerrainTypeConfig.DicTerrainTypePropertie.Values) { list.Add(terrainTypeProperty.name, terrainTypeProperty.id); } return list; } [ShowIf("canBrushTerrainType")] [HorizontalGroup("地块信息/Territory")] [Button(SdfIconType.GearFill, "编辑地块")] public void EditTerrainTypeConfig() { var window = GetWindow(); window.Show(); } private void SetCellBlockType(int cellIndex, int TerrainTypeIndex) { if (!_terrainTypeConfig.TryGetValue(TerrainTypeIndex, out TerrainTypeProperty terrainTypeProperty)) { DebugUtil.LogError($"没有取到地格属性,id:{TerrainTypeIndex}"); return; } var map = _map; // Key: TerrainTypeIndex Value: tgs.territories.index if (!map.TerrainTypeIndexDic.ContainsKey(TerrainTypeIndex)) map.TerrainTypeIndexDic.Add(TerrainTypeIndex, map.TerrainTypeIndexDic.Count); map.TerrainGridSystem.CellSetBorderVisible(cellIndex, false); map.SetTerrainType(cellIndex, TerrainTypeIndex); map.TerrainGridSystem.CellToggleRegionSurface(cellIndex, true, terrainTypeProperty.Color); var buffPath = terrainTypeProperty.buffObjectPath; if (!string.IsNullOrEmpty(buffPath)) AddBuffCell(cellIndex, buffPath); Debug.Log( $"Set Territory, cellIndex ({cellIndex}), terrain type ({TerrainTypeIndex}), name ({terrainTypeProperty.Color})"); } private void ClearCellBlockType(int cellIndex) { if (!_terrainTypeConfig.TryGetValue(TerrainTypeIndex, out TerrainTypeProperty terrainTypeProperty)) { DebugUtil.LogError($"没有取到地格属性,id:{TerrainTypeIndex}"); return; } var map = _map; map.TerrainGridSystem.CellSetBorderVisible(cellIndex, true); map.TerrainGridSystem.CellHideRegionSurface(cellIndex); _map.SetBlockColor(cellIndex, false, terrainTypeProperty.Color); map?.SetTerrainType(cellIndex, -1); var buffPath = terrainTypeProperty.buffObjectPath; if (!string.IsNullOrEmpty(buffPath)) { RemoveBuffCell(cellIndex); } Debug.Log($"Cell Clear Territory, cellIndex({cellIndex})"); } #region 地块指示物 private Dictionary _buffPrefabDic; private GameObject buffRoot; private void AddBuffCell(int cellIndex, string path) { // 阵地buff指示 if (!_buffPrefabDic.ContainsKey(cellIndex)) { var buff = CreateBuffObj(cellIndex, path); if (buff == null) return; _buffPrefabDic.Add(cellIndex, buff); DebugUtil.Log("格子{0}添加指示图标,路径为{1}", cellIndex, path); } } private void RemoveBuffCell(int cellIndex) { if (_buffPrefabDic.TryGetValue(cellIndex, out var buff)) { if (buff != null) { DestroyImmediate(buff); } _buffPrefabDic.Remove(cellIndex); DebugUtil.Log("格子{0}移除指示图标", cellIndex); } } private GameObject CreateBuffObj(int cellIndex, string path) { var buffObj = AssetDatabase.LoadAssetAtPath(path); if (buffObj == null) { DebugUtil.LogError($"{path} 路径下无Buff指示预制体 "); return null; } if (buffRoot == null) buffRoot = new GameObject("buffRoot"); var posV3 = _map.TGSCellIndex2WorldPosition(cellIndex); var buff = Instantiate(buffObj, posV3, buffObj.transform.rotation, buffRoot.transform); buff.SetActive(true); return buff; } #endregion #endregion #region 地区信息 private static readonly Color regionColor = MapUtils.GetRGBAColor("FF960072"); private static bool canEditorSingleRegion = false; private RegionArea _currEditRegionArea; [Serializable] public class RegionArea { [HorizontalGroup("1")] [ReadOnly] public int id; [HorizontalGroup("1")] [ReadOnly] [LabelText("数量")] public int regionCount; [LabelText("备注"), HorizontalGroup("1")] [OnValueChanged("OnNoteValueChanged")] public string note; private void OnNoteValueChanged() { _region.note = note; } public List positions => _region.positions; private MapData.Region _region; public RegionArea(MapData.Region region) { _region = region; note = _region.note; } [Button("编辑"), HorizontalGroup("1")] private void EditorRegion() { var map = thisWindow._map; thisWindow._currEditRegionArea = this; var regionslist = map.MapData.regions; for (int i = 0; i < regionslist.Count; i++) { map.SetRegionColor(i, false, regionColor); } map.SetRegionColor(_region, true, regionColor); canEditorSingleRegion = true; } public void AddPosition(int cellIndex) { if (positions.Contains(cellIndex)) return; positions.Add(cellIndex); regionCount++; thisWindow._map.TerrainGridSystem.CellToggleRegionSurface(cellIndex, true, regionColor); } public void RemovePosition(int cellIndex) { if (!positions.Contains(cellIndex)) return; positions.Remove(cellIndex); regionCount--; thisWindow._map.TerrainGridSystem.CellHideRegionSurface(cellIndex); } } [BoxGroup("地区信息")] [HorizontalGroup("地区信息/Region")] [LabelText("编辑地区"), Indent] [OnValueChanged("OnCanEditorAreaTypeChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorArea; private void OnCanEditorAreaTypeChanged() { if (canEditorArea) { canBrushTerrainType = false; canEditorBlockArea = false; canEditorDefenseArea = false; canEditorSingleBlockRegion = false; canEditorSingleDefenseRegion = false; ClearDefenseRegionColor(); ClearBlockRegionColor(); } else { ClearRegionColor(); SceneView.RepaintAll(); canEditorSingleRegion = false; _currEditRegionArea = null; } } [LabelText("地区列表")] [ShowIf("canEditorArea")] [VerticalGroup("地区信息/RegionInfo"), Indent] [ListDrawerSettings(CustomAddFunction = "CustomAddRegion", CustomRemoveIndexFunction = "CustomRemoveRegion", DraggableItems = false)] public List RegionList = new(); private void CustomAddRegion() { var region = new MapData.Region(); _currentMapData.regions.Add(region); UpdateRegion(); } private void CustomRemoveRegion(int index) { ClearRegionColor(); _currentMapData.regions.RemoveAt(index); UpdateRegion(); } private void UpdateRegion() { RegionList.Clear(); if (_currentMapData != null) { int index = 0; foreach (var region in _currentMapData.regions) { RegionArea ra = new RegionArea(region); ra.id = index; ra.regionCount = ra.positions.Count; RegionList.Add(ra); index++; } } } private void ClearRegionColor() { if (_map == null) return; for (int i = 0; i < _map.MapData.regions.Count; i++) { _map.SetRegionColor(i, false, regionColor); } } #endregion #region 阻挡区信息 private static readonly Color BlockRegionColor = Color.blue; private BlockRegionArea _currEditBlockRegion; private static bool canEditorSingleBlockRegion = false; private Dictionary _blockPrefabDic; private GameObject blockRoot; [Serializable] public class BlockRegionArea { private const string BuffPrefabPath = "Art_Out/Other/BuffPoint"; [HorizontalGroup("1")] [ReadOnly] public int id; [HorizontalGroup("1")] [ReadOnly] [LabelText("数量")] public int regionCount; [LabelText("备注"), HorizontalGroup("1")] [OnValueChanged("OnNoteValueChanged")] public string note; private void OnNoteValueChanged() { _region.note = note; } [Button("编辑"), HorizontalGroup("1")] private void EditorRegion() { var map = thisWindow._map; thisWindow._currEditBlockRegion = this; var regionsList = map.MapData.blockRegions; foreach (var blockRegion in regionsList) { map.SetBlocksColor(blockRegion.positions, false, BlockRegionColor); } map.SetBlocksColor(_region.positions, true, BlockRegionColor); canEditorSingleBlockRegion = true; } [HorizontalGroup("3")] [PreviewField(50, ObjectFieldAlignment.Center)] [LabelText("指示预览图"), OnValueChanged("OnObjectValueChanged")] [AssetList(Path = BuffPrefabPath)] public GameObject buffObject; private void OnObjectValueChanged() { if (buffObject != null) { _region.path = "Assets/" + BuffPrefabPath + "/" + buffObject.name + ".prefab"; } } [HorizontalGroup("2")] [LabelText("指示位置"), OnValueChanged("OnPosValueChanged")] public Vector3 pos = Vector3.zero; private void OnPosValueChanged() { _region.centerPos = pos; if (obj != null) { obj.transform.position = pos; } } [Button("添加至场景"), HorizontalGroup("3")] [ShowIf("NeedAdd")] private void AddToScene() { obj = thisWindow.CreateBlockObj(_region.path, pos); } [Button("更换指示"), HorizontalGroup("3")] [HideIf("NeedAdd")] private void ChangeObj() { if (obj) DestroyImmediate(obj); obj = thisWindow.CreateBlockObj(_region.path, pos); } private bool NeedAdd => obj == null; [HideInInspector] public GameObject obj; public List Positions => _region.positions; [HideInInspector] public MapData.BlockRegion _region; public BlockRegionArea(MapData.BlockRegion region) { _region = region; pos = _region.centerPos; note = _region.note; if (!string.IsNullOrEmpty(region.path)) { obj = thisWindow.CreateBlockObj(_region.path, _region.centerPos); buffObject = AssetDatabase.LoadAssetAtPath(_region.path); } } public void AddPosition(int cellIndex) { if (Positions.Contains(cellIndex)) return; Positions.Add(cellIndex); DebugUtil.Log($"{id}阻挡区添加地格{cellIndex}"); regionCount++; thisWindow._map.TerrainGridSystem.CellToggleRegionSurface(cellIndex, true, BlockRegionColor); } public void RemovePosition(int cellIndex) { if (!Positions.Contains(cellIndex)) return; Positions.Remove(cellIndex); DebugUtil.Log($"{id}阻挡区移除地格{cellIndex}"); regionCount--; thisWindow._map.TerrainGridSystem.CellHideRegionSurface(cellIndex); } } [BoxGroup("阻挡区信息")] [HorizontalGroup("阻挡区信息/Region")] [LabelText("编辑阻挡区"), Indent] [OnValueChanged("OnCanEditorBlockAreaChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorBlockArea; private void OnCanEditorBlockAreaChanged() { if (canEditorBlockArea) { canEditorArea = false; canBrushTerrainType = false; canEditorDefenseArea = false; canEditorSingleRegion = false; canEditorSingleDefenseRegion = false; ClearDefenseRegionColor(); ClearRegionColor(); } else { ClearBlockRegionColor(); SceneView.RepaintAll(); _currEditBlockRegion = null; canEditorSingleBlockRegion = false; } } [LabelText("阻挡区列表")] [ShowIf("canEditorBlockArea")] [VerticalGroup("阻挡区信息/RegionInfo"), Indent] [ListDrawerSettings(CustomAddFunction = "CustomAddBlockRegion", CustomRemoveIndexFunction = "CustomRemoveBlockRegionIndex", DraggableItems = false)] public List blockRegionList = new(); private void CustomAddBlockRegion() { var region = new MapData.BlockRegion(); _currentMapData.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(); _currentMapData.blockRegions.RemoveAt(index); UpdateBlockRegion(); } private void UpdateBlockRegion() { blockRegionList.Clear(); if (_currentMapData != null) { var index = 0; foreach (var region in _currentMapData.blockRegions) { var blockRegion = new BlockRegionArea(region) { id = index, regionCount = region.positions.Count, }; blockRegionList.Add(blockRegion); index++; } } } private void ClearBlockRegionColor() { if (_map == null) return; foreach (var blockRegion in _map.MapData.blockRegions) { _map.SetBlocksColor(blockRegion.positions, false, BlockRegionColor); } } private GameObject CreateBlockObj(string path, Vector3 pos) { var blockObj = AssetDatabase.LoadAssetAtPath(path); if (blockObj == null) { DebugUtil.LogError($"{path} 路径下无Block指示预制体 "); return null; } if (blockRoot == null) blockRoot = new GameObject("BlockRoot"); var obj = Instantiate(blockObj, pos, blockObj.transform.rotation, blockRoot.transform); obj.SetActive(true); return obj; } private void DestroyAllBlockObj() { if (blockRoot) DestroyImmediate(blockRoot); foreach (var blockRegion in blockRegionList) { if (blockRegion.obj) DestroyImmediate(blockRegion.obj); } } #endregion #region 防守区信息 private static readonly Color DefenseRegionColor = Color.magenta; private DefenseRegionArea _currEditDefenseRegion; private static bool canEditorSingleDefenseRegion = false; [Serializable] public class DefenseRegionArea { [HorizontalGroup("1")] [ReadOnly] public int id; [HorizontalGroup("1")] [ReadOnly] [LabelText("数量")] public int regionCount; [LabelText("备注"), HorizontalGroup("1")] [OnValueChanged("OnNoteValueChanged")] public string note; private void OnNoteValueChanged() { _region.note = note; } public List Positions => _region.positions; private MapData.Region _region; public DefenseRegionArea(MapData.Region region) { _region = region; note = _region.note; } [Button("编辑"), HorizontalGroup("1")] private void EditorRegion() { var map = thisWindow._map; thisWindow._currEditDefenseRegion = this; var regionsList = map.MapData.defenseRegions; foreach (var defenseRegion in regionsList) { map.SetBlocksColor(defenseRegion.positions, false, DefenseRegionColor); } map.SetBlocksColor(_region.positions, true, DefenseRegionColor); canEditorSingleDefenseRegion = true; } public void AddPosition(int cellIndex) { if (Positions.Contains(cellIndex)) return; Positions.Add(cellIndex); DebugUtil.Log($"{id}防守区添加地格{cellIndex}"); regionCount++; thisWindow._map.TerrainGridSystem.CellToggleRegionSurface(cellIndex, true, DefenseRegionColor); } public void RemovePosition(int cellIndex) { if (!Positions.Contains(cellIndex)) return; Positions.Remove(cellIndex); DebugUtil.Log($"{id}防守区移除地格{cellIndex}"); regionCount--; thisWindow._map.TerrainGridSystem.CellHideRegionSurface(cellIndex); } } [BoxGroup("防守区信息")] [HorizontalGroup("防守区信息/Region")] [LabelText("编辑防守区"), Indent] [OnValueChanged("OnCanEditorDefenseAreaChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorDefenseArea; private void OnCanEditorDefenseAreaChanged() { if (canEditorDefenseArea) { canEditorBlockArea = false; canEditorArea = false; canBrushTerrainType = false; canEditorSingleRegion = false; canEditorSingleBlockRegion = false; ClearBlockRegionColor(); ClearRegionColor(); } else { ClearDefenseRegionColor(); SceneView.RepaintAll(); _currEditDefenseRegion = null; canEditorSingleDefenseRegion = false; } } [LabelText("防守区列表")] [ShowIf("canEditorDefenseArea")] [VerticalGroup("防守区信息/RegionInfo"), Indent] [ListDrawerSettings(CustomAddFunction = "CustomAddDefenseRegion", CustomRemoveIndexFunction = "CustomRemoveDefenseRegion", DraggableItems = false)] public List defenseRegionList = new(); private void CustomAddDefenseRegion() { var region = new MapData.Region(); _currentMapData.defenseRegions.Add(region); UpdateDefenseRegion(); } private void CustomRemoveDefenseRegion(int index) { ClearDefenseRegionColor(); _currentMapData.defenseRegions.RemoveAt(index); UpdateDefenseRegion(); } private void UpdateDefenseRegion() { defenseRegionList.Clear(); if (_currentMapData != null) { var index = 0; foreach (var region in _currentMapData.defenseRegions) { var defenseRegion = new DefenseRegionArea(region) { id = index, regionCount = region.positions.Count, }; defenseRegionList.Add(defenseRegion); index++; } } } private void ClearDefenseRegionColor() { if (_map == null) return; foreach (var defenseRegion in _map.MapData.defenseRegions) { _map.SetBlocksColor(defenseRegion.positions, false, DefenseRegionColor); } } #endregion #region 功能 [Button("保存")] private void RebuildPrefab() { foreach (var blockRegionArea in blockRegionList) { blockRegionArea._region.id = blockRegionArea.id; } _currMapManager.SaveMapData(); } [Button("清除网格数据")] private void ClearGridData() { if (EditorUtility.DisplayDialog("清理网格数据", "您是否确认清理地图网格数据", "确认", "取消")) { _currentMapData.ClearGridData(); _map.TerrainGridSystem.TerritoryDestroyAll(); ClearRegionColor(); ClearBlockRegionColor(); ClearDefenseRegionColor(); UpdateRegion(); UpdateBlockRegion(); UpdateDefenseRegion(); _currMapManager.SaveMapData(); } } #endregion #region MainLife public static void OpenWindow(MapManager mapSceneEditor) { MapEditorSettings.Init(); thisWindow = GetWindow(); thisWindow.name = "MapGridWindow"; thisWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600); thisWindow._currMapManager = mapSceneEditor; thisWindow._currentMapData = null; thisWindow.ShowTab(); thisWindow.LoadMap(mapSceneEditor.TGS, mapSceneEditor.MapData, mapSceneEditor.Map); thisWindow.LoadBuffPrefab(); UnityEditor.Compilation.CompilationPipeline.compilationStarted += OnCompilationStart; } private static void OnCompilationStart(object obj) { thisWindow?.Close(); thisWindow = null; } private void LoadBuffPrefab() { DestroyBuffObj(); _buffPrefabDic.Clear(); var buffObjCells = _map.MapData.showBuffPoints; foreach (var cell in buffObjCells) { var buffObj = CreateBuffObj(cell.cellIndex, cell.path); _buffPrefabDic.TryAdd(cell.cellIndex, buffObj); } } private void DestroyBuffObj() { if (_buffPrefabDic == null) return; _buffPrefabDic.Clear(); DestroyImmediate(buffRoot); buffRoot = null; } private void LoadMap(TerrainGridSystem tgs, MapData data, Map map) { _currentMapData = data; _map = map; _terrainTypeConfig = TerrainTypeConfig.DicTerrainTypePropertie; _map.TerrainGridSystem.highlightEffect = HighlightEffect.Default; tgs.OnMouseClickOnGrid += OnMouseClickCell; DestroyAllBlockObj(); UpdateRegion(); UpdateBlockRegion(); UpdateDefenseRegion(); } protected override void OnEnable() { EnhancedTouchSupport.Enable(); TerrainTypeConfig.Load(); _buffPrefabDic = new Dictionary(); _blockPrefabDic = new Dictionary(); base.OnEnable(); } protected override void OnDisable() { DestroyBuffObj(); _buffPrefabDic = null; _blockPrefabDic = null; EnhancedTouchSupport.Disable(); base.OnDisable(); } protected override void OnGUI() { base.OnGUI(); if (_currMapManager == null || _currMapManager.MapData != _currentMapData) { Debug.Log("地图数据变更,请重新点击编辑网格!"); Close(); } } protected override void OnDestroy() { base.OnDestroy(); DestroyBuffObj(); DestroyAllBlockObj(); if (_currMapManager != null) _currMapManager.SaveMapData(); ClearRegionColor(); ClearBlockRegionColor(); ClearDefenseRegionColor(); _map.TerrainGridSystem.OnMouseClickOnGrid -= OnMouseClickCell; UnityEditor.Compilation.CompilationPipeline.compilationStarted -= OnCompilationStart; } #endregion #region 点击事件 private void OnMouseClickCell(TerrainGridSystem tgs, int cellIndex, int buttonIndex) { int leftButton = 0; OnCellOperation(tgs, cellIndex, buttonIndex == leftButton); } private void OnCellOperation(TerrainGridSystem tgs, int cellIndex, bool isOpTrue) { if (!canBrushTerrainType && !canEditorArea && !canEditorBlockArea && !canEditorDefenseArea) return; if (canEditorArea && _currEditRegionArea == null) return; if (canEditorBlockArea && _currEditBlockRegion == null) return; if (canEditorDefenseArea && _currEditDefenseRegion == null) return; // 地块 if (isOpTrue && TerrainTypeIndex >= 0 && canBrushTerrainType) { SetCellBlockType(cellIndex, TerrainTypeIndex); } else if (!isOpTrue && canBrushTerrainType) { if (_currentMapData.BlocksData[cellIndex].TerrainTypeIndex == TerrainTypeIndex) { ClearCellBlockType(cellIndex); } } // 普通地区 if (isOpTrue && canEditorSingleRegion && _currEditRegionArea != null) { _currEditRegionArea.AddPosition(cellIndex); } else if (!isOpTrue && canEditorSingleRegion && _currEditRegionArea != null) { _currEditRegionArea.RemovePosition(cellIndex); } // 阻挡区 if (isOpTrue && canEditorSingleBlockRegion && _currEditBlockRegion != null) { _currEditBlockRegion.AddPosition(cellIndex); } else if (!isOpTrue && canEditorSingleBlockRegion && _currEditBlockRegion != null) { _currEditBlockRegion.RemovePosition(cellIndex); } // 防守区 if (isOpTrue && canEditorSingleDefenseRegion && _currEditDefenseRegion != null) { _currEditDefenseRegion.AddPosition(cellIndex); } else if (!isOpTrue && canEditorSingleDefenseRegion && _currEditDefenseRegion != null) { _currEditDefenseRegion.RemovePosition(cellIndex); } } #endregion } }