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 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 static Dictionary _legionTerrainTypeConfig; private MapData _currentMapData; private MapManager _currMapManager; private Map _map; private bool _isLegionMap; #endregion #region 显示地图索引功能 [BoxGroup("显示地格索引")] [LabelText("显示类型"), Indent] [OnValueChanged("ShowCellIndex")] [LabelWidth(100)] [SerializeField] private CellDebugInfo cellDebugInfo = CellDebugInfo.Nothing; private void ShowCellIndex() { if (_map == null || _map.TerrainGridSystem == null) return; _map.TerrainGridSystem.displayCellDebugInfo = cellDebugInfo; var obj = FindObjectOfType().gameObject; Selection.activeGameObject = obj; } #endregion #region 刷地块信息 [BoxGroup("地块信息")] [LabelText("刷地块"), Indent] [OnValueChanged("OnCanBrushTerrainTypeChanged")] [LabelWidth(100)] [SerializeField] [ShowIf("@!canEditorArea")] private bool canBrushTerrainType; private void OnCanBrushTerrainTypeChanged() { if (canBrushTerrainType && _map != null) { canEditorArea = false; ClearRegionColor(); } } [HorizontalGroup("地块信息/Territory")] [ValueDropdown("GetTerrainTypeProperties")] [Indent] [LabelText("选择地块")] [ShowIf("canBrushTerrainType")] public int terrainTypeIndex = 0; private IEnumerable GetTerrainTypeProperties() { ValueDropdownList list = new(); if (!_isLegionMap) foreach (var terrainTypeProperty in TerrainTypeConfig.DicTerrainTypePropertie.Values) { list.Add(terrainTypeProperty.name, terrainTypeProperty.id); } else foreach (var legionTerrainTypeProperty in LegionTerrainTypeConfig.DicTerrainTypePropertie.Values) { list.Add(legionTerrainTypeProperty.name, legionTerrainTypeProperty.id); } return list; } [ShowIf("canBrushTerrainType")] [HorizontalGroup("地块信息/Territory")] [Button(SdfIconType.GearFill, "编辑地块")] public void EditTerrainTypeConfig() { if (!_isLegionMap) { var window = GetWindow(); window.Show(); } else { var window = GetWindow(); window.Show(); } } private void SetCellBlockType(int cellIndex, int terrainTypeIndex) { if (!_isLegionMap) { 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( $"设置地格: ({cellIndex}), 地格类型: ({terrainTypeIndex}), 名字: ({terrainTypeProperty.name})"); } else { if (!_legionTerrainTypeConfig.TryGetValue(terrainTypeIndex, out var terrainTypeProperty)) { DebugUtil.LogError($"没有取到军团地格属性,id:{terrainTypeIndex}"); return; } var map = _map; // Key: terrainTypeIndex Value: tgs.territories.index if (!map.LegionTerrainTypeIndexDic.ContainsKey(terrainTypeIndex)) map.LegionTerrainTypeIndexDic.Add(terrainTypeIndex, map.LegionTerrainTypeIndexDic.Count); map.TerrainGridSystem.CellSetBorderVisible(cellIndex, false); map.SetTerrainType(cellIndex, terrainTypeIndex, true); map.TerrainGridSystem.CellToggleRegionSurface(cellIndex, true, terrainTypeProperty.Color); var buffPath = terrainTypeProperty.buffObjectPath; if (!string.IsNullOrEmpty(buffPath)) { AddBuffCell(cellIndex, buffPath); } Debug.Log( $"设置军团地格: ({cellIndex}), 地格类型: ({terrainTypeIndex}), 名字: ({terrainTypeProperty.name})"); } } private void ClearCellBlockType(int cellIndex) { if (!_isLegionMap) { 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($"清除地格cellIndex: ({cellIndex})"); } else { if (!_legionTerrainTypeConfig.TryGetValue(terrainTypeIndex, out var 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, true); var buffPath = terrainTypeProperty.buffObjectPath; if (!string.IsNullOrEmpty(buffPath)) { RemoveBuffCell(cellIndex); } Debug.Log($"清除军团地格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); /*var showBuffData = new MapData.ShowBuffData _currentMapData.showBuffPoints.Add();*/ 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] [ShowIf("@!_isLegionMap")] [OnValueChanged("OnCanEditorAreaTypeChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorArea; private void OnCanEditorAreaTypeChanged() { if (canEditorArea) { canBrushTerrainType = false; } else { ClearRegionColor(); SceneView.RepaintAll(); canEditorSingleRegion = false; _currEditRegionArea = null; } } [LabelText("地区列表")] [ShowIf("@!_isLegionMap&&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 MinesColor = MapUtils.GetRGBAColor("2D004CFF"); private static bool canEditorSingleMinesRegion; private MinesRegionArea _currEditMinesRegionArea; [Serializable] public class MinesRegionArea { [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 MinesRegionArea(MapData.Region region) { _region = region; note = _region.note; } [Button("编辑"), HorizontalGroup("1")] private void EditorRegion() { var map = _thisWindow._map; _thisWindow._currEditMinesRegionArea = this; var regionList = map.MapData.minesRegions; foreach (var region in regionList) { map.SetBlocksColor(region.positions, false, MinesColor); } map.SetBlocksColor(_region.positions, true, MinesColor); canEditorSingleMinesRegion = true; } public void AddPosition(int cellIndex) { if (positions.Contains(cellIndex)) return; positions.Add(cellIndex); regionCount++; _thisWindow._map.TerrainGridSystem.CellToggleRegionSurface(cellIndex, true, MinesColor); } public void RemovePosition(int cellIndex) { if (!positions.Contains(cellIndex)) return; positions.Remove(cellIndex); regionCount--; _thisWindow._map.TerrainGridSystem.CellHideRegionSurface(cellIndex); } } [BoxGroup("雷区信息")] [HorizontalGroup("雷区信息/Region")] [LabelText("编辑雷区"), Indent] [ShowIf("@!_isLegionMap")] [OnValueChanged("OnCanEditorMinesAreaTypeChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorMinesArea; private void OnCanEditorMinesAreaTypeChanged() { if (canEditorMinesArea) { canEditorArea = false; canBrushTerrainType = false; canEditorBlockArea = false; canEditorDefenseArea = false; canEditorSingleBlockRegion = false; canEditorSingleDefenseRegion = false; ClearDefenseRegionColor(); ClearBlockRegionColor(); ClearRegionColor(); } else { ClearMinesRegionColor(); SceneView.RepaintAll(); canEditorSingleMinesRegion = false; _currEditMinesRegionArea = null; } } [LabelText("雷区列表")] [ShowIf("@!_isLegionMap&&canEditorMinesArea")] [VerticalGroup("雷区信息/RegionInfo"), Indent] [ListDrawerSettings(CustomAddFunction = "CustomAddMinesRegion", CustomRemoveIndexFunction = "CustomRemoveMinesRegion", DraggableItems = false)] public List minesRegionList = new(); private void CustomAddMinesRegion() { var region = new MapData.Region(); _currentMapData.minesRegions.Add(region); UpdateMinesRegion(); } private void CustomRemoveMinesRegion(int index) { ClearMinesRegionColor(); _currentMapData.minesRegions.RemoveAt(index); UpdateMinesRegion(); } private void UpdateMinesRegion() { minesRegionList.Clear(); if (_currentMapData != null) { var index = 0; foreach (var region in _currentMapData.minesRegions) { MinesRegionArea ra = new MinesRegionArea(region) { id = index }; ra.regionCount = ra.positions.Count; minesRegionList.Add(ra); index++; } } } private void ClearMinesRegionColor() { if (_map == null) return; foreach (var region in _map.MapData.minesRegions) { _map.SetBlocksColor(region.positions, false, MinesColor); } } #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")] [ShowIf("@!_isLegionMap")] [LabelText("编辑阻挡区"), Indent] [OnValueChanged("OnCanEditorBlockAreaChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorBlockArea; private void OnCanEditorBlockAreaChanged() { if (canEditorBlockArea) { canEditorArea = false; canEditorMinesArea = false; canBrushTerrainType = false; canEditorDefenseArea = false; canEditorSingleRegion = false; canEditorSingleDefenseRegion = false; ClearDefenseRegionColor(); ClearRegionColor(); ClearMinesRegionColor(); } else { ClearBlockRegionColor(); SceneView.RepaintAll(); _currEditBlockRegion = null; canEditorSingleBlockRegion = false; } } [LabelText("阻挡区列表")] [ShowIf("@!_isLegionMap&&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")] [ShowIf("@!_isLegionMap")] [LabelText("编辑触发区"), Indent] [OnValueChanged("OnCanEditorDefenseAreaChanged")] [LabelWidth(100)] [SerializeField] private bool canEditorDefenseArea; private void OnCanEditorDefenseAreaChanged() { if (canEditorDefenseArea) { canEditorBlockArea = false; canEditorArea = false; canEditorMinesArea = false; canBrushTerrainType = false; canEditorSingleRegion = false; canEditorSingleBlockRegion = false; ClearBlockRegionColor(); ClearRegionColor(); ClearMinesRegionColor(); } else { ClearDefenseRegionColor(); SceneView.RepaintAll(); _currEditDefenseRegion = null; canEditorSingleDefenseRegion = false; } } [LabelText("刷怪触发区列表")] [ShowIf("@!_isLegionMap&&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 阻挡球编辑 /// /// 球体根节点 /// private GameObject blockSphereRoot; /// /// 已修改阻挡球字典 /// private readonly Dictionary blockSphereInfo = new(); /// /// 被隐藏的物体列表,用于后续恢复显示 /// private readonly List hideObjs = new List(); /// /// 所有禁止攻击的格子 /// private readonly List banAttackCells = new(); /// /// 标准六边形内接圆直径 /// private static readonly float Calibre = 3f; /// /// 编辑时颜色 /// private static readonly Color EditingSphereColor = Color.red; /// /// 已编辑过的数据颜色 /// private static readonly Color ChangedSphereColor = Color.green; [Serializable] public class BlockSpereEditorInfo { [HideInInspector] public MapData.BlockSphereInfo blockSphereInfo; #region 可视字段 [HorizontalGroup("1", 0.1f)] [LabelText("地格")] [LabelWidth(30)] [ReadOnly] public int cellIndex; [HorizontalGroup("1", 0.12f)] [LabelText("缩放")] [LabelWidth(30)] [EnableIf("canEditor")] [ShowIf("@isChanged||canEditor")] [OnValueChanged("OnScaleValueChanged")] public float scale = 1f; [HorizontalGroup("1", 0.25f)] [LabelText("偏移")] [LabelWidth(30)] [EnableIf("canEditor")] [ShowIf("@isChanged||canEditor")] [OnValueChanged("OnOffestValueChanged")] public Vector2 offest; [HorizontalGroup("1", 0.25f)] [LabelText("备注")] [LabelWidth(30)] [EnableIf("canEditor")] // [ShowIf("@isChanged||canEditor")] [OnValueChanged("OnNoteValueChanged")] public string note; #endregion #region 字段 /// /// 可编辑 /// [HideInInspector] public bool canEditor; /// /// 数据已经变化 /// [HideInInspector] public bool isChanged; /// /// 阻挡球物体 /// [HideInInspector] public GameObject sphere; /// /// 原始共享材质 /// [HideInInspector] public Material originalSharedMaterial; /// /// 编辑时的临时材质 /// [HideInInspector] public Material editingMaterial; /// /// 地格中心位置 /// [HideInInspector] public Vector3 originalPos; #endregion #region 构造函数 public BlockSpereEditorInfo(int cellIndex, GameObject sphere) { var map = _thisWindow._map; this.cellIndex = cellIndex; blockSphereInfo = new MapData.BlockSphereInfo() { cellIndex = cellIndex, }; originalPos = map.TGSCellIndex2WorldPosition(cellIndex); if (sphere != null) { this.sphere = sphere; SetSphereColor(Color.white); } isChanged = false; } public BlockSpereEditorInfo(MapData.BlockSphereInfo blockInfo, GameObject sphere) { var map = _thisWindow._map; blockSphereInfo = new MapData.BlockSphereInfo { cellIndex = blockInfo.cellIndex, scale = blockInfo.scale, note = blockInfo.note, offestPos = blockInfo.offestPos, }; cellIndex = blockInfo.cellIndex; originalPos = map.TGSCellIndex2WorldPosition(blockInfo.cellIndex); offest = new Vector2(blockInfo.offestPos.x - originalPos.x, blockInfo.offestPos.z - originalPos.z); scale = blockInfo.scale / Calibre; if (sphere != null) { this.sphere = sphere; } UpdateChangedData(); } #endregion #region 按钮 [Button("恢复默认")] [HorizontalGroup("1")] [ShowIf("isChanged")] public void Revert() { if (!isChanged) return; isChanged = false; if (sphere != null) { scale = 1f; offest = new Vector2(0f, 0f); blockSphereInfo.offestPos = originalPos; blockSphereInfo.scale = Calibre; sphere.transform.localScale = Vector3.one * Calibre; sphere.transform.position = originalPos; // 如果正在监听这个球体,更新监听的位置和缩放 if (_thisWindow.currentEditingSphere == this) { _thisWindow.lastPosition = originalPos; _thisWindow.lastScale = Vector3.one * Calibre; } if (!canEditor) { SetSphereColor(Color.white); } } } [Button("编辑")] [HorizontalGroup("1")] [HideIf("canEditor")] private void EditorBlockAttack() { canEditor = true; if (sphere != null) { var renderer = sphere.GetComponent(); // 保存原始材质(可能已经是绿色的编辑过材质) originalSharedMaterial = renderer.sharedMaterial; // 创建编辑用的红色材质 editingMaterial = new Material(originalSharedMaterial); editingMaterial.color = EditingSphereColor; renderer.sharedMaterial = editingMaterial; if (_thisWindow.currentEditingSphere != null) { _thisWindow.currentEditingSphere.ExitEditorBlockAttack(); } Selection.activeGameObject = sphere; _thisWindow.StartMonitoringSphere(this); } } [Button("保存")] [HorizontalGroup("1")] [ShowIf("canEditor")] public void ExitEditorBlockAttack() { canEditor = false; if (sphere != null) { var renderer = sphere.GetComponent(); // 清理临时材质并恢复原始材质 if (editingMaterial != null) { DestroyImmediate(editingMaterial); editingMaterial = null; } // 恢复原始材质 if (originalSharedMaterial != null) { renderer.sharedMaterial = originalSharedMaterial; } blockSphereInfo.scale = Calibre * scale; blockSphereInfo.offestPos = sphere.transform.position; DebugUtil.Log( $"保存 :{blockSphereInfo.cellIndex} 上的阻挡攻击球体真实直径为: {blockSphereInfo.scale}, 具体位置为: {blockSphereInfo.offestPos}, " + $"原始的位置是:{originalPos}, 原始直径是:{Calibre}"); UpdateChangedData(); } // 停止监听Transform变化 _thisWindow.StopMonitoringSphere(); } #endregion #region 值变化 private void OnScaleValueChanged() { var realScale = Calibre * scale; if (sphere != null) { sphere.transform.localScale = Vector3.one * realScale; } UpdateChangedData(); } private void OnOffestValueChanged() { var realOffestX = offest.x + originalPos.x; var realOffestZ = offest.y + originalPos.z; var newPos = new Vector3(realOffestX, 0f, realOffestZ); if (sphere != null) { sphere.transform.position = newPos; } UpdateChangedData(); } private void OnNoteValueChanged() { blockSphereInfo.note = note; } public void UpdateChangedData() { isChanged = offest != Vector2.zero || !Mathf.Approximately(1f, scale); // 如果状态发生变化且不在编辑状态,更新球体颜色 if (!canEditor && sphere != null) { SetSphereColor(isChanged ? ChangedSphereColor : Color.white); } } /// /// 设置球体颜色 /// private void SetSphereColor(Color color) { if (sphere == null) return; var renderer = sphere.GetComponent(); if (renderer != null) { if (!canEditor) { if (renderer.sharedMaterial != null) { var material = new Material(renderer.sharedMaterial); material.color = color; renderer.sharedMaterial = material; } } } } #endregion } [BoxGroup("攻击阻挡球")] [HorizontalGroup("攻击阻挡球/Block")] [LabelText("编辑攻击阻挡球"), Indent] [ShowIf("@!_isLegionMap")] [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 = _map.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(); if (renderer != null) { renderer.sharedMaterial = editorInfo.originalSharedMaterial; } } DestroyImmediate(editorInfo.editingMaterial); } } showBuildings = true; ShowHiddenObjects(); DestroyBlockSphere(); } } /// /// 更新阻挡球信息 /// private void UpdateBlockSphereInfo() { blockSphereInfo.Clear(); GetAllBanAttackCell(); foreach (var blockInfo in _currentMapData.BlockSphereInfos) { blockSphereInfo[blockInfo.cellIndex] = blockInfo; } } /// /// 获取所有禁止攻击地格 /// private void GetAllBanAttackCell() { banAttackCells.Clear(); var allCells = _currentMapData.BlocksData; for (var i = 0; i < allCells.Count; i++) { var blockData = allCells[i]; if (!blockData.IsDefaultTerrainType()) { var blockInfo = blockData.GetTerrainTypeProperty(); if (blockInfo.banAttack) { banAttackCells.Add(i); } } } } [LabelText("展示建筑")] [HorizontalGroup("攻击阻挡球/BlockBuildings"), Indent] [ShowIf("@!_isLegionMap&&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("@!_isLegionMap&&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("@!_isLegionMap&&canEditorBlockSphere")] [ListDrawerSettings(HideAddButton = true, CustomRemoveIndexFunction = "CustomRemoveBlockSphereIndex")] public List editingBlockSphereList = new(); [HideInInspector] public List blockSphereEditorList = new(); private void CustomRemoveBlockSphereIndex(int index) { if (index < editingBlockSphereList.Count) { editingBlockSphereList[index].Revert(); DebugUtil.Log($"删除并还原{editingBlockSphereList[index].cellIndex}的阻挡球编辑数据"); editingBlockSphereList.RemoveAt(index); } } /// /// 创建球体 /// private GameObject CreateSphere(int cellIndex, Vector3 pos, Vector3 scale) { var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.position = pos; sphere.transform.localScale = scale; if (blockSphereRoot == null) blockSphereRoot = new GameObject("blockSphereRoot"); sphere.transform.SetParent(blockSphereRoot.transform); sphere.name = "sphere" + cellIndex; return sphere; } private void DestroyBlockSphere() { DestroyImmediate(blockSphereRoot); } /// /// 保存数据 /// private void SaveBlockSphereInfo() { _currentMapData.BlockSphereInfos.Clear(); foreach (var blockSpereEditor in editingBlockSphereList) { _currentMapData.BlockSphereInfos.Add(blockSpereEditor.blockSphereInfo); } } /// /// 加载数据 /// private void LoadBlockSphereInfo() { blockSphereInfo.Clear(); foreach (var blockInfo in _currentMapData.BlockSphereInfos) { blockSphereInfo[blockInfo.cellIndex] = blockInfo; } } #region Sphere物体编辑器监听 /// /// 当前正在编辑的球体信息 /// [HideInInspector] public BlockSpereEditorInfo currentEditingSphere; /// /// 上次记录的位置 /// [HideInInspector] public Vector3 lastPosition; /// /// 上次记录的缩放 /// [HideInInspector] public Vector3 lastScale; /// /// 开始监听球体Transform变化 /// private void StartMonitoringSphere(BlockSpereEditorInfo editorInfo) { currentEditingSphere = editorInfo; if (editorInfo.sphere != null) { lastPosition = editorInfo.sphere.transform.position; lastScale = editorInfo.sphere.transform.localScale; // 注册编辑器更新回调 EditorApplication.update += OnEditorUpdate; } } /// /// 停止监听球体Transform变化 /// private void StopMonitoringSphere() { currentEditingSphere = null; EditorApplication.update -= OnEditorUpdate; } /// /// 编辑器更新回调 /// private void OnEditorUpdate() { if (currentEditingSphere?.sphere == null || !currentEditingSphere.canEditor) { StopMonitoringSphere(); return; } var sphere = currentEditingSphere.sphere; var transform = sphere.transform; // 检查位置变化 if (Vector3.Distance(transform.position, lastPosition) > 0.001f) { // 锁定Y轴 var newPos = transform.position; newPos.y = 0f; transform.position = newPos; // 更新偏移值 var offsetX = newPos.x - currentEditingSphere.originalPos.x; var offsetZ = newPos.z - currentEditingSphere.originalPos.z; currentEditingSphere.offest = new Vector2(offsetX, offsetZ); lastPosition = newPos; // 标记为已修改 currentEditingSphere.UpdateChangedData(); } // 检查缩放变化 if (Vector3.Distance(transform.localScale, lastScale) > 0.001f) { var newScale = transform.localScale.x; transform.localScale = Vector3.one * newScale; currentEditingSphere.scale = newScale / Calibre; lastScale = transform.localScale; currentEditingSphere.UpdateChangedData(); } } #endregion #region 物体隐藏/显示管理 /// /// 需要隐藏的物体节点名字 /// private readonly List hideObjsRoot = new() { "Art", "BackGround", "Buildings", "enemyObjRoot", "midObjRoot", "selfObjRoot" }; /// /// 不需要隐藏的物体节点名字 /// private readonly List noHideObjsRoot = new() { "Ground", "Ground2", "Lights", "Fog", "Global Volume", "Effects" }; /// /// 隐藏指定节点下的物体(排除白名单中的物体) /// public void HideObjectsExcept() { if (hideObjsRoot == null || hideObjsRoot.Count == 0) { return; } // 清空之前的隐藏物体列表 hideObjs.Clear(); foreach (string nodeName in hideObjsRoot) { GameObject node = GameObject.Find(nodeName); if (node == null) { continue; } HideChildrenRecursively(node.transform, noHideObjsRoot); } } /// /// 递归隐藏子物体 /// /// 父级Transform /// 排除的物体名列表 private void HideChildrenRecursively(Transform parent, List excludeNames) { for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); GameObject childObj = child.gameObject; // 检查是否在排除列表中(完全匹配) bool shouldExclude = false; if (excludeNames != null) { foreach (string excludeName in excludeNames) { if (childObj.name.Equals(excludeName, System.StringComparison.OrdinalIgnoreCase)) { shouldExclude = true; break; } } } if (shouldExclude) { continue; } else { // 不在排除列表中,隐藏此物体 if (childObj.activeSelf) { childObj.SetActive(false); hideObjs.Add(childObj); } // 继续递归处理子物体 HideChildrenRecursively(child, excludeNames); } } } /// /// 显示之前隐藏的所有物体 /// private void ShowHiddenObjects() { if (hideObjs == null || hideObjs.Count == 0) { return; } for (int i = hideObjs.Count - 1; i >= 0; i--) { GameObject obj = hideObjs[i]; // 检查物体是否仍然存在(可能已被删除) if (obj != null) { obj.SetActive(true); } hideObjs.RemoveAt(i); } } #endregion #endregion #region 功能 [Button("保存")] private void RebuildPrefab() { SaveBlockSphereInfo(); _currMapManager.SaveMapData(); } [Button("清除网格数据")] private void ClearGridData() { if (EditorUtility.DisplayDialog("清理网格数据", "您是否确认清理地图网格数据", "确认", "取消")) { _currentMapData.ClearGridData(); _map.TerrainGridSystem.TerritoryDestroyAll(); ClearRegionColor(); UpdateRegion(); DestroyBlockSphere(); _currMapManager.SaveMapData(); } } #endregion #region MainLife public static void OpenWindow(MapManager mapSceneEditor, bool isLegionMap = false) { MapEditorSettings.Init(); _thisWindow = GetWindow(); _thisWindow.name = "MapGridWindow"; _thisWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600); _thisWindow._currMapManager = mapSceneEditor; _thisWindow._currentMapData = null; _thisWindow._isLegionMap = isLegionMap; _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; _legionTerrainTypeConfig = LegionTerrainTypeConfig.DicTerrainTypePropertie; _map.TerrainGridSystem.highlightEffect = HighlightEffect.Default; tgs.OnMouseClickOnGrid += OnMouseClickCell; UpdateRegion(); // 加载阻挡球 LoadBlockSphereInfo(); } private void Awake() { SceneView.duringSceneGui += OnSceneGUI; } protected override void OnEnable() { EnhancedTouchSupport.Enable(); TerrainTypeConfig.Load(); LegionTerrainTypeConfig.Load(); _buffPrefabDic = new Dictionary(); base.OnEnable(); } protected override void OnDisable() { DestroyBuffObj(); _buffPrefabDic = null; EnhancedTouchSupport.Disable(); DestroyBlockSphere(); ShowHiddenObjects(); base.OnDisable(); } protected override void OnGUI() { base.OnGUI(); if (_currMapManager == null || _currMapManager.MapData != _currentMapData) { Debug.Log("地图数据变更,请重新点击编辑网格!"); Close(); } } protected override void OnDestroy() { base.OnDestroy(); ShowHiddenObjects(); DestroyBuffObj(); if (_currMapManager != null) _currMapManager.SaveMapData(); ClearRegionColor(); DestroyBlockSphere(); _map.TerrainGridSystem.OnMouseClickOnGrid -= OnMouseClickCell; UnityEditor.Compilation.CompilationPipeline.compilationStarted -= OnCompilationStart; SceneView.duringSceneGui -= OnSceneGUI; } #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) return; if (canEditorArea && _currEditRegionArea == null) return; // 地块 if (canBrushTerrainType) OnClickBlockType(cellIndex, isOpTrue); // 普通地区 if (isOpTrue && canEditorSingleRegion && _currEditRegionArea != null) { _currEditRegionArea.AddPosition(cellIndex); } else if (!isOpTrue && canEditorSingleRegion && _currEditRegionArea != null) { _currEditRegionArea.RemovePosition(cellIndex); } } private void OnClickBlockType(int cellIndex, bool isOpTrue) { if (isOpTrue && terrainTypeIndex >= 0) { SetCellBlockType(cellIndex, terrainTypeIndex); } else if (!isOpTrue) { if (!_isLegionMap && _currentMapData.BlocksData[cellIndex].TerrainTypeIndex == terrainTypeIndex) { ClearCellBlockType(cellIndex); } else if (_isLegionMap && _currentMapData.BlocksData[cellIndex].LegionTypeIndex == terrainTypeIndex) { ClearCellBlockType(cellIndex); } } } #endregion #region Draw private void OnSceneGUI(SceneView sceneView) { DrawSphereID(); } private GUIStyle labelStyleSphere; private void DrawSphereID() { if (!canEditorBlockSphere) return; labelStyleSphere ??= new GUIStyle { fontSize = 30, fontStyle = FontStyle.Bold, normal = { textColor = Color.black } }; foreach (var blockSpereEditor in blockSphereEditorList) { if (blockSpereEditor.sphere != null) { var pos = new Vector3(blockSpereEditor.sphere.transform.position.x, Calibre, blockSpereEditor.sphere.transform.position.z); Handles.Label(pos, blockSpereEditor.cellIndex.ToString(), labelStyleSphere); } } } #endregion } }