I made a post last week asking about prefab vs scriptableobject, this is more or less a followup question on that post but pertains to an entirely different concept. So i’ve been working on a custom inspector for the scriptable object so I can easily do everything I need to do. But I cant figure out how to create a new prefab from the data in the scriptableobject (line 45). Got any ideas on how to do that? I would like to create a prefab for each object and store the scriptableobject in the prefab so i can edit either and have the data reflect.
using Editor;
using Inventory;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(ItemData))]
public class ItemDataEditor : UnityEditor.Editor
{
private SerializedProperty list;
private Vector2 scrollDescription;
public void OnEnable()
{
list = serializedObject.FindProperty("Components");
}
public override void OnInspectorGUI()
{
ItemData item = (ItemData)target;
int spriteSize = 52;
int spacing = 10;
int offsetLeft = 20;
var width = Screen.width - spriteSize - (3 * spacing);
EditorHelpers.BeginArea(new Rect(offsetLeft, 2, width + 10, EditorGUIUtility.singleLineHeight * 5f));
item.Name = EditorGUILayout.TextField(item.Name);
item.StackSize = EditorGUILayout.IntSlider("Max stack size", item.StackSize, 1, 100);
item.Prefab = (GameObject)EditorGUILayout.ObjectField(item.Prefab, typeof(GameObject), false);
EditorHelpers.EndArea();
EditorHelpers.BeginArea(new Rect(offsetLeft + width, 2, Screen.width - 8, EditorGUIUtility.singleLineHeight * 5f));
item.Sprite = (Sprite)EditorGUILayout.ObjectField(item.Sprite, typeof(Sprite), false, GUILayout.Height(spriteSize), GUILayout.Width(spriteSize));
EditorHelpers.EndArea();
GUILayout.Space(EditorGUIUtility.singleLineHeight * 3.5f);
scrollDescription = EditorGUILayout.BeginScrollView(scrollDescription, GUILayout.Height(EditorGUIUtility.singleLineHeight * 4f));
item.Description = EditorGUILayout.TextArea(item.Description, GUILayout.ExpandHeight(true));
EditorGUILayout.EndScrollView();
EditorGUILayout.PropertyField(list);
EditorGUI.BeginDisabledGroup(item.Prefab);
if (GUILayout.Button("Create prefab", new GUIStyle(GUI.skin.button) { fontSize = 10 }, GUILayout.Height(15)))
{
}
EditorGUI.EndDisabledGroup();
if (GUI.changed)
{
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(item);
}
}
}
An update to what I have found so far. There doesnt seem to be a way to create a prefab object and save it without creating one in a scene and removing it afterwards. Im starting to think I might have to make a base prefab and make a prefab variant for each item. making a copy and filling in the data like that.
I can spawn prefab objects by script using Instantiate. First I drag an asset into the scene window, then from there I drag it back down into the assets where I have a prefab folder to keep them seperate, then I am prompted to see if I want a prefab made (which i do). From that point on scripts can instantiate clones of that prefab, inheriting it’s properties. You could use a script to modify those properties as you need. I find it easiest to have a public reference to the model so I can drag the prefab to that field, then the scripts can use that reference to instantiate that model. Do you need a code sample or area these concepts clear enough to you?
I am not trying to create them using a manual route, I am trying to create a new prefab from a script without the need to create a gameobject in the scene and remove it after i am done creating my data and save as a prefab. an item does not exist yet and I want to create one and store it as a prefab.
Well, I have used procedural object creation for terrain meshes, I guess you could use that for anything and just bypass the official “prefab” system and use your own preferences for the objects you create. If you make the fields you want more permanent serializable then the Unity Editor seems to keep them around.
*@*ProtagonistKun “An update to what I have found so far. There doesnt seem to be a way to create a prefab object and save it without creating one in a scene and removing it afterwards”
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateAsset : MonoBehaviour
{
[MenuItem("Test/Create Prefab")]
static void CreatePrefab()
{
var path = "Assets/prefabs";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
GameObject obj = new GameObject("test.prefab");
path = Path.Combine(path, obj.name);
var pf = PrefabUtility.SaveAsPrefabAsset(obj, path);
DestroyImmediate(obj);
Debug.Log("Created a prefab:" + AssetDatabase.GetAssetPath(pf));
}
}
EDIT: although it does create a game object… and you’ll have to remove it. Maybe there is some other way…
EDIT 2: Actually there is a deprecated method to create an empty prefab without adding a gameobject, but it will give you a warning in console…
UnityEditor.PrefabUtility.CreateEmptyPrefab(string)' is obsolete: `The concept of creating a completely empty Prefab has been discontinued. You can however use SaveAsPrefabAsset with an empty GameObject.'
Maybe it is possible to create a prefab asset without a temporary GameObject without using this deprecated method (although I don’t know how) - either way, this is how it seems to work:
[MenuItem("Test/Create Prefab")]
static void CreatePrefab()
{
var path = "Assets/prefabs";
var name = "test.prefab";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, name);
var pf = PrefabUtility.CreateEmptyPrefab(path);
Debug.Log("Created a prefab:" + AssetDatabase.GetAssetPath(pf));
}
I ll just stick with creating one and removing them. seems unwise to use deprecated code when making something that didnt use it in the first place. Thx for the info