下面我将为你提供一个完整的示例,展示如何在 Unity 中实现从场景导出数据到 Excel 的功能。这个示例将涵盖你提到的所有步骤,包括创建编辑器窗口、查找场景中的对象、导出数据到 Excel 文件等。
1. 创建编辑器窗口
首先,创建一个名为 ExportData4Svr.cs
的文件,并放置在 Assembly-CSharp-Editor/Editor
目录下。以下是基本的代码结构:
using UnityEngine;
using UnityEditor;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
public class ExportData4Svr : EditorWindow
{
[MenuItem("Tools/ExportData4Svr")]
static void Export()
{
ExportData();
}
static void ExportData()
{
// 这里可以调用其他方法来获取数据并导出
Dump();
}
public static void Dump()
{
// 相对路径表示的excel文件名
string excelPath = "Assets/Resources/场景表.xls";
// 创建工作簿
HSSFWorkbook workBook = new HSSFWorkbook();
ISheet sheet = workBook.CreateSheet("场景配置");
// 创建表头
IRow headerRow = sheet.CreateRow(0);
headerRow.CreateCell(0).SetCellValue("地图宽度");
headerRow.CreateCell(1).SetCellValue("地图高度");
// 这里可以添加更多的列
// 示例数据
int mapWidth = 100; // 这里可以替换为实际的地图宽度
int mapHeight = 100; // 这里可以替换为实际的地图高度
// 创建数据行
IRow dataRow = sheet.CreateRow(1);
dataRow.CreateCell(0).SetCellValue(mapWidth);
dataRow.CreateCell(1).SetCellValue(mapHeight);
// 写入文件
using (FileStream fs = new FileStream(excelPath, FileMode.Create, FileAccess.Write))
{
workBook.Write(fs);
}
workBook.Close();
AssetDatabase.Refresh(); // 刷新资源
Debug.Log("数据导出成功到: " + excelPath);
}
}
2. 获取场景中的资源数据
在 ExportData
方法中,你可以添加代码来查找场景中的对象并获取它们的数据。以下是一个示例,展示如何查找特定类型的对象和根据名称查找对象:
static void ExportData()
{
// 获取场景中的所有 Tree 类型的对象
Component[] trees = GameObject.Find("SceneRoot").GetComponentsInChildren(typeof(Tree));
foreach (var tree in trees)
{
Debug.Log("Found tree at position: " + tree.transform.position);
}
// 获取所有以 "water" 开头的材质
GameObject terrain = GameObject.Find("SceneRoot");
foreach (Transform child in terrain.transform)
{
Renderer render = child.gameObject.GetComponent<Renderer>();
if (render != null)
{
foreach (var material in render.sharedMaterials)
{
if (material.name.StartsWith("water"))
{
Debug.Log("Water position: " + child.gameObject.transform.position);
}
}
}
}
// 继续调用 Dump 方法来导出数据
Dump();
}
3. 使用 NPOI 库操作 Excel
确保你已经将 NPOI 库添加到 Unity 项目中。你可以通过 NuGet 或直接下载 NPOI 的 DLL 文件并放入 Assets/Plugins
目录。
4. 完整代码示例
将上述代码整合在一起,形成一个完整的 ExportData4Svr.cs
文件:
using UnityEngine;
using UnityEditor;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
public class ExportData4Svr : EditorWindow
{
[MenuItem("Tools/ExportData4Svr")]
static void Export()
{
ExportData();
}
static void ExportData()
{
// 获取场景中的所有 Tree 类型的对象
Component[] trees = GameObject.Find("SceneRoot").GetComponentsInChildren(typeof(Tree));
foreach (var tree in trees)
{
Debug.Log("Found tree at position: " + tree.transform.position);
}
// 获取所有以 "water" 开头的材质
GameObject terrain = GameObject.Find("SceneRoot");
foreach (Transform child in terrain.transform)
{
Renderer render = child.gameObject.GetComponent<Renderer>();
if (render != null)
{
foreach (var material in render.sharedMaterials)
{
if (material.name.StartsWith("water"))
{
Debug.Log("Water position: " + child.gameObject.transform.position);
}
}
}
}
// 调用 Dump 方法来导出数据
Dump();
}
public static void Dump()
{
// 相对路径表示的excel文件名
string excelPath = "Assets/Resources/场景表.xls";
// 创建工作簿
HSSFWorkbook workBook = new HSSFWorkbook();
ISheet sheet = workBook.CreateSheet("场景配置");
// 创建表头
IRow headerRow = sheet.CreateRow(0);
headerRow.CreateCell(0).SetCellValue("地图宽度");
headerRow.CreateCell(1).SetCellValue("地图高度");
headerRow.CreateCell(2).SetCellValue("树木数量");
headerRow.CreateCell(3).SetCellValue("水体位置");
// 示例数据
int mapWidth = 100; // 这里可以替换为实际的地图宽度
int mapHeight = 100; // 这里可以替换为实际的地图高度
int treeCount = GameObject.Find("SceneRoot").GetComponentsInChildren<Tree>().Length;
// 创建数据行
IRow dataRow = sheet.CreateRow(1);
dataRow.CreateCell(0).SetCellValue(mapWidth);
dataRow.CreateCell(1).SetCellValue(mapHeight);
dataRow.CreateCell(2).SetCellValue(treeCount);
// 记录水体位置
int waterRowIndex = 2; // 从第二行开始记录水体位置
foreach (Transform child in GameObject.Find("SceneRoot").transform)
{
Renderer render = child.gameObject.GetComponent<Renderer>();
if (render != null)
{
foreach (var material in render.sharedMaterials)
{
if (material.name.StartsWith("water"))
{
IRow waterRow = sheet.CreateRow(waterRowIndex++);
waterRow.CreateCell(0).SetCellValue("水体位置");
waterRow.CreateCell(1).SetCellValue(child.gameObject.transform.position.x);
waterRow.CreateCell(2).SetCellValue(child.gameObject.transform.position.y);
waterRow.CreateCell(3).SetCellValue(child.gameObject.transform.position.z);
}
}
}
}
// 写入文件
using (FileStream fs = new FileStream(excelPath, FileMode.Create, FileAccess.Write))
{
workBook.Write(fs);
}
workBook.Close();
AssetDatabase.Refresh(); // 刷新资源
Debug.Log("数据导出成功到: " + excelPath);
}
}
代码说明
- 菜单项:通过
MenuItem
属性创建一个菜单项,点击后会调用Export
方法。 - 导出数据:在
ExportData
方法中,首先查找场景中的所有Tree
类型的对象,并记录它们的位置。然后查找所有以 “water” 开头的材质,并记录它们的位置。 - 写入 Excel:在
Dump
方法中,创建一个 Excel 工作簿,并在第一行写入表头。接着,写入地图的宽度、高度和树木数量。最后,记录水体的位置。 - 文件写入:使用
FileStream
将数据写入到指定路径的 Excel 文件中,并在完成后刷新 Unity 的资源管理器。
运行步骤
- 将上述代码保存到
ExportData4Svr.cs
文件中。 - 确保 NPOI 库已正确添加到 Unity 项目中。
- 在 Unity 编辑器中,点击菜单
Tools -> ExportData4Svr
,运行导出功能。 - 检查
Assets/Resources/场景表.xls
文件,确认数据是否正确导出。
未来的扩展
-
支持更多数据类型:
- 敌人位置:可以添加代码来查找场景中的敌人对象,并记录它们的位置。
- 可交互对象:查找所有可交互的对象(如门、开关等),并记录它们的状态和位置。
- 资源点:如果有资源点(如矿石、树木等),可以记录它们的位置和类型。
下面是一个示例,展示如何查找敌人对象并记录它们的位置:
// 查找敌人对象 Component[] enemies = GameObject.Find("SceneRoot").GetComponentsInChildren(typeof(Enemy)); foreach (var enemy in enemies) { Debug.Log("Found enemy at position: " + enemy.transform.position); }
-
支持其他数据格式:
- 除了 Excel,你还可以考虑导出为 JSON 或 XML 格式,这样可以更方便地与其他系统进行集成。
- 使用
JsonUtility
类可以轻松将数据序列化为 JSON 格式。
示例代码(导出为 JSON):
[System.Serializable] public class SceneData { public int mapWidth; public int mapHeight; public List<Vector3> waterPositions; } public static void ExportToJson() { SceneData sceneData = new SceneData { mapWidth = 100, // 替换为实际值 mapHeight = 100, // 替换为实际值 waterPositions = new List<Vector3>() }; // 添加水体位置 foreach (Transform child in GameObject.Find("SceneRoot").transform) { Renderer render = child.gameObject.GetComponent<Renderer>(); if (render != null) { foreach (var material in render.sharedMaterials) { if (material.name.StartsWith("water")) { sceneData.waterPositions.Add(child.gameObject.transform.position); } } } } string json = JsonUtility.ToJson(sceneData, true); File.WriteAllText("Assets/Resources/场景数据.json", json); Debug.Log("数据导出成功到: Assets/Resources/场景数据.json"); }
-
优化代码结构:
- 将数据导出逻辑分离到不同的方法中,以提高可读性和可维护性。
- 使用数据结构(如类或结构体)来存储导出的数据,便于管理和扩展。
示例代码(使用类来存储数据):
[System.Serializable] public class TreeData { public Vector3 position; } [System.Serializable] public class WaterData { public Vector3 position; } public class SceneExportData { public int mapWidth; public int mapHeight; public List<TreeData> trees = new List<TreeData>(); public List<WaterData> waters = new List<WaterData>(); }
-
用户界面改进:
- 可以为导出功能添加更多的用户界面选项,例如选择导出格式、选择导出数据的类型等。
- 使用
EditorGUILayout
类来创建更友好的编辑器界面。
示例代码(简单的用户界面):
private bool exportToExcel = true; private bool exportToJson = false; void OnGUI() { exportToExcel = EditorGUILayout.Toggle("导出到 Excel", exportToExcel); exportToJson = EditorGUILayout.Toggle("导出到 JSON", exportToJson); if (GUILayout.Button("导出数据")) { if (exportToExcel) { ExportData(); } if (exportToJson) { ExportToJson(); } } }
总结
通过以上的扩展和优化,你可以将 Unity 编辑器中的数据导出功能提升到一个新的水平。无论是支持更多的数据类型、导出格式,还是优化代码结构和用户界面,这些改进都将使得你的工具更加灵活和易用。