Skip to content

Instantly share code, notes, and snippets.

@gitcrtn
Created August 2, 2025 03:16
Show Gist options
  • Select an option

  • Save gitcrtn/f841ac3458f9efae6981c8280a91855b to your computer and use it in GitHub Desktop.

Select an option

Save gitcrtn/f841ac3458f9efae6981c8280a91855b to your computer and use it in GitHub Desktop.
Prefab Favorite Manager for Unity
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