如何调整一个克隆的形状/尺寸以影响场景视图中的所有其他克隆 [英] How can I adjust shape/dimensions of one clone to affect all other clones in the scene view

查看:89
本文介绍了如何调整一个克隆的形状/尺寸以影响场景视图中的所有其他克隆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过调整一个来更改/调整场景视图中多个克隆对象的形状/尺寸.该对象可以说是需要扩展的四边形或线渲染器.例如,当一个游戏对象线条渲染器在场景视图中扩展(使用鼠标)时,所有其他克隆都将受到影响.我知道在克隆之前调整一个对象的形状/尺寸要简单得多,而且可以在预制件上进行此更改并将其应用于所有对象,但是我需要查看它们发生的动态变化,以使我的设计过程更加灵活.有效的. 我还想在需要时打开和关闭此功能.请在

I would like to change/adjust the shape/dimensions of several cloned objects within the scene view by adjusting one. This object could be say a quad or a line renderer that needs to be extended. For example as one game objects line renderer is extended (using the mouse) in the scene view, all other clones are affected. I know that it's a lot simpler to adjust shape/dimensions of one object before cloning it, also this change can be made on a prefab and applied to all, but I need to see the dynamic changes as they happen to make my design process more effective. I would also like to turn this functionality on and off, when the need arises. Please see how I created my clones in this question.

请注意,我不想在运行时实现这一目标.

Note that I don't want to achieve this at runtime.

推荐答案

如何调整一个克隆的形状/尺寸以影响其他所有克隆 在场景视图中克隆

How can I adjust shape/dimensions of one clone to affect all other clones in the scene view

在修改组件时同步属性.为了使用现有的代码库,我们还需要克隆修改后的对象,以确保在我们重新创建其他对象时不会将其销毁.

Synchronize properties when modifications to the component are made. To work with the existing code-base, we'll also need to clone the modified object to ensure that it's not destroyed when we re-create the other objects.

该对象可以是需要渲染为四边形或线条的渲染器 扩展

This object could be say a quad or a line renderer that needs to be extended

所以我们想知道 any 组件上的 any 属性何时被修改.使用自定义脚本,对于OnValidate来说是微不足道的,但是对于像LineRenderer这样的密封组件,这有点棘手.幸运的是,由于我们正在使用编辑器,因此可以使用其一些核心功能.

So we want to know when any property on any component has been modified. With custom scripts it's trivial with OnValidate, but with a sealed component such LineRenderer it's a little trickier. Fortunately, since we're working with the Editor we have access to some of its core features.

具体来说,只要对场景进行修改,我们就可以加入到Editor的Undo.postprocessModifications事件中以获取回调.该委托将为我们提供一个UndoPropertyModification数组,该数组将包含一个已修改组件属性的列表,可用于通过EditorUtility.CopySerializedIfDifferent与其他对象进行同步.

Specifically, we can hook into the Editor's Undo.postprocessModifications event to get a callback whenever modifications are made to the scene. This delegate will provide us with an UndoPropertyModification array that will contain a list of modified component properties which we can use to synchronize the other objects via EditorUtility.CopySerializedIfDifferent.

CircleSpawn

CircleSpawn

[ExecuteInEditMode]
public class CircleSpawn : MonoBehaviour
{
    public List<GameObject> Objects;
    public GameObject OriginalObject;
    public GameObject PreviousObject;
    public GameObject ActiveObject;
    public SpawnData Data;

    private void OnEnable ()
    {
        if (Objects == null) Objects = new List<GameObject>();

        // Register modification event
        Undo.postprocessModifications += OnPropertyModification;
    }

    private void OnDisable ()
    {
        // Deregister modification event
        Undo.postprocessModifications -= OnPropertyModification;
    }

    private UndoPropertyModification[] OnPropertyModification (
            UndoPropertyModification[] modifications)
    {
        // Iterate through modifications
        foreach (var mod in modifications)
        {
            var trg = mod.currentValue.target as Component;
            if (trg)
            {
                // Filter only those objects that we've created
                if (Objects.Contains(trg.gameObject))
                {
                    // Clone the object and make it 'active'
                    if (!ActiveObject.Equals(trg.gameObject))
                    {
                        SetActiveObj(Instantiate(trg.gameObject));
                        ActiveObject.name = OriginalObject.name;
                        ActiveObject.hideFlags =
                        HideFlags.DontSaveInBuild | HideFlags.HideInHierarchy;
                        ActiveObject.SetActive(false);
                    }

                    // Synchronize the other object properties
                    foreach (var obj in Objects)
                    {
                        var type = mod.currentValue.target.GetType();
                        var comp = obj.GetComponent(type);
                        if (comp == null)
                            comp = obj.AddComponent(type);

                        EditorUtility.CopySerializedIfDifferent(trg, comp);
                    }

                    UpdateTransforms();
                    break;
                }
            }
        }

        return modifications;
    }

    public void SetActiveObj (GameObject active)
    {
        // Destroy the active object
        if (!OriginalObject.Equals(ActiveObject) &&
             PreviousObject && !PreviousObject.Equals(ActiveObject))
             DestroyImmediate(ActiveObject);

        ActiveObject = active;
    }

    public void UpdateObjects ()
    {    
        // Destroy old objects
        foreach (var obj in Objects) DestroyImmediate(obj);

        Objects.Clear();

        var steps = 360.0f / Data.Count;
        var angle = 0f;

        // Instantiate new objects
        for (var i = 0; i < Data.Count; i++)
        {
            var rot = Quaternion.Euler(0f, 0f, Data.Angle + angle);
            var pos = rot * Vector3.right * Data.Radius;
            var obj = Instantiate(ActiveObject, transform.position + pos, rot);
            obj.SetActive(true);
            Objects.Add(obj);
            angle += steps;
        }
    }

    public void UpdateTransforms ()
    {
        var steps = 360.0f / Objects.Count;
        var angle = 0f;

        // Set transforms based on Angle and Radius
        for (var i = 0; i < Objects.Count; i++)
        {
            var rot = Quaternion.Euler(0f, 0f, Data.Angle + angle);
            var pos = rot * Vector3.right * Data.Radius;
            Objects[i].transform.position =
            transform.position + pos;
            Objects[i].transform.rotation = rot;
            angle += steps;
        }
    }
}

CircleSpawnEditor

CircleSpawnEditor

[CustomEditor(typeof(CircleSpawn))]
public class CircleSpawnEditor : Editor
{
    public override void OnInspectorGUI ()
    {
        GUI.enabled = !EditorApplication.isPlaying;
        var spawner = (CircleSpawn)target;

        // Draw object field
        EditorGUILayout.LabelField("Object");
        spawner.OriginalObject = (GameObject)EditorGUILayout.ObjectField(
        spawner.OriginalObject, typeof(GameObject), true);
        if (!spawner.OriginalObject) return;

        // Restore original object
        if (GUILayout.Button("Revert") || !spawner.ActiveObject ||
           !spawner.OriginalObject.Equals(spawner.PreviousObject))
        {
            // Store data reference
            spawner.Data = spawner.OriginalObject.GetComponent<SpawnData>();
            if (!spawner.Data) return;

            spawner.SetActiveObj(spawner.OriginalObject);
            spawner.PreviousObject = spawner.OriginalObject;
            spawner.UpdateObjects();
        }

        // Draw numeric sliders
        EditorGUILayout.LabelField("Radius"); // Set as required
        spawner.Data.Radius = EditorGUILayout.Slider(spawner.Data.Radius, 0f, 100f);
        EditorGUILayout.LabelField("Angle"); // Set as required
        spawner.Data.Angle = EditorGUILayout.Slider(spawner.Data.Angle, 0f, 360f);
        EditorGUILayout.LabelField("Count"); // Set as required
        spawner.Data.Count = EditorGUILayout.IntSlider(spawner.Data.Count, 0, 36);  

        // Update objects on Count slider change
        if (spawner.Data.Count != spawner.Objects.Count)
            spawner.UpdateObjects();

        // Update transforms on Angle or Radius slider change
        if (!Mathf.Approximately(spawner.Data.Angle, spawner.Data.LastAngle) ||
            !Mathf.Approximately(spawner.Data.Radius, spawner.Data.LastRadius))
        {
            spawner.Data.LastAngle = spawner.Data.Angle;
            spawner.Data.LastRadius = spawner.Data.Radius;
            spawner.UpdateTransforms();
        }
    }
}

SpawnData

SpawnData

public class SpawnData : MonoBehaviour
{
    public int Count;
    public float Radius, LastRadius, Angle, LastAngle;
}

我已经对代码进行了一些重构,但是在大多数情况下,更改很少.

这篇关于如何调整一个克隆的形状/尺寸以影响场景视图中的所有其他克隆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆