Unity拓展关于阵列物品生成以及物品替换

用于快速在某个物体下生成阵列,以及替换子物体。

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} 个子物体。");
    }
}
相关推荐
xcLeigh10 小时前
Unity基础:创建你的第一个游戏物体——Cube、Sphere与基本3D物体
游戏·3d·unity·教程
ellis197011 小时前
C#异常相关关键字:Exceptions,throw,try,catch,finally
unity·c#
HH‘HH21 小时前
Unity通过OPC UA工业协议连接工业设备实战指南
unity·游戏引擎
め.1 天前
定点数运算库
算法·unity
点量云实时渲染-小芹1 天前
UE/Unity/Webgl模型在信创服务器上实时渲染推流的可行性分析
unity·webgl·云渲染信创·国产实时渲染·ue信创云推流
Duo1J1 天前
【UE】Slate 编辑器工具开发03 - 节点编辑器 (EdGraph)
ue5·编辑器·游戏引擎·ue4
郝学胜-神的一滴1 天前
[简化版 GAMES 104] 现代游戏引擎 02:拆解现代游戏引擎5+1层级架构,吃透引擎底层核心逻辑
c++·unity·架构·游戏引擎·图形渲染·unreal engine·系统设计
unityのkiven1 天前
Unity 中如何创建一片森林:享元模式能不能用?应该怎么用?
unity·游戏引擎·享元模式
LONGZETECH2 天前
新能源汽车充电设备装配与调试仿真教学软件 技术架构与核心实现解析
大数据·算法·3d·unity·架构·汽车