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} 个子物体。");
    }
}
相关推荐
叶帆14 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君14 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
会思考的猴子15 天前
Unity VFX 属性 Postion 和 TargetPostion
unity
hai31524754315 天前
九章编程法 · 猜数字游戏 (GW-BASIC 重构版) *
人工智能·microsoft·游戏引擎·游戏程序
心前阳光15 天前
Unity资源导入之自动化资源导入
unity·自动化·游戏引擎
心前阳光15 天前
Unity之2021.3.45f2c1发布安卓程序遇到的问题
android·unity·游戏引擎
纪纯15 天前
PicoVR Unity Integration SDK 3.4 常用交互API
unity·游戏引擎·vr·pico
龙智DevSecOps解决方案15 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
葛兰岱尔15 天前
从 SolidWorks 到 Three.js,从 Inventor 到 Unity——制造业CAD模型“几何-语义一体化“转换,不再是天方夜谭!
开发语言·javascript·unity
鼎艺创新科技15 天前
三维电子沙盘中OSGB倾斜摄影数据的加载与渲染
游戏引擎·cocos2d