I would like to save a class on disk using AssetDatabase.CreateAsset() : Code (csharp): public Class MyClass : UnityEngine.Object { } MyClass A = new MyClass(); AssetDatabase.CreateAsset(A, "myClass.asset"); I receive a System.NullReferenceException on the CreateAsset() call. Debugging my code reveals that both A.hideFlags and A.name properties throw a NullReferenceException. I guess I forgot to set the base class Object properly. What is the best practice to instantiate a class inheriting from Object?
Actually ScriptableObject is fine. Now Unity warns that MyClass must be instantiated using the ScriptableObject.CreateInstance method instead of new MyClass. MyClass doesn't have a default constructor. How to specify a constructor with argument in that case?
ScriptableObject and all descendants (Component - MonoBehaviour) are not meant to be used through new and Unity will fire in if you try to. If thats a problem then keep your class and see if marking it as [System.Serializable()] helps
I still don't get how Unity manages custom assets... My goal is to create a persistent object containing all data global to the game (i.e. it wouldn't make sense to attached the data to a particular GameObject). This asset would be similar to a TerrainData asset. By persistent I mean: the asset should be created only one time, from a custom menu (MyAsset / Import MyAsset...). This action includes reading data from binary file, etc. the data contained in the asset is preserved even though the project is reopened or a new scene is created / deleted etc. the data should be accessible at runtime from any GameObject So in one hand, I have a custom asset MyAsset: Code (csharp): public class MyAsset : public ScriptableObject { [INDENT]private int[] data; public MyAsset() { [INDENT]Debug.Log("MyAsset ctor");[/INDENT] } public Init(string inputFile) { [INDENT] // ...populate "data" from inputFile...[/INDENT] }[/INDENT] } And in the other hand, I have a script editor that create MyAsset: Code (csharp): public class ImportMyAsset : ScriptableObject { [INDENT][MenuItem ( "MyAsset/Import MyAsset..." )] [INDENT]static void MenuImportMyAsset() { // Get the file where the data is stored string inputFile = EditorUtility.OpenFilePanel("Import MyAsset", "", "bytes"); // Instantiate an object MyAsset asset = (MyAsset) ScriptableObject.CreateInstance("MyAsset"); // Populate the asset from inputFile asset.Init(inputFile); // Create the asset AssetDatabase.CreateAsset(asset, "Assets/New MyAsset.asset"); [/INDENT]}[/INDENT] } When I trigger the "import MyAsset..." menu for the very first time, everything looks fine: the Init() function looks fine "New MyAsset.asset" is created on disk "New MyAsset" appears in the Project hierarchy But after that, the default constructor of MyAsset is called a lot of times completely at random or when I: trigger the play button, go back and forth from the "scene" panel to the "game" panel, select or deselect "New MyAsset" randomly too Off course, when the default constructor is called, it erases the original object (containing the data from the Init() function). I really don't understand what is going on. Any idea?
What about using a singleton that inherits from System.Object, not from any Unity classes? That's how a lot of people handle 'managers', including me.
Even though I create a singleton independent from any Unity classes, The singleton is somehow reset as soon as I push the play button. I guess that no variable instantiated in the editor are accessible when the game is running, unless they are stored on disk as an asset and read back at runtime. Can someone confirm that?
or saved in a Scene. . You probably want to write a custom Editor script. If you need this to happen independent of the Editor, then you will need to use PlayerPrefs or write your own I/O to XML or similar. That creates or changes a prefab ( That prefab should create a faux-Singleton that is used to access the data. Code (csharp): publlic class Manager : MonoBehavior P public static Manager instance; public void Awake() { if (instance != null) Debug.LogError("ONly one instnace allowed") instance = this; } that can then be accessed from other scripts like this: Manager.instance.somedata;