用于快速在某个物体下生成阵列,以及替换子物体。
csharp
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class CombinedTool : EditorWindow
{
private enum Tab
{
Creator, // 阵列生成器
Replacer // 替换子物体
}
[SerializeField] private Tab currentTab = Tab.Creator;
// ---------- 阵列生成器参数 ----------
[SerializeField] private GameObject creatorPrefab;
[SerializeField] private int creatorRows = 5;
[SerializeField] private int creatorColumns = 5;
[SerializeField] private float creatorSpacing = 2f;
[SerializeField] private Vector3 creatorOffset = Vector3.zero;
[SerializeField] private Transform creatorParent;
// ---------- 替换子物体参数 ----------
[SerializeField] private GameObject replacerParentObject;
[SerializeField] private GameObject replacerPrefab;
// 窗口菜单项
[MenuItem("Tools/物品阵列生成器")]
public static void ShowCreator()
{
var window = GetWindow<CombinedTool>("组合工具");
window.currentTab = Tab.Creator;
window.Show();
}
[MenuItem("Tools/替换子物体为预制体")]
public static void ShowReplacer()
{
var window = GetWindow<CombinedTool>("组合工具");
window.currentTab = Tab.Replacer;
window.Show();
}
private void OnEnable()
{
// 加载上次使用的标签页
currentTab = (Tab)EditorPrefs.GetInt("CombinedTool_CurrentTab", (int)Tab.Creator);
}
private void OnDisable()
{
// 保存当前标签页
EditorPrefs.SetInt("CombinedTool_CurrentTab", (int)currentTab);
}
private void OnGUI()
{
DrawTabs();
EditorGUILayout.Space(10);
switch (currentTab)
{
case Tab.Creator:
DrawCreatorGUI();
break;
case Tab.Replacer:
DrawReplacerGUI();
break;
}
}
private void DrawTabs()
{
EditorGUILayout.BeginHorizontal();
{
if (GUILayout.Toggle(currentTab == Tab.Creator, "阵列生成器", EditorStyles.toolbarButton))
currentTab = Tab.Creator;
if (GUILayout.Toggle(currentTab == Tab.Replacer, "替换子物体", EditorStyles.toolbarButton))
currentTab = Tab.Replacer;
}
EditorGUILayout.EndHorizontal();
}
// ---------- 阵列生成器界面 ----------
private void DrawCreatorGUI()
{
GUILayout.Label("阵列参数", EditorStyles.boldLabel);
creatorPrefab = (GameObject)EditorGUILayout.ObjectField("物品预制体", creatorPrefab, typeof(GameObject), false);
creatorRows = EditorGUILayout.IntField("行数", creatorRows);
creatorColumns = EditorGUILayout.IntField("列数", creatorColumns);
creatorSpacing = EditorGUILayout.FloatField("间距", creatorSpacing);
creatorOffset = EditorGUILayout.Vector3Field("整体偏移", creatorOffset);
creatorParent = (Transform)EditorGUILayout.ObjectField("父对象 (可选)", creatorParent, typeof(Transform), true);
EditorGUILayout.Space();
GUI.enabled = creatorPrefab != null;
if (GUILayout.Button("生成阵列"))
{
GenerateGrid();
}
if (GUILayout.Button("清除所有生成的物品"))
{
ClearGenerated();
}
GUI.enabled = true;
if (creatorParent != null)
{
EditorGUILayout.HelpBox($"当前父对象下现有 {creatorParent.childCount} 个子物体", MessageType.Info);
}
}
// ---------- 替换子物体界面 ----------
private void DrawReplacerGUI()
{
GUILayout.Label("设置", EditorStyles.boldLabel);
replacerParentObject = (GameObject)EditorGUILayout.ObjectField("父物体", replacerParentObject, typeof(GameObject), true);
replacerPrefab = (GameObject)EditorGUILayout.ObjectField("目标预制体", replacerPrefab, typeof(GameObject), false);
GUI.enabled = replacerParentObject != null && replacerPrefab != null;
if (GUILayout.Button("执行替换"))
{
Replace();
}
GUI.enabled = true;
if (replacerParentObject != null)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField($"父物体下将替换 {replacerParentObject.transform.childCount} 个子物体。", EditorStyles.helpBox);
}
}
// ---------- 阵列生成器核心逻辑 ----------
private void GenerateGrid()
{
if (creatorPrefab == null)
{
Debug.LogError("请先指定物品预制体!");
return;
}
Transform parent = creatorParent;
if (parent == null)
{
GameObject newParent = new GameObject("GeneratedGrid");
parent = newParent.transform;
Undo.RegisterCreatedObjectUndo(newParent, "Create Grid Parent");
}
Undo.RegisterCompleteObjectUndo(parent, "Generate Grid");
float startX = -(creatorColumns - 1) * creatorSpacing * 0.5f;
float startZ = -(creatorRows - 1) * creatorSpacing * 0.5f;
List<GameObject> createdObjects = new List<GameObject>();
for (int i = 0; i < creatorRows; i++)
{
for (int j = 0; j < creatorColumns; j++)
{
float x = startX + j * creatorSpacing;
float z = startZ + i * creatorSpacing;
Vector3 localPos = new Vector3(x, 0, z) + creatorOffset;
GameObject newObj;
if (PrefabUtility.IsPartOfAnyPrefab(creatorPrefab))
{
newObj = (GameObject)PrefabUtility.InstantiatePrefab(creatorPrefab);
}
else
{
newObj = Instantiate(creatorPrefab);
}
Undo.RegisterCreatedObjectUndo(newObj, "Create Grid Item");
Transform newTransform = newObj.transform;
Undo.SetTransformParent(newTransform, parent, "Reparent Grid Item");
newTransform.localPosition = localPos;
newTransform.localRotation = Quaternion.identity;
newTransform.localScale = Vector3.one;
newObj.name = $"{creatorPrefab.name}_{i}_{j}";
createdObjects.Add(newObj);
}
}
Debug.Log($"生成完成:共 {creatorRows * creatorColumns} 个物品,父对象为 {parent.name}");
}
private void ClearGenerated()
{
if (creatorParent == null)
{
Debug.LogWarning("未指定父对象,无法清除。");
return;
}
Undo.RegisterCompleteObjectUndo(creatorParent, "Clear Generated Items");
List<GameObject> childrenToDelete = new List<GameObject>();
foreach (Transform child in creatorParent)
{
childrenToDelete.Add(child.gameObject);
}
foreach (GameObject child in childrenToDelete)
{
Undo.DestroyObjectImmediate(child);
}
Debug.Log($"已清除 {childrenToDelete.Count} 个生成的物品");
}
// ---------- 替换子物体核心逻辑 ----------
private void Replace()
{
if (replacerParentObject == null || replacerPrefab == null) return;
Undo.RegisterFullObjectHierarchyUndo(replacerParentObject, "Replace Children with Prefab");
Transform parent = replacerParentObject.transform;
List<Transform> children = new List<Transform>();
foreach (Transform child in parent)
{
children.Add(child);
}
foreach (Transform child in children)
{
Vector3 localPos = child.localPosition;
Quaternion localRot = child.localRotation;
Vector3 localScale = child.localScale;
string oldName = child.name;
Undo.DestroyObjectImmediate(child.gameObject);
GameObject newObj = (GameObject)PrefabUtility.InstantiatePrefab(replacerPrefab);
Undo.RegisterCreatedObjectUndo(newObj, "Create replacement object");
Transform newTransform = newObj.transform;
Undo.SetTransformParent(newTransform, parent, "Reparent replacement");
newTransform.localPosition = localPos;
newTransform.localRotation = localRot;
newTransform.localScale = localScale;
newObj.name = oldName;
}
Debug.Log($"替换完成,共处理 {children.Count} 个子物体。");
}
}