Created
August 2, 2025 03:16
-
-
Save gitcrtn/f841ac3458f9efae6981c8280a91855b to your computer and use it in GitHub Desktop.
Prefab Favorite Manager for Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using UnityEngine; | |
| using UnityEditor; | |
| using System.Collections.Generic; | |
| using System.IO; | |
| using System.Linq; | |
| public class PrefabFavoriteManager : EditorWindow | |
| { | |
| private List<GameObject> favoritePrefabs = new List<GameObject>(); | |
| private Vector2 scrollPosition; | |
| private const string PREF_KEY = "PrefabFavoriteManager_Favorites"; | |
| // サムネイル表示設定 | |
| private bool showThumbnails = true; | |
| private float thumbnailSize = 64f; | |
| private bool gridView = false; | |
| // サムネイル更新用 | |
| private double lastRepaintTime = 0; | |
| private const double REPAINT_INTERVAL = 0.1; // 0.1秒間隔で再描画 | |
| [MenuItem("Tools/Prefab Favorite Manager")] | |
| public static void ShowWindow() | |
| { | |
| PrefabFavoriteManager window = GetWindow<PrefabFavoriteManager>(); | |
| window.titleContent = new GUIContent("お気に入りPrefab"); | |
| window.minSize = new Vector2(300, 400); | |
| window.Show(); | |
| } | |
| private void OnEnable() | |
| { | |
| LoadFavorites(); | |
| LoadDisplaySettings(); | |
| } | |
| private void OnDisable() | |
| { | |
| SaveFavorites(); | |
| SaveDisplaySettings(); | |
| } | |
| private void OnGUI() | |
| { | |
| EditorGUILayout.Space(10); | |
| // タイトル | |
| EditorGUILayout.LabelField("Prefabお気に入りマネージャー", EditorStyles.boldLabel); | |
| EditorGUILayout.Space(5); | |
| // 表示設定 | |
| DrawDisplaySettings(); | |
| EditorGUILayout.Space(5); | |
| // ドラッグ&ドロップエリア | |
| DrawDropArea(); | |
| EditorGUILayout.Space(10); | |
| // お気に入りリスト | |
| DrawFavoritesList(); | |
| EditorGUILayout.Space(10); | |
| // 操作ボタン | |
| DrawControlButtons(); | |
| // サムネイル生成のための定期的な再描画 | |
| if (showThumbnails && EditorApplication.timeSinceStartup - lastRepaintTime > REPAINT_INTERVAL) | |
| { | |
| lastRepaintTime = EditorApplication.timeSinceStartup; | |
| Repaint(); | |
| } | |
| } | |
| private void DrawDisplaySettings() | |
| { | |
| EditorGUILayout.BeginHorizontal(); | |
| showThumbnails = EditorGUILayout.Toggle("サムネイル表示", showThumbnails); | |
| if (showThumbnails) | |
| { | |
| EditorGUILayout.LabelField("サイズ:", GUILayout.Width(40)); | |
| thumbnailSize = EditorGUILayout.Slider(thumbnailSize, 32f, 128f, GUILayout.Width(100)); | |
| gridView = EditorGUILayout.Toggle("グリッド表示", gridView); | |
| } | |
| EditorGUILayout.EndHorizontal(); | |
| } | |
| private void DrawDropArea() | |
| { | |
| // ドラッグ&ドロップエリアの描画 | |
| Rect dropArea = GUILayoutUtility.GetRect(0, 50, GUILayout.ExpandWidth(true)); | |
| GUI.Box(dropArea, "Prefabをここにドラッグ&ドロップ", EditorStyles.helpBox); | |
| // ドラッグ&ドロップのイベント処理 | |
| Event evt = Event.current; | |
| if (dropArea.Contains(evt.mousePosition)) | |
| { | |
| if (evt.type == EventType.DragUpdated) | |
| { | |
| // ドラッグされているオブジェクトがPrefabかチェック | |
| bool validDrag = false; | |
| foreach (Object draggedObject in DragAndDrop.objectReferences) | |
| { | |
| if (draggedObject is GameObject && PrefabUtility.GetPrefabAssetType(draggedObject) != PrefabAssetType.NotAPrefab) | |
| { | |
| validDrag = true; | |
| break; | |
| } | |
| } | |
| if (validDrag) | |
| { | |
| DragAndDrop.visualMode = DragAndDropVisualMode.Copy; | |
| evt.Use(); | |
| } | |
| } | |
| else if (evt.type == EventType.DragPerform) | |
| { | |
| DragAndDrop.AcceptDrag(); | |
| // ドロップされたPrefabを追加 | |
| foreach (Object draggedObject in DragAndDrop.objectReferences) | |
| { | |
| if (draggedObject is GameObject prefab && | |
| PrefabUtility.GetPrefabAssetType(prefab) != PrefabAssetType.NotAPrefab) | |
| { | |
| AddToFavorites(prefab); | |
| } | |
| } | |
| evt.Use(); | |
| } | |
| } | |
| } | |
| private void DrawFavoritesList() | |
| { | |
| EditorGUILayout.LabelField($"お気に入り ({favoritePrefabs.Count}個)", EditorStyles.boldLabel); | |
| if (favoritePrefabs.Count == 0) | |
| { | |
| EditorGUILayout.HelpBox("お気に入りのPrefabがありません。\n上のエリアにPrefabをドラッグ&ドロップしてください。", MessageType.Info); | |
| return; | |
| } | |
| scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); | |
| if (showThumbnails && gridView) | |
| { | |
| DrawGridView(); | |
| } | |
| else | |
| { | |
| DrawListView(); | |
| } | |
| EditorGUILayout.EndScrollView(); | |
| } | |
| private Texture2D GetPrefabThumbnail(GameObject prefab) | |
| { | |
| if (prefab == null) return null; | |
| // まずAssetPreviewを試す | |
| Texture2D thumbnail = AssetPreview.GetAssetPreview(prefab); | |
| if (thumbnail != null) | |
| { | |
| return thumbnail; | |
| } | |
| // AssetPreviewが準備できていない場合、小さなサムネイルを試す | |
| thumbnail = AssetPreview.GetMiniThumbnail(prefab); | |
| if (thumbnail != null) | |
| { | |
| return thumbnail; | |
| } | |
| // それでもダメな場合、プリミティブアイコンを使用 | |
| var content = EditorGUIUtility.ObjectContent(prefab, typeof(GameObject)); | |
| return content.image as Texture2D; | |
| } | |
| private void DrawListView() | |
| { | |
| for (int i = favoritePrefabs.Count - 1; i >= 0; i--) | |
| { | |
| if (favoritePrefabs[i] == null) | |
| { | |
| favoritePrefabs.RemoveAt(i); | |
| continue; | |
| } | |
| EditorGUILayout.BeginHorizontal(EditorStyles.helpBox); | |
| if (showThumbnails) | |
| { | |
| // サムネイル表示 | |
| Texture2D thumbnail = GetPrefabThumbnail(favoritePrefabs[i]); | |
| if (thumbnail != null) | |
| { | |
| // 正方形にクロップして表示 | |
| Rect thumbnailRect = GUILayoutUtility.GetRect(thumbnailSize, thumbnailSize, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); | |
| GUI.DrawTexture(thumbnailRect, thumbnail, ScaleMode.ScaleAndCrop); | |
| } | |
| else | |
| { | |
| // フォールバック: デフォルトのGameObjectアイコン | |
| GUILayout.Label(EditorGUIUtility.IconContent("GameObject Icon"), | |
| GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); | |
| } | |
| EditorGUILayout.BeginVertical(); | |
| } | |
| // Prefab名とオブジェクトフィールド | |
| EditorGUILayout.LabelField(favoritePrefabs[i].name, EditorStyles.boldLabel); | |
| EditorGUILayout.ObjectField("", favoritePrefabs[i], typeof(GameObject), false); | |
| if (showThumbnails) | |
| { | |
| EditorGUILayout.EndVertical(); | |
| } | |
| EditorGUILayout.BeginVertical(GUILayout.Width(80)); | |
| // Hierarchyに配置ボタン | |
| if (GUILayout.Button("配置", GUILayout.Height(25))) | |
| { | |
| PlacePrefabInScene(favoritePrefabs[i]); | |
| } | |
| // 削除ボタン | |
| if (GUILayout.Button("削除", GUILayout.Height(25))) | |
| { | |
| RemoveFromFavorites(i); | |
| } | |
| EditorGUILayout.EndVertical(); | |
| EditorGUILayout.EndHorizontal(); | |
| EditorGUILayout.Space(2); | |
| } | |
| } | |
| private void DrawGridView() | |
| { | |
| float windowWidth = position.width - 30; // スクロールバーとマージンを考慮 | |
| int itemsPerRow = Mathf.Max(1, Mathf.FloorToInt(windowWidth / (thumbnailSize + 10))); | |
| for (int i = 0; i < favoritePrefabs.Count; i += itemsPerRow) | |
| { | |
| EditorGUILayout.BeginHorizontal(); | |
| for (int j = 0; j < itemsPerRow && (i + j) < favoritePrefabs.Count; j++) | |
| { | |
| int index = i + j; | |
| if (favoritePrefabs[index] == null) | |
| { | |
| favoritePrefabs.RemoveAt(index); | |
| continue; | |
| } | |
| DrawGridItem(favoritePrefabs[index], index); | |
| } | |
| EditorGUILayout.EndHorizontal(); | |
| EditorGUILayout.Space(5); | |
| } | |
| } | |
| private void DrawGridItem(GameObject prefab, int index) | |
| { | |
| EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(thumbnailSize + 10)); | |
| // サムネイル | |
| Texture2D thumbnail = GetPrefabThumbnail(prefab); | |
| if (thumbnail != null) | |
| { | |
| // サムネイルをボタンとして表示 | |
| Rect buttonRect = GUILayoutUtility.GetRect(thumbnailSize, thumbnailSize, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); | |
| if (GUI.Button(buttonRect, "")) | |
| { | |
| PlacePrefabInScene(prefab); | |
| } | |
| // ボタンの上にサムネイルを描画 | |
| GUI.DrawTexture(buttonRect, thumbnail, ScaleMode.ScaleAndCrop); | |
| } | |
| else | |
| { | |
| // フォールバック | |
| if (GUILayout.Button(EditorGUIUtility.IconContent("GameObject Icon"), | |
| GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize))) | |
| { | |
| PlacePrefabInScene(prefab); | |
| } | |
| } | |
| // Prefab名(長い名前は省略) | |
| string displayName = prefab.name; | |
| if (displayName.Length > 12) | |
| { | |
| displayName = displayName.Substring(0, 9) + "..."; | |
| } | |
| EditorGUILayout.LabelField(displayName, EditorStyles.centeredGreyMiniLabel, GUILayout.Height(16)); | |
| // 削除ボタン | |
| if (GUILayout.Button("×", GUILayout.Height(20))) | |
| { | |
| RemoveFromFavorites(index); | |
| } | |
| EditorGUILayout.EndVertical(); | |
| } | |
| private void DrawControlButtons() | |
| { | |
| EditorGUILayout.BeginHorizontal(); | |
| if (GUILayout.Button("すべてクリア")) | |
| { | |
| if (EditorUtility.DisplayDialog("確認", "すべてのお気に入りを削除しますか?", "はい", "いいえ")) | |
| { | |
| ClearAllFavorites(); | |
| } | |
| } | |
| if (GUILayout.Button("データを保存")) | |
| { | |
| SaveFavorites(); | |
| SaveDisplaySettings(); | |
| ShowNotification(new GUIContent($"保存しました ({favoritePrefabs.Count}個のPrefab)")); | |
| } | |
| EditorGUILayout.EndHorizontal(); | |
| } | |
| private void AddToFavorites(GameObject prefab) | |
| { | |
| if (prefab == null) return; | |
| if (!favoritePrefabs.Contains(prefab)) | |
| { | |
| favoritePrefabs.Add(prefab); | |
| // サムネイルの生成を開始 | |
| AssetPreview.GetAssetPreview(prefab); | |
| Debug.Log($"お気に入りに追加: {prefab.name}"); | |
| SaveFavorites(); | |
| } | |
| else | |
| { | |
| Debug.LogWarning($"既にお気に入りに登録されています: {prefab.name}"); | |
| } | |
| } | |
| private void RemoveFromFavorites(int index) | |
| { | |
| if (index >= 0 && index < favoritePrefabs.Count) | |
| { | |
| Debug.Log($"お気に入りから削除: {favoritePrefabs[index].name}"); | |
| favoritePrefabs.RemoveAt(index); | |
| SaveFavorites(); | |
| } | |
| } | |
| private void ClearAllFavorites() | |
| { | |
| favoritePrefabs.Clear(); | |
| SaveFavorites(); | |
| Debug.Log("すべてのお気に入りをクリアしました"); | |
| } | |
| private void PlacePrefabInScene(GameObject prefab) | |
| { | |
| if (prefab == null) return; | |
| GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject; | |
| if (instance != null) | |
| { | |
| // Sceneビューの中央に配置 | |
| if (SceneView.lastActiveSceneView != null) | |
| { | |
| instance.transform.position = SceneView.lastActiveSceneView.pivot; | |
| } | |
| // Undoに登録 | |
| Undo.RegisterCreatedObjectUndo(instance, $"Create {prefab.name}"); | |
| // 作成したオブジェクトを選択 | |
| Selection.activeGameObject = instance; | |
| Debug.Log($"シーンに配置: {prefab.name}"); | |
| } | |
| } | |
| private void SaveFavorites() | |
| { | |
| try | |
| { | |
| // アセットのGUIDを保存(アセットパスよりも確実) | |
| List<string> guids = new List<string>(); | |
| foreach (var prefab in favoritePrefabs) | |
| { | |
| if (prefab != null) | |
| { | |
| string assetPath = AssetDatabase.GetAssetPath(prefab); | |
| string guid = AssetDatabase.AssetPathToGUID(assetPath); | |
| if (!string.IsNullOrEmpty(guid)) | |
| { | |
| guids.Add(guid); | |
| } | |
| } | |
| } | |
| // GUIDリストを文字列として保存(区切り文字を使用) | |
| string guidString = string.Join("|", guids.ToArray()); | |
| EditorPrefs.SetString(PREF_KEY, guidString); | |
| Debug.Log($"お気に入りを保存しました: {guids.Count}個のPrefab"); | |
| } | |
| catch (System.Exception e) | |
| { | |
| Debug.LogError($"お気に入りの保存に失敗しました: {e.Message}"); | |
| } | |
| } | |
| private void LoadFavorites() | |
| { | |
| try | |
| { | |
| string guidString = EditorPrefs.GetString(PREF_KEY, ""); | |
| if (!string.IsNullOrEmpty(guidString)) | |
| { | |
| string[] guids = guidString.Split('|'); | |
| favoritePrefabs.Clear(); | |
| foreach (string guid in guids) | |
| { | |
| if (!string.IsNullOrEmpty(guid)) | |
| { | |
| string assetPath = AssetDatabase.GUIDToAssetPath(guid); | |
| if (!string.IsNullOrEmpty(assetPath)) | |
| { | |
| GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath); | |
| if (prefab != null && PrefabUtility.GetPrefabAssetType(prefab) != PrefabAssetType.NotAPrefab) | |
| { | |
| favoritePrefabs.Add(prefab); | |
| // サムネイル生成を開始 | |
| AssetPreview.GetAssetPreview(prefab); | |
| } | |
| } | |
| } | |
| } | |
| Debug.Log($"お気に入りをロードしました: {favoritePrefabs.Count}個のPrefab"); | |
| } | |
| else | |
| { | |
| favoritePrefabs = new List<GameObject>(); | |
| } | |
| } | |
| catch (System.Exception e) | |
| { | |
| Debug.LogError($"お気に入りのロードに失敗しました: {e.Message}"); | |
| favoritePrefabs = new List<GameObject>(); | |
| } | |
| } | |
| private void SaveDisplaySettings() | |
| { | |
| EditorPrefs.SetBool(PREF_KEY + "_ShowThumbnails", showThumbnails); | |
| EditorPrefs.SetFloat(PREF_KEY + "_ThumbnailSize", thumbnailSize); | |
| EditorPrefs.SetBool(PREF_KEY + "_GridView", gridView); | |
| } | |
| private void LoadDisplaySettings() | |
| { | |
| showThumbnails = EditorPrefs.GetBool(PREF_KEY + "_ShowThumbnails", true); | |
| thumbnailSize = EditorPrefs.GetFloat(PREF_KEY + "_ThumbnailSize", 64f); | |
| gridView = EditorPrefs.GetBool(PREF_KEY + "_GridView", false); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment