Search Unity

UnityEngine.Object

Discussion in 'Scripting' started by sberlemont, Dec 18, 2010.

  1. sberlemont

    sberlemont

    Joined:
    May 16, 2010
    Posts:
    37
    I would like to save a class on disk using AssetDatabase.CreateAsset() :

    Code (csharp):
    1. public Class MyClass : UnityEngine.Object {
    2. }
    3.  
    4. MyClass A = new MyClass();
    5.  
    6. AssetDatabase.CreateAsset(A, "myClass.asset");
    7.  
    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?
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Sure you want / can / need to inherit from Object, not ScriptableObject or SerializableObject?
     
  3. sberlemont

    sberlemont

    Joined:
    May 16, 2010
    Posts:
    37
    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?
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    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
     
  5. sberlemont

    sberlemont

    Joined:
    May 16, 2010
    Posts:
    37
    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):
    1. public class MyAsset : public ScriptableObject {
    2.  
    3. [INDENT]private int[] data;
    4.  
    5. public MyAsset() {
    6. [INDENT]Debug.Log("MyAsset ctor");[/INDENT]
    7. }
    8.  
    9. public Init(string inputFile) {
    10. [INDENT]
    11. // ...populate "data" from inputFile...[/INDENT]
    12. }[/INDENT]
    13. }
    And in the other hand, I have a script editor that create MyAsset:

    Code (csharp):
    1. public class ImportMyAsset : ScriptableObject {
    2. [INDENT][MenuItem ( "MyAsset/Import MyAsset..." )]
    3. [INDENT]static void MenuImportMyAsset() {
    4.  
    5. // Get the file where the data is stored
    6. string inputFile = EditorUtility.OpenFilePanel("Import MyAsset", "", "bytes");
    7.  
    8. // Instantiate an object
    9. MyAsset asset = (MyAsset) ScriptableObject.CreateInstance("MyAsset");
    10.  
    11. // Populate the asset from inputFile
    12. asset.Init(inputFile);
    13.  
    14. // Create the asset
    15. AssetDatabase.CreateAsset(asset, "Assets/New MyAsset.asset");
    16. [/INDENT]}[/INDENT]
    17. }
    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?
     
    Last edited: Dec 19, 2010
  6. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    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.
     
  7. sberlemont

    sberlemont

    Joined:
    May 16, 2010
    Posts:
    37
    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?
     
  8. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    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):
    1.  
    2. publlic class Manager : MonoBehavior P
    3. public static Manager instance;
    4. public void Awake() {
    5.  if (instance != null) Debug.LogError("ONly one instnace allowed")
    6.  instance = this;
    7. }
    that can then be accessed from other scripts like this:
    Manager.instance.somedata;
     
    Last edited: Dec 20, 2010