You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过滑块动态创建/销毁并调整圆形排列的2D游戏对象

实现实时预览的等距圆形排列编辑器工具

我完全明白你的需求——把原来「点击按钮才生效」的工具改成滑块实时调整、场景即时预览的版本,核心就是把创建/更新逻辑从按钮点击事件,转移到参数变更的回调里,同时处理好对象的增删和位置更新。

下面我给你一步步拆解实现方案,假设你原来的编辑器是基于EditorWindow做的(如果是自定义Inspector的话逻辑类似):


第一步:定义核心变量与初始化

首先我们需要在编辑器类里存储当前的对象列表、数量、半径这些参数,还要记录一个父对象来管理这些排列的GameObject,避免场景杂乱:

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class CircleArrangerWindow : EditorWindow
{
    // 排列参数
    private int objectCount = 8;
    private float radius = 2f;
    // 预制体(替换成你自己的对象即可)
    private GameObject prefab;
    // 存储已创建的对象,方便后续增删操作
    private List<GameObject> spawnedObjects = new List<GameObject>();
    // 父对象,用来统一管理所有排列的对象
    private GameObject parentObject;

    [MenuItem("Tools/Circle Arranger")]
    public static void ShowWindow()
    {
        GetWindow<CircleArrangerWindow>("Circle Arranger");
    }
}

第二步:绘制UI滑块并监听参数变化

在OnGUI()里绘制滑块,然后实时判断参数是否发生变化——只要参数被修改,立刻执行更新逻辑:

private void OnGUI()
{
    GUILayout.Label("Circle Arrangement Settings", EditorStyles.boldLabel);

    // 预制体选择框
    prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);

    // 数量滑块(限制1-20个,你可以自己调整范围)
    int newCount = EditorGUILayout.IntSlider("Object Count", objectCount, 1, 20);
    // 半径滑块(限制0.5-10米,范围按需调整)
    float newRadius = EditorGUILayout.Slider("Radius", radius, 0.5f, 10f);

    // 检查参数是否变化,变化则触发更新;也保留手动强制更新按钮
    if (newCount != objectCount || newRadius != radius || GUILayout.Button("Force Update"))
    {
        objectCount = newCount;
        radius = newRadius;
        UpdateCircleArrangement();
    }
}

第三步:实现核心的更新逻辑(创建/销毁+位置调整)

UpdateCircleArrangement()方法是核心,它要完成三件事:

  1. 确保父对象存在(用来统一管理所有排列的对象)
  2. 根据新的数量,自动创建或销毁多余的对象
  3. 重新计算所有对象的位置,保持圆形等距排列
private void UpdateCircleArrangement()
{
    if (prefab == null)
    {
        Debug.LogWarning("请先指定要排列的预制体!");
        return;
    }

    // 初始化父对象(如果不存在就创建)
    if (parentObject == null)
    {
        parentObject = new GameObject("CircleArrangement_Parent");
    }

    // --- 处理对象数量变化:创建/销毁对象 ---
    // 如果需要更多对象,批量创建新的
    while (spawnedObjects.Count < objectCount)
    {
        GameObject newObj = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
        newObj.transform.SetParent(parentObject.transform);
        spawnedObjects.Add(newObj);
    }
    // 如果需要更少对象,销毁多余的
    while (spawnedObjects.Count > objectCount)
    {
        GameObject objToRemove = spawnedObjects[spawnedObjects.Count - 1];
        spawnedObjects.Remove(objToRemove);
        DestroyImmediate(objToRemove); // 编辑器模式下用DestroyImmediate
    }

    // --- 重新计算所有对象的位置,保持等距圆形排列 ---
    float angleStep = 360f / objectCount; // 每个对象的角度间隔(始终保持等距)
    for (int i = 0; i < spawnedObjects.Count; i++)
    {
        float angle = i * angleStep;
        // 角度转弧度,计算世界坐标
        float radian = angle * Mathf.Deg2Rad;
        float x = Mathf.Cos(radian) * radius;
        float z = Mathf.Sin(radian) * radius;
        spawnedObjects[i].transform.position = new Vector3(x, 0, z);

        // 可选:让对象朝向圆心
        spawnedObjects[i].transform.LookAt(parentObject.transform.position);
    }
}

第四步:额外优化:窗口关闭时的自动清理(可选)

如果希望关闭编辑器窗口时自动清理测试对象,可以加上OnDestroy()回调:

private void OnDestroy()
{
    if (parentObject != null)
    {
        DestroyImmediate(parentObject);
    }
    spawnedObjects.Clear();
}

关键逻辑说明

  1. 数量滑块的处理:通过while循环对比当前对象数量和目标数量,少了就创建,多了就销毁,确保数量完全匹配。
  2. 保持等距角度:每次更新时重新计算angleStep = 360 / objectCount,这样无论数量多少,对象都会均匀分布在360度的圆形上,相邻对象的角度间距始终等距。
  3. 半径实时调整:每次半径变化时,重新计算所有对象的坐标,立刻在场景视图中看到位置变化。

这样你滑动滑块的时候,场景里的对象会实时增删、调整位置,完全不需要点击按钮啦!

内容的提问来源于stack exchange,提问作者Hilarious404

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:05:16