using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace MindPowerSdk.Editor
{
///
/// 地图生成工具窗口,用于配置地图数据参数、材质映射,以及生成、清除、保存地图到预制体。
/// 注意:每个地图配置项对应一个 MapName 与资源数据名称组合生成一个地图。
///
public class MapGeneratorEditorWindow : EditorWindow
{
// 文件夹路径设置
private string mapDataFolder = "";
private string resourceDataFolder = "";
// 地图数据配置:每个地图对应一个名称与数据资源名称
private List mapEntries = new List();
// 其他地图参数
private int chunkSize = 64;
private Material terrainMaterial;
// 材质映射设置(草、树等),关键字支持多个,用逗号分隔
private List materialMappings = new List();
// 生成地图时的父物体名称
private const string GENERATED_MAPS_PARENT = "GeneratedMaps";
[MenuItem("Tools/地图生成工具")]
public static void ShowWindow()
{
GetWindow("地图生成工具");
}
private void OnEnable()
{
// 初始化默认数据
if (mapEntries == null) mapEntries = new List();
if (materialMappings == null) materialMappings = new List();
}
private void OnGUI()
{
GUILayout.Label("文件夹路径设置", EditorStyles.boldLabel);
// 数据源文件夹选择
EditorGUILayout.BeginHorizontal();
mapDataFolder = EditorGUILayout.TextField("数据源文件夹", mapDataFolder);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string folder = EditorUtility.OpenFolderPanel("选择数据源文件夹", "", "");
if (!string.IsNullOrEmpty(folder))
{
mapDataFolder = folder;
}
}
EditorGUILayout.EndHorizontal();
// 资源数据文件夹选择
EditorGUILayout.BeginHorizontal();
resourceDataFolder = EditorGUILayout.TextField("资源数据文件夹", resourceDataFolder);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string folder = EditorUtility.OpenFolderPanel("选择资源数据文件夹", "", "");
if (!string.IsNullOrEmpty(folder))
{
resourceDataFolder = folder;
}
}
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("地图数据配置 (每个配置项对应一个地图)", EditorStyles.boldLabel);
// 列表显示地图配置项
for (int i = 0; i < mapEntries.Count; i++)
{
EditorGUILayout.BeginHorizontal();
mapEntries[i].mapName = EditorGUILayout.TextField("Map 名称", mapEntries[i].mapName);
mapEntries[i].resourceDataName = EditorGUILayout.TextField("资源名称", mapEntries[i].resourceDataName);
mapEntries[i].isSmoothing = EditorGUILayout.Toggle("对地形平滑处理", mapEntries[i].isSmoothing);
if (GUILayout.Button("删除", GUILayout.Width(60)))
{
mapEntries.RemoveAt(i);
i--;
}
EditorGUILayout.EndHorizontal();
}
if (GUILayout.Button("添加地图配置"))
{
mapEntries.Add(new MapInfoEntry());
}
GUILayout.Space(10);
GUILayout.Label("地图其他参数", EditorStyles.boldLabel);
chunkSize = EditorGUILayout.IntField("Chunk Size", chunkSize);
terrainMaterial =
(Material)EditorGUILayout.ObjectField("Terrain Material", terrainMaterial, typeof(Material), false);
GUILayout.Space(10);
GUILayout.Label("材质映射配置 (草、树等)", EditorStyles.boldLabel);
// 材质映射配置项
for (int i = 0; i < materialMappings.Count; i++)
{
EditorGUILayout.BeginHorizontal();
// 关键字输入,支持多个关键字,用逗号分隔
materialMappings[i].keywords = EditorGUILayout.TextField("匹配关键字(,分隔)", materialMappings[i].keywords);
materialMappings[i].targetMaterial =
(Material)EditorGUILayout.ObjectField("目标材质", materialMappings[i].targetMaterial, typeof(Material),
false);
if (GUILayout.Button("删除", GUILayout.Width(60)))
{
materialMappings.RemoveAt(i);
i--;
}
EditorGUILayout.EndHorizontal();
}
if (GUILayout.Button("添加材质映射配置"))
{
materialMappings.Add(new MaterialMappingEntry());
}
GUILayout.Space(10);
// 操作按钮
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("生成到场景"))
{
GenerateMaps();
}
if (GUILayout.Button("清除生成地图"))
{
ClearGeneratedMaps();
}
if (GUILayout.Button("保存为预制体"))
{
SaveMapsAsPrefabs();
}
EditorGUILayout.EndHorizontal();
}
///
/// 根据当前配置生成所有地图,并生成到场景下的 GENERATED_MAPS_PARENT 父物体内。
///
private void GenerateMaps()
{
// 检查必要的路径和配置
if (string.IsNullOrEmpty(mapDataFolder) || string.IsNullOrEmpty(resourceDataFolder))
{
Debug.LogError("请先设置数据源和资源数据的文件夹路径!");
return;
}
if (mapEntries.Count == 0)
{
Debug.LogError("请添加至少一个地图配置项!");
return;
}
// 查找或创建生成地图的父物体
GameObject parent = GameObject.Find(GENERATED_MAPS_PARENT);
if (parent == null)
{
parent = new GameObject(GENERATED_MAPS_PARENT);
}
// 遍历每个地图配置项生成地图
foreach (var entry in mapEntries)
{
// 拼接完整数据路径
string mapDataPath = Path.Combine(mapDataFolder, entry.mapName);
string resourceDataPath = Path.Combine(resourceDataFolder, entry.resourceDataName);
// 读取地图数据
using FileStream fs = File.OpenRead(mapDataPath);
BinaryReader reader = new BinaryReader(fs);
var map = new MPMap();
map.Load(reader);
Debug.Log($"map size:({map.Width},{map.Height}) | section size:({map.SectionWidth},{map.SectionHeight})");
// 调用生成 Terrain 的方法,传入 mapName 作为标识
TerrainGenerator.GenTerrain(map, chunkSize, terrainMaterial, parent.transform, entry.mapName,
entry.isSmoothing);
Debug.Log($"生成地图:{entry.mapName}\n数据路径:{mapDataPath}\n资源路径:{resourceDataPath}");
}
}
///
/// 清除场景中已生成的地图(父物体名称为 GENERATED_MAPS_PARENT)
///
private void ClearGeneratedMaps()
{
GameObject parent = GameObject.Find(GENERATED_MAPS_PARENT);
if (parent != null)
{
DestroyImmediate(parent);
Debug.Log("已清除生成的地图");
}
else
{
Debug.LogWarning("未找到生成的地图");
}
}
///
/// 将生成的每个地图(即每个 MapName 对应的 Terrain 节点)保存为独立预制体,存储在 Assets/Prefabs 下。
///
private void SaveMapsAsPrefabs()
{
#if UNITY_EDITOR
GameObject parent = GameObject.Find(GENERATED_MAPS_PARENT);
if (parent == null)
{
Debug.LogWarning("没有生成的地图可以保存");
return;
}
// 遍历每个地图生成的子对象
foreach (Transform mapTransform in parent.transform)
{
string prefabPath = "Assets/Prefabs/" + mapTransform.name + ".prefab";
string directory = Path.GetDirectoryName(prefabPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
PrefabUtility.SaveAsPrefabAssetAndConnect(mapTransform.gameObject, prefabPath,
InteractionMode.UserAction);
Debug.Log($"保存预制体:{prefabPath}");
}
#else
Debug.LogWarning("该功能仅在 Unity Editor 下可用");
#endif
}
///
/// 根据传入的类型名称(如“草”或“树”)进行模糊匹配,
/// 遍历材质映射配置,返回第一个匹配的目标材质,未匹配返回 null。
///
public Material GetMappedMaterial(string typeName)
{
foreach (var mapping in materialMappings)
{
if (!string.IsNullOrEmpty(mapping.keywords))
{
// 以逗号分隔关键字,并检查 typeName 是否包含任一关键字
string[] keys = mapping.keywords.Split(',');
foreach (var key in keys)
{
if (typeName.Contains(key.Trim()))
{
return mapping.targetMaterial;
}
}
}
}
return null;
}
}
///
/// 地图配置项,每个项对应一个 Map 名称与资源数据名称组合
///
[System.Serializable]
public class MapInfoEntry
{
public string mapName = "";
public string resourceDataName = "";
public bool isSmoothing = true; // 是否平滑处理
}
///
/// 材质映射配置项,用于配置多个关键字与目标材质的对应关系
///
[System.Serializable]
public class MaterialMappingEntry
{
// 支持多个匹配关键字,用逗号分隔
public string keywords = "";
public Material targetMaterial;
}
}