Add a prefab creator window

This commit is contained in:
Michal Pikulski
2025-09-10 13:47:59 +02:00
parent f5bd7457a9
commit ba56f1ec9c
2 changed files with 213 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
using UnityEditor;
using UnityEngine;
using System.IO;
namespace Editor
{
public class PrefabCreatorWindow : EditorWindow
{
private string _prefabName = "NewPrefab";
private string _saveFolderPath = "Assets/Prefabs/Items";
private string _pickupSoFolderPath = "Assets/Data/Items";
private string _puzzleSoFolderPath = "Assets/Data/Puzzles";
private bool _addPickup;
private bool _addCombineWith;
private bool _addSlot;
private bool _addObjective;
private PickupItemData _pickupData;
private PuzzleStepSO _objectiveData;
private UnityEditor.Editor _soEditor;
[MenuItem("Tools/Prefab Creator")]
public static void ShowWindow()
{
var window = GetWindow<PrefabCreatorWindow>("Prefab Creator");
window.minSize = new Vector2(400, 400);
// Set default paths if not already set
if (string.IsNullOrEmpty(window._saveFolderPath))
window._saveFolderPath = "Assets/Prefabs/Items";
if (string.IsNullOrEmpty(window._pickupSoFolderPath))
window._pickupSoFolderPath = "Assets/Data/Items";
if (string.IsNullOrEmpty(window._puzzleSoFolderPath))
window._puzzleSoFolderPath = "Assets/Data/Puzzles";
}
private void OnGUI()
{
EditorGUILayout.LabelField("Prefab Creator", EditorStyles.boldLabel);
_prefabName = EditorGUILayout.TextField("Prefab Name", _prefabName);
// Prefab save folder
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Save Folder");
EditorGUILayout.SelectableLabel(_saveFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
if (GUILayout.Button("Select...", GUILayout.Width(80)))
{
string selected = EditorUtility.OpenFolderPanel("Select Save Folder", Path.Combine(Application.dataPath, "Prefabs/Items"), "");
if (!string.IsNullOrEmpty(selected))
{
if (selected.Replace("\\", "/").Contains(Application.dataPath.Replace("\\", "/")))
{
_saveFolderPath = "Assets" + selected.Replace("\\", "/").Substring(Application.dataPath.Replace("\\", "/").Length);
}
else
{
EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside the Assets directory.", "OK");
}
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Add Components:", EditorStyles.boldLabel);
_addPickup = EditorGUILayout.Toggle("Pickup", _addPickup);
_addCombineWith = EditorGUILayout.Toggle("CombineWithBehavior", _addCombineWith);
_addSlot = EditorGUILayout.Toggle("SlotItemBehavior", _addSlot);
_addObjective = EditorGUILayout.Toggle("ObjectiveStepBehaviour", _addObjective);
EditorGUILayout.Space();
if (_addPickup)
{
EditorGUILayout.LabelField("Pickup Data:", EditorStyles.boldLabel);
_pickupData = (PickupItemData)EditorGUILayout.ObjectField("PickupItemData", _pickupData, typeof(PickupItemData), false);
// Pickup SO save folder
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Save To");
EditorGUILayout.SelectableLabel(_pickupSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
if (GUILayout.Button("Select...", GUILayout.Width(80)))
{
string selected = EditorUtility.OpenFolderPanel("Select Pickup Data Folder", Path.Combine(Application.dataPath, "Data/Items"), "");
if (!string.IsNullOrEmpty(selected))
{
if (selected.Replace("\\", "/").Contains(Application.dataPath.Replace("\\", "/")))
{
_pickupSoFolderPath = "Assets" + selected.Replace("\\", "/").Substring(Application.dataPath.Replace("\\", "/").Length);
}
else
{
EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside the Assets directory.", "OK");
}
}
}
EditorGUILayout.EndHorizontal();
if (_pickupData == null && GUILayout.Button("Create New PickupItemData"))
{
_pickupData = CreateScriptableAsset<PickupItemData>(_prefabName + "_pickupSO", _pickupSoFolderPath);
}
if (_pickupData != null)
{
DrawScriptableObjectEditor(_pickupData);
}
}
if (_addObjective)
{
EditorGUILayout.LabelField("Objective Data:", EditorStyles.boldLabel);
_objectiveData = (PuzzleStepSO)EditorGUILayout.ObjectField("PuzzleStepSO", _objectiveData, typeof(PuzzleStepSO), false);
// Puzzle SO save folder
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Save To");
EditorGUILayout.SelectableLabel(_puzzleSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
if (GUILayout.Button("Select...", GUILayout.Width(80)))
{
string selected = EditorUtility.OpenFolderPanel("Select Puzzle Data Folder", Path.Combine(Application.dataPath, "Data/Puzzles"), "");
if (!string.IsNullOrEmpty(selected))
{
if (selected.Replace("\\", "/").Contains(Application.dataPath.Replace("\\", "/")))
{
_puzzleSoFolderPath = "Assets" + selected.Replace("\\", "/").Substring(Application.dataPath.Replace("\\", "/").Length);
}
else
{
EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside the Assets directory.", "OK");
}
}
}
EditorGUILayout.EndHorizontal();
if (_objectiveData == null && GUILayout.Button("Create New PuzzleStepSO"))
{
_objectiveData = CreateScriptableAsset<PuzzleStepSO>(_prefabName + "_puzzleSO", _puzzleSoFolderPath);
}
if (_objectiveData != null)
{
DrawScriptableObjectEditor(_objectiveData);
}
}
GUILayout.FlexibleSpace();
GUI.enabled = !string.IsNullOrEmpty(_prefabName) && !string.IsNullOrEmpty(_saveFolderPath);
if (GUILayout.Button("Create Prefab"))
{
CreatePrefab();
}
GUI.enabled = true;
}
private void CreatePrefab()
{
var go = new GameObject(_prefabName);
go.AddComponent<Interactable>();
go.AddComponent<BoxCollider>();
int interactableLayer = LayerMask.NameToLayer("Interactable");
if (interactableLayer != -1)
go.layer = interactableLayer;
go.AddComponent<SpriteRenderer>();
if (_addPickup)
{
var pickup = go.AddComponent<Pickup>();
pickup.itemData = _pickupData;
}
if (_addCombineWith)
{
go.AddComponent<CombineWithBehavior>();
}
if (_addSlot)
{
go.AddComponent<SlotItemBehavior>();
}
if (_addObjective)
{
var obj = go.AddComponent<ObjectiveStepBehaviour>();
obj.stepData = _objectiveData;
}
string prefabPath = Path.Combine(_saveFolderPath, _prefabName + ".prefab").Replace("\\", "/");
PrefabUtility.SaveAsPrefabAsset(go, prefabPath);
DestroyImmediate(go);
AssetDatabase.Refresh();
EditorUtility.DisplayDialog("Prefab Created", $"Prefab saved to {prefabPath}", "OK");
}
private T CreateScriptableAsset<T>(string assetName, string folderPath) where T : ScriptableObject
{
// Ensure folder exists
if (!AssetDatabase.IsValidFolder(folderPath))
{
Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), folderPath));
AssetDatabase.Refresh();
}
string folder = !string.IsNullOrEmpty(folderPath) ? folderPath : "Assets";
string path = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(folder, assetName + ".asset"));
var asset = ScriptableObject.CreateInstance<T>();
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Selection.activeObject = asset;
return asset;
}
private string SanitizeFileName(string fileName)
{
foreach (char c in Path.GetInvalidFileNameChars())
fileName = fileName.Replace(c, '_');
return fileName;
}
private void DrawScriptableObjectEditor(ScriptableObject so)
{
if (so == null) return;
if (_soEditor == null || _soEditor.target != so)
_soEditor = UnityEditor.Editor.CreateEditor(so);
if (_soEditor != null)
_soEditor.OnInspectorGUI();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f67e06e997f642509ba61ea12b0f793e
timeCreated: 1757503955