【Unity】複数のオブジェクトをオフセット移動させるエディタ拡張

やりたいこと

特にUIを作成していると複数のオブジェクトをまとめて平行移動したいということがちらほらあります。
親子関係をしっかり管理していればよいのですが、手を抜いていると面倒なことになります。

方法としては複数選択してシーンビュー上で手動で動かすということもできますが、その場合手動なので、微妙に位置ズレしたり、Xだけ動かしたいのでYも微妙に変わるなどが起こります。

Ctrlを押しながらスナップ移動という手段もありますが、スナップ移動の指定単位はTransform基準なのでRectTransform上では微妙な値になったりします。

そこで選択したオブジェクトを簡単にオフセット移動させるエディタ拡張を作成しました。

実際のコード

実際のコードは以下になります。

Editorフォルダ配下にスクリプトを作成し、下記をコピペしてください。

using UnityEngine;
using UnityEditor;

namespace CatHut
{
    public class SelectedObjectOffsetter : EditorWindow
    {
        /// <summary>
        /// Position offset for RectTransform.
        /// </summary>
        private Vector3? rectPosition;
        /// <summary>
        /// Rotation offset for RectTransform.
        /// </summary>
        private Vector3? rectRotation;
        /// <summary>
        /// Scale offset for RectTransform.
        /// </summary>
        private Vector3? rectScale;

        /// <summary>
        /// Position offset for Transform.
        /// </summary>
        private Vector3? transPosition;
        /// <summary>
        /// Rotation offset for Transform.
        /// </summary>
        private Vector3? transRotation;
        /// <summary>
        /// Scale offset for Transform.
        /// </summary>
        private Vector3? transScale;

        /// <summary>
        /// Displays the Selected Object Offsetter window.
        /// </summary>
        [MenuItem("Tools/CatHut/Selected Object Offsetter %&m")]
        public static void ShowWindow()
        {
            GetWindow<SelectedObjectOffsetter>("Selected Object Offsetter");
        }

        /// <summary>
        /// Draws the GUI elements for the editor window.
        /// </summary>
        private void OnGUI()
        {
            GUILayout.Label("RectTransform 操作", EditorStyles.boldLabel);
            DrawTransformControls(ref rectPosition, ref rectRotation, ref rectScale);

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("RectTransformに反映"))
            {
                ApplyToSelectedRectTransforms();
            }
            if (GUILayout.Button("入力値リセット"))
            {
                rectPosition = Vector3.zero;
                rectRotation = Vector3.zero;
                rectScale = Vector3.zero;
                GUI.FocusControl(null); // Remove focus from the current control
            }
            GUILayout.EndHorizontal();

            GUILayout.Space(20);

            GUILayout.Label("Transform 操作", EditorStyles.boldLabel);
            DrawTransformControls(ref transPosition, ref transRotation, ref transScale);

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Transformに反映"))
            {
                ApplyToSelectedTransforms();
            }
            if (GUILayout.Button("入力値リセット"))
            {
                transPosition = Vector3.zero;
                transRotation = Vector3.zero;
                transScale = Vector3.zero;
                GUI.FocusControl(null); // Remove focus from the current control
            }
            GUILayout.EndHorizontal();
        }

        /// <summary>
        /// Draws the input fields for position, rotation, and scale for either RectTransform or Transform.
        /// </summary>
        /// <param name="position">Position value.</param>
        /// <param name="rotation">Rotation value.</param>
        /// <param name="scale">Scale value.</param>
        private void DrawTransformControls(ref Vector3? position, ref Vector3? rotation, ref Vector3? scale)
        {
            position = EditorGUILayout.Vector3Field("Position", position ?? Vector3.zero);
            rotation = EditorGUILayout.Vector3Field("Rotation", rotation ?? Vector3.zero);
            scale = EditorGUILayout.Vector3Field("Scale", scale ?? Vector3.zero);
        }

        /// <summary>
        /// Applies the specified RectTransform changes as offsets to the selected GameObjects.
        /// </summary>
        private void ApplyToSelectedRectTransforms()
        {
            foreach (GameObject obj in Selection.gameObjects)
            {
                RectTransform rectTransform = obj.GetComponent<RectTransform>();
                if (rectTransform != null)
                {
                    Undo.RecordObject(rectTransform, "Move RectTransform");

                    if (rectPosition.HasValue)
                    {
                        rectTransform.localPosition += rectPosition.Value;
                    }

                    if (rectRotation.HasValue)
                    {
                        rectTransform.localEulerAngles += rectRotation.Value;
                    }

                    if (rectScale.HasValue)
                    {
                        rectTransform.localScale += rectScale.Value;
                    }
                }
            }
        }

        /// <summary>
        /// Applies the specified Transform changes as offsets to the selected GameObjects.
        /// </summary>
        private void ApplyToSelectedTransforms()
        {
            foreach (GameObject obj in Selection.gameObjects)
            {
                Transform transform = obj.GetComponent<Transform>();
                if (transform != null)
                {
                    Undo.RecordObject(transform, "Move Transform");

                    if (transPosition.HasValue)
                    {
                        transform.localPosition += transPosition.Value;
                    }

                    if (transRotation.HasValue)
                    {
                        transform.localEulerAngles += transRotation.Value;
                    }

                    if (transScale.HasValue)
                    {
                        transform.localScale += transScale.Value;
                    }
                }
            }
        }
    }
}

使い方

上部メニューの Tools/CatHut/Selected Object Offsetter から起動すると下記のようなウィンドウが表示されます。

Transform用とRectTransform用の設定が表示されるので、移動対象によって使い分けてください。

移動したい対象を選択(複数選択可)して「反映」を押すと移動が反映されます。

指定は全てオフセット値(現在値からの変化量)です。設定値自体を指定したい場合には通常のTransformを使用してください。

使用例)

コメント

タイトルとURLをコピーしました