NLDClient-yudde/ProjectNLD/Assets/Editor/MapEditor/MapGridWindow.cs

1376 lines
45 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

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

using 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<int, TerrainTypeProperty> _terrainTypeConfig;
private static Dictionary<int, LegionTerrainTypeProperty> _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<TerrainGridSystem>().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<int> 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<TerrainTypeConfigWindow>();
window.Show();
}
else
{
var window = GetWindow<LegionTerrainTypeConfigWindow>();
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<int, GameObject> _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<GameObject>(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<int> 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<RegionArea> 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 阻挡球编辑
/// <summary>
/// 球体根节点
/// </summary>
private GameObject blockSphereRoot;
/// <summary>
/// 已修改阻挡球字典
/// </summary>
private readonly Dictionary<int, MapData.BlockSphereInfo> blockSphereInfo = new();
/// <summary>
/// 被隐藏的物体列表,用于后续恢复显示
/// </summary>
private readonly List<GameObject> hideObjs = new List<GameObject>();
/// <summary>
/// 所有禁止攻击的格子
/// </summary>
private readonly List<int> banAttackCells = new();
/// <summary>
/// 标准六边形内接圆直径
/// </summary>
private static readonly float Calibre = 3f;
/// <summary>
/// 编辑时颜色
/// </summary>
private static readonly Color EditingSphereColor = Color.red;
/// <summary>
/// 已编辑过的数据颜色
/// </summary>
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 字段
/// <summary>
/// 可编辑
/// </summary>
[HideInInspector] public bool canEditor;
/// <summary>
/// 数据已经变化
/// </summary>
[HideInInspector] public bool isChanged;
/// <summary>
/// 阻挡球物体
/// </summary>
[HideInInspector] public GameObject sphere;
/// <summary>
/// 原始共享材质
/// </summary>
[HideInInspector] public Material originalSharedMaterial;
/// <summary>
/// 编辑时的临时材质
/// </summary>
[HideInInspector] public Material editingMaterial;
/// <summary>
/// 地格中心位置
/// </summary>
[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<Renderer>();
// 保存原始材质(可能已经是绿色的编辑过材质)
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<Renderer>();
// 清理临时材质并恢复原始材质
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);
}
}
/// <summary>
/// 设置球体颜色
/// </summary>
private void SetSphereColor(Color color)
{
if (sphere == null) return;
var renderer = sphere.GetComponent<Renderer>();
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<Renderer>();
if (renderer != null)
{
renderer.sharedMaterial = editorInfo.originalSharedMaterial;
}
}
DestroyImmediate(editorInfo.editingMaterial);
}
}
showBuildings = true;
ShowHiddenObjects();
DestroyBlockSphere();
}
}
/// <summary>
/// 更新阻挡球信息
/// </summary>
private void UpdateBlockSphereInfo()
{
blockSphereInfo.Clear();
GetAllBanAttackCell();
foreach (var blockInfo in _currentMapData.BlockSphereInfos)
{
blockSphereInfo[blockInfo.cellIndex] = blockInfo;
}
}
/// <summary>
/// 获取所有禁止攻击地格
/// </summary>
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<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);
}
}
/// <summary>
/// 创建球体
/// </summary>
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);
}
/// <summary>
/// 保存数据
/// </summary>
private void SaveBlockSphereInfo()
{
_currentMapData.BlockSphereInfos.Clear();
foreach (var blockSpereEditor in editingBlockSphereList)
{
_currentMapData.BlockSphereInfos.Add(blockSpereEditor.blockSphereInfo);
}
}
/// <summary>
/// 加载数据
/// </summary>
private void LoadBlockSphereInfo()
{
blockSphereInfo.Clear();
foreach (var blockInfo in _currentMapData.BlockSphereInfos)
{
blockSphereInfo[blockInfo.cellIndex] = blockInfo;
}
}
#region Sphere物体编辑器监听
/// <summary>
/// 当前正在编辑的球体信息
/// </summary>
[HideInInspector] public BlockSpereEditorInfo currentEditingSphere;
/// <summary>
/// 上次记录的位置
/// </summary>
[HideInInspector] public Vector3 lastPosition;
/// <summary>
/// 上次记录的缩放
/// </summary>
[HideInInspector] public Vector3 lastScale;
/// <summary>
/// 开始监听球体Transform变化
/// </summary>
private void StartMonitoringSphere(BlockSpereEditorInfo editorInfo)
{
currentEditingSphere = editorInfo;
if (editorInfo.sphere != null)
{
lastPosition = editorInfo.sphere.transform.position;
lastScale = editorInfo.sphere.transform.localScale;
// 注册编辑器更新回调
EditorApplication.update += OnEditorUpdate;
}
}
/// <summary>
/// 停止监听球体Transform变化
/// </summary>
private void StopMonitoringSphere()
{
currentEditingSphere = null;
EditorApplication.update -= OnEditorUpdate;
}
/// <summary>
/// 编辑器更新回调
/// </summary>
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 物体隐藏/显示管理
/// <summary>
/// 需要隐藏的物体节点名字
/// </summary>
private readonly List<string> hideObjsRoot = new()
{
"Art", "BackGround", "Buildings", "enemyObjRoot", "midObjRoot", "selfObjRoot"
};
/// <summary>
/// 不需要隐藏的物体节点名字
/// </summary>
private readonly List<string> noHideObjsRoot = new()
{
"Ground", "Ground2", "Lights", "Fog", "Global Volume", "Effects"
};
/// <summary>
/// 隐藏指定节点下的物体(排除白名单中的物体)
/// </summary>
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);
}
}
/// <summary>
/// 递归隐藏子物体
/// </summary>
/// <param name="parent">父级Transform</param>
/// <param name="excludeNames">排除的物体名列表</param>
private void HideChildrenRecursively(Transform parent, List<string> 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);
}
}
}
/// <summary>
/// 显示之前隐藏的所有物体
/// </summary>
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<MapGridWindow>();
_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<int, GameObject>();
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
}
}