/// <summary> /// GUI を描画する時に呼び出されます /// </summary> public override void OnGUI(string searchContext) { var settings = GameObjectDuplicationHookerSettings.LoadFromEditorPrefs(); using (var checkScope = new EditorGUI.ChangeCheckScope()) { settings.IsEnable = EditorGUILayout.Toggle("Enabled", settings.IsEnable); settings.IsEnableSerialNumber = EditorGUILayout.Toggle("Enabled Serial Number", settings.IsEnableSerialNumber); if (checkScope.changed) { GameObjectDuplicationHookerSettings.SaveToEditorPrefs(settings); } } }
/// <summary> /// Hierarchy の項目を描画する時に呼び出されます /// </summary> private static void HierarchyWindowItemOnGui(int instanceID, Rect selectionRect) { // Preferences で有効になっているかどうかを確認する var settings = GameObjectDuplicationHookerSettings.LoadFromEditorPrefs(); var isEnable = settings.IsEnable; if (!isEnable) { return; } // 複製コマンド以外のイベントは無視 var current = Event.current; var commandName = current.commandName; if (string.IsNullOrWhiteSpace(commandName)) { return; } if (commandName != "Duplicate") { return; } var type = current.type; if (type != EventType.ExecuteCommand && type != EventType.ValidateCommand) { return; } // 独自の複製コマンドで処理を上書きするため、 // Unity 通常の複製コマンドを検知したら使用済みにする current.Use(); // commandName が Duplicate のイベントは1フレームの間に何回も来るため // すでに独自の複製処理を実行している場合はここから先には進めない if (m_isDuplicating) { return; } m_isDuplicating = true; var duplicatedGameObjectList = new List <GameObject>(); // 現在選択中のゲームオブジェクトを順番に複製していく // Selection.gameObjects は順不同で毎回順番が変わってしまうため sibilingIndex でソート foreach (var original in Selection.gameObjects.OrderBy(x => x.transform.GetSiblingIndex())) { // 複製後に名前の末尾に数値を付けないようにするために名前をキャッシュ // スケーリング値などに誤差が生じないようにするために transform のプロパティもキャッシュ var name = original.name; var localPosition = original.transform.localPosition; var localRotation = original.transform.localRotation; var localScale = original.transform.localScale; GameObject clone; // プレハブのインスタンスかどうかで使用する Instantiate を切り替える if (PrefabUtility.GetPrefabAssetType(original) == PrefabAssetType.NotAPrefab) { clone = Object.Instantiate(original, original.transform.parent); } else { // プレハブのインスタンスの場合は元のプレハブから Instantiate する var prefab = PrefabUtility.GetCorrespondingObjectFromSource(original); clone = ( GameObject )PrefabUtility.InstantiatePrefab(prefab, original.transform.parent); } // 連番対応が有効になっている場合は // 名前の文字列末尾の数字をインクリメントします if (settings.IsEnableSerialNumber) { name = GetNameWithSerialNumber(name); } // キャッシュしておいたパラメータを設定 clone.name = name; clone.transform.localPosition = localPosition; clone.transform.localRotation = localRotation; clone.transform.localScale = localScale; // 複製完了後に複製したゲームオブジェクトを // Hierarchy で選択状態にするために一時リストに保持 duplicatedGameObjectList.Add(clone); // Undo できるように登録 Undo.RegisterCreatedObjectUndo(clone, "Duplicate"); } EditorApplication.delayCall += () => { // 複製したゲームオブジェクトを Hierarchy で選択状態にする // この処理を1フレーム待たないと独自の複製コマンドが正常に動作しなかった Selection.instanceIDs = duplicatedGameObjectList .Select(x => x.GetInstanceID()) .ToArray() ; duplicatedGameObjectList.Clear(); m_isDuplicating = false; }; }