326 lines
11 KiB
C#
326 lines
11 KiB
C#
using Framework;
|
||
using Gameplay;
|
||
using NPOI.SS.Formula.Functions;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using Cysharp.Threading.Tasks;
|
||
using TGS;
|
||
using UnityEditor;
|
||
using UnityEditor.SceneManagement;
|
||
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
using UnityEngine.UIElements;
|
||
using static UnityEditor.Searcher.SearcherWindow.Alignment;
|
||
using Cell = TGS.Cell;
|
||
|
||
|
||
public class EditorMap
|
||
{
|
||
private static EditorMap _instance;
|
||
public static EditorMap Instance
|
||
{
|
||
get
|
||
{
|
||
|
||
if (_instance == null)
|
||
{
|
||
_instance = new EditorMap();
|
||
}
|
||
|
||
return _instance;
|
||
}
|
||
}
|
||
|
||
public delegate void OnMapChanged();
|
||
public OnMapChanged onMapChanged;
|
||
public Map Current
|
||
{
|
||
get => _map;
|
||
set
|
||
{
|
||
_map = value;
|
||
onMapChanged?.Invoke();
|
||
}
|
||
}
|
||
private Map _map;
|
||
}
|
||
public class MapEditorUtils
|
||
{
|
||
public const float UPP = 100;
|
||
|
||
public static Dictionary<GameObject, List<int>> mapObjectOccupyCells = new Dictionary<GameObject, List<int>>();
|
||
// public static Map CreateNewMap(int id, string name, int column, int row, string backgroundPath, MapData.EnvironmentType environmentType)
|
||
// {
|
||
// OpenMapScene();
|
||
//
|
||
// var asset = AssetDatabase.LoadAssetAtPath<GameObject>(MapEditorConstant.MapTemplatePrefab);
|
||
// var root = GameObject.Instantiate(asset);
|
||
// var tgs = root.GetComponentInChildren<TerrainGridSystem>();
|
||
//
|
||
// tgs.columnCount = column;
|
||
// tgs.rowCount = row;
|
||
//
|
||
// MapData mapData = new MapData(id, name, column, row, environmentType);
|
||
// var map = Map.Create(root, mapData);
|
||
// map.SetGroundTexture(AssetDatabase.LoadAssetAtPath<Texture2D>(backgroundPath));
|
||
// map.ShowInfo((int)Map.InfoMask.ShowAll);
|
||
// ResetCamera();
|
||
// return map;
|
||
// }
|
||
|
||
public static void OpenMapScene()
|
||
{
|
||
//GameSceneManager.Instance.ChangeScene(GameSceneManager.EnumScene.GameLevel);
|
||
var scene = SceneManager.GetActiveScene();
|
||
if (scene.path == MapEditorConstant.MapEditorScene)
|
||
{
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
EditorSceneManager.OpenScene(MapEditorConstant.MapEditorScene);
|
||
}
|
||
}
|
||
|
||
// public static void SaveEditorMap()
|
||
// {
|
||
// var map = EditorMap.Instance.Current;
|
||
// if (map != null)
|
||
// {
|
||
// var prefabFilePath = string.Format(Constants.MAP_ASSET_FORMAT_PATH, map.GetMapFileName());
|
||
//
|
||
// // PrefabUtility.SaveAsPrefabAssetAndConnect(map.GameObject,
|
||
// // prefabFilePath, InteractionMode.UserAction);
|
||
//
|
||
// var configFilePath = string.Format(Constants.MAP_CONFIG_FORMAT_PATH, map.GetMapFileName());
|
||
// // if (File.Exists(configFilePath))
|
||
// // {
|
||
// // VersionControlSystem.Checkout(configFilePath);
|
||
// // }
|
||
// Framework.JsonHelper.SaveJson(configFilePath, map.MapData);
|
||
//
|
||
// if (File.Exists(prefabFilePath) && File.Exists(configFilePath))
|
||
// {
|
||
// CustomPopUpWindow.PopUp($"Save Successfully:\n {prefabFilePath} \n {configFilePath} \n");
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// public static Map LoadMap(TerrainGridSystem terrainGridSystem,MapData mapData)
|
||
// {
|
||
// //OpenMapScene();
|
||
// //ResetCamera();
|
||
// //MapUtils.UnLoadMap(EditorMap.Instance.Current);
|
||
// var map = MapUtils.LoadMap(terrainGridSystem,mapData);
|
||
// if (map != null)
|
||
// {
|
||
// map.ShowInfo((int)Map.InfoMask.ShowAll);
|
||
// return map;
|
||
// }
|
||
// return null;
|
||
// }
|
||
|
||
public static void UnLoadMap(EditorMap editorMap)
|
||
{
|
||
MapUtils.UnLoadMap(editorMap.Current);
|
||
editorMap.Current = null;
|
||
}
|
||
|
||
// public static void ResetCamera()
|
||
// {
|
||
// if (Camera.main == null)
|
||
// {
|
||
// var camera = new GameObject("Main Camera").AddComponent<Camera>();
|
||
// camera.tag = "MainCamera";
|
||
// }
|
||
//
|
||
// var mainCamera = Camera.main;
|
||
// var cameraController = mainCamera.gameObject.GetComponent<CameraController>();
|
||
// if (!cameraController)
|
||
// {
|
||
// cameraController = mainCamera.gameObject.AddComponent<CameraController>();
|
||
// }
|
||
//
|
||
// cameraController.Map = EditorMap.Instance.Current != null ? EditorMap.Instance.Current : null;
|
||
// mainCamera.orthographic = true;
|
||
// mainCamera.orthographicSize = cameraController.CameraMaxSize;
|
||
// mainCamera.gameObject.transform.forward = Vector3.down;
|
||
// mainCamera.gameObject.transform.up = Vector3.forward;
|
||
// if (Application.isPlaying)
|
||
// {
|
||
// if (mainCamera != null)
|
||
// {
|
||
// GameObject.DontDestroyOnLoad(mainCamera.gameObject);
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
/// <summary>
|
||
/// 物件自动吸附格子
|
||
/// </summary>
|
||
/// <param name="mapObject"></param>
|
||
public static void ObjectAutoAdsorptionCell(GameObject mapObject)
|
||
{
|
||
var map = EditorMap.Instance.Current;
|
||
|
||
MeshFilter meshFilter = mapObject.GetComponentInChildren<MeshFilter>();
|
||
|
||
if (meshFilter != null)
|
||
{
|
||
var bounds = CalculateBounds(meshFilter.sharedMesh);
|
||
|
||
// Debug.Log($"包围盒大小:{bounds.size},包围盒中心位置:{bounds.center},最大:{bounds.max},最小:{bounds.min}");
|
||
|
||
Vector3 centerWorldPos = mapObject.transform.TransformPoint(new Vector3(bounds.center.x, 0f, bounds.center.z));
|
||
|
||
Cell cell = map.TerrainGridSystem.CellGetAtPosition(centerWorldPos, true);
|
||
|
||
if (cell != null)
|
||
{
|
||
var nearestPoint = FindNearestPoint(cell.index, centerWorldPos);
|
||
|
||
mapObject.transform.position = nearestPoint;
|
||
|
||
Vector3 centerWorldPos2 = mapObject.transform.TransformPoint(new Vector3(bounds.center.x, 0f, bounds.center.z));
|
||
|
||
Vector3 moveVector = mapObject.transform.position - centerWorldPos2;
|
||
|
||
mapObject.transform.position += moveVector;
|
||
|
||
CalculateFloorArea(mapObject ,bounds);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 刷地图建筑物占地地块,默认刷为0号地块
|
||
/// </summary>
|
||
public static void CalculateFloorArea(GameObject mapObject, Bounds bounds)
|
||
{
|
||
Dictionary<int, TerrainTypeProperty> terrainTypeConfig = TerrainTypeConfig.DicTerrainTypePropertie;
|
||
|
||
var map = EditorMap.Instance.Current;
|
||
|
||
if (mapObjectOccupyCells.TryGetValue(mapObject, out var cells))
|
||
{
|
||
foreach (var cell in cells)
|
||
{
|
||
map.TerrainGridSystem.CellSetColor(cell, Color.clear);
|
||
}
|
||
cells.Clear();
|
||
}
|
||
else
|
||
{
|
||
|
||
cells = new List<int>();
|
||
mapObjectOccupyCells.Add(mapObject, cells);
|
||
}
|
||
|
||
var lowerLeft = mapObject.transform.TransformPoint(new Vector3(bounds.min.x, 0f, bounds.min.y));
|
||
|
||
var topRight = mapObject.transform.TransformPoint(new Vector3(bounds.max.x, 0f, bounds.max.y));
|
||
|
||
var lowerRight = mapObject.transform.TransformPoint(new Vector3(bounds.max.x, 0f, bounds.min.y));
|
||
|
||
var topLeft = mapObject.transform.TransformPoint(new Vector3(bounds.min.x, 0f, bounds.max.y));
|
||
|
||
var minPos = new Vector3(Mathf.Min(lowerLeft.x, topRight.x, lowerRight.x, topLeft.x), 0f,
|
||
Mathf.Min(lowerLeft.z, topRight.z, lowerRight.z, topLeft.z));
|
||
|
||
var maxPos = new Vector3(Mathf.Max(lowerLeft.x, topRight.x, lowerRight.x, topLeft.x), 0f,
|
||
Mathf.Max(lowerLeft.z, topRight.z, lowerRight.z, topLeft.z));
|
||
|
||
if (map.TerrainGridSystem.CellGetAtPosition(minPos, true) != null &&
|
||
map.TerrainGridSystem.CellGetAtPosition(maxPos, true) != null)
|
||
{
|
||
var minCellPos = map.TGSCellIndex2BlockPosition(map.TerrainGridSystem.CellGetAtPosition(minPos, true).index);
|
||
|
||
var maxCellPos = map.TGSCellIndex2BlockPosition(map.TerrainGridSystem.CellGetAtPosition(maxPos, true).index);
|
||
|
||
var minX = Mathf.Min(minCellPos.x, maxCellPos.x);
|
||
var maxX = Mathf.Max(minCellPos.x, maxCellPos.x);
|
||
var minY = Mathf.Min(minCellPos.y, maxCellPos.y);
|
||
var maxY = Mathf.Max(minCellPos.y, maxCellPos.y);
|
||
|
||
//Debug.Log($"最大y:{maxY},最小y:{minY},最大x:{maxX},最小x:{minX}");
|
||
|
||
for (int i = minX; i <= maxX; ++i)
|
||
{
|
||
for(int j = minY; j <= maxY; ++j)
|
||
{
|
||
|
||
var cellIndex = map.BlockPosition2TGSCellIndex(new(i, j));
|
||
|
||
cells.Add(cellIndex);
|
||
|
||
map.TerrainGridSystem.CellSetColor(cellIndex, terrainTypeConfig[0].Color);
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 计算3m以下的包围盒大小
|
||
/// </summary>
|
||
/// <param name="mesh"></param>
|
||
/// <returns></returns>
|
||
public static Bounds CalculateBounds(Mesh mesh)
|
||
{
|
||
float limitHeight = 3f;
|
||
|
||
if (mesh != null)
|
||
{
|
||
Vector3[] vertices = mesh.vertices;
|
||
|
||
List<Vector3> limitVertices = vertices.Where(vertex => vertex.z <= limitHeight).ToList();
|
||
|
||
Bounds bounds = new Bounds(new Vector3(limitVertices[0].x, limitVertices[0].y, 0f), Vector3.zero);
|
||
|
||
foreach (Vector3 vertex in limitVertices)
|
||
{
|
||
bounds.Encapsulate(new Vector3(vertex.x, vertex.y, 0f));
|
||
}
|
||
|
||
return bounds;
|
||
}
|
||
else
|
||
{
|
||
return new Bounds();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 寻找六边形中距离最近的点
|
||
/// </summary>
|
||
/// <param name="cellIndex"></param>
|
||
/// <param name="centerPos"></param>
|
||
/// <returns></returns>
|
||
public static Vector3 FindNearestPoint(int cellIndex, Vector3 centerPos)
|
||
{
|
||
var map = EditorMap.Instance.Current;
|
||
|
||
Dictionary<Vector3,float> vertices = new Dictionary<Vector3,float>();
|
||
|
||
for (int index = 0;index < map.TerrainGridSystem.CellGetVertexCount(cellIndex); index++)
|
||
{
|
||
var vertex = map.TerrainGridSystem.CellGetVertexPosition(cellIndex, index);
|
||
float distance = Vector3.Distance(vertex, centerPos);
|
||
vertices.Add(vertex, distance);
|
||
}
|
||
|
||
vertices.Add(map.TGSCellIndex2WorldPosition(cellIndex), Vector3.Distance(map.TGSCellIndex2WorldPosition(cellIndex), centerPos));
|
||
|
||
var neareatPoint = vertices.FirstOrDefault(x => x.Value == vertices.Values.Min()).Key;
|
||
|
||
return neareatPoint;
|
||
}
|
||
} |