Search Unity

Possible scriptable object bug or feature

Discussion in 'General Discussion' started by qidrokun, Sep 9, 2021.

  1. qidrokun

    qidrokun

    Joined:
    Nov 29, 2019
    Posts:
    13
    Hey,

    I was using pretty basic inheritance by utilizing scriptable objects to be able to store some data of my inventory system. And i noticed that it seemed to throw an error about the presets every time i inherited them from the parent object. (the associated script cannot be loaded. please fix all compiler errors and assign a valid script)

    I dug around and found many answers like the script had different name as the class definition and such, but what worked for me was to drop the abstract class definition of c# from the front of the parent class that inherits from the ScriptableObject. This is very weird behaviour for me as I've been taught that the abstract is exactly meant to be indicative of a baseclass that others inherit from and not something you can use to create actual instances of.

    Could someone shed light to this odd behaviour for me, I assume it's just something unity doesn't utilize in the code similarly as basic c# or something?

    Best regards,
    qidrokun
     
  2. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,573
    "abstract" is not indicative, it is a strict rule.

    Placing abstract keyword on a class means that user CANNOT create instances of the class and not that they shouldn't do that. Not the same thing.

    Additionally, unity does not use dogmatic C#, C# is a scripting language in it, so things being done in "proper C# fashion" is not necessarily a good idea in unity.

    Generally in many cases in unity inheritance wouldn't be used much (aside from inheriting from scriptable object/mono behavior) and you wouldn't be using polymorphic behavior much either.

    So it would be a better idea to post some code examples along with errors you're receiving.
     
    Ryiah likes this.
  3. qidrokun

    qidrokun

    Joined:
    Nov 29, 2019
    Posts:
    13
    I agree, but basically i used abstract to indicate the class to be sort of blueprint for all derivative classes, but if it is sort of blocking some features and that messes with unity i can accept it, I dont have code to show for it as after 6 hours of debug i just wanted to die. But basically it was something akin to this.

    public abstract Person : ScriptableObject()
    {
    string name;
    int age;
    }

    Warrior: : Person()
    {
    //Warrior parameters
    }

    Banker : Person()
    {
    //Banker parameters
    }

    So when i designed the idea i was going to have a template for Person which would contain all parameters shared by the specific entities, the biggest issue was the abstract type which caused all the generated class types to lose their reference to the script according to unity. When i would test the different types they were fine until I'd restart unity
    and try to replay the project and all the created objects were not working as intended, once i removed abstract from the front all returned back to the peaceful life before (Unity was very bad at indicating this bug, and just threw a script is missing error at the templates inspector).

    Anyways it might be worth treading lot more careful at the c# specific inheritance stuff after this experience. :p
     
  4. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,573
    That's not what abstract does.

    "abstract" means "by my royal decree, all attempts to make an instance of this class must cause compile error and prevent the program from being built". It is not indication, it is enforcement.

    In your example, there's zero reason to make Person abstract because it would basically mean that in your world only Bankers and Warriors are allowed to exist. I somehow doubt that this is what you had in mind.

    Abstract is usually used to provide base class with blank virtual methods. For example:
    Code (csharp):
    1.  
    2. [RequireComponent(typeof(UnityEngine.UI.Text)]
    3. public abstract class DataDisplayBase: MonoBehavior{
    4.      UnityEngine.UI.Text text = null;
    5.      void Start(){
    6.         text = GetComponent<UnityEngine.UI.Text>();
    7.      }
    8.  
    9.      public abstract string getDisplayString();
    10.  
    11.      void Update(){
    12.         if (text)
    13.            text.text = getDisplayString();
    14.      }
    15. }
    16.  
    Then you do.
    Code (csharp):
    1.  
    2. public class HelloDisplay: DataDisplayBase{
    3.     public override string getDisplayString(){
    4.         return "Hello";
    5.     }
    6. }
    7.  
    And in case of unity you can also do your person/banker thing without inheritance.
    Code (csharp):
    1.  
    2. public class Banker{
    3.     public Person personData;
    4. }
    5.  
    This would allow multiple different Bankers and Warriors to use same basic parameter block.

    Then comes a question - what are you going to do if a person is both banker and warrior. C# does not allow multiple inheritance. Or what are you going to do if a banker should turn into a warrior.

    That moves us close to database design, in all honesty, but it is still something worth pondering.
    ----
    One the most common novice programming errors is overuse of inheritance.

    The decide that a Cat should inherit from Mammal, Mammal from Animal, animal from Actor, actor from Object and Object from Thing. Then they waste ton of time making beautiful class hierarchies except that making hierarchies beautiful does not improve the program behavior in any way.

    So it is a good idea to keep in mind, that a class, if exists, should be doing something, and also think about how can you get rid of hierarchies completely.

    And then you can do this:
    Everything is a SceneObject. Nothing inherits from SceneObject. A Cat is a SceneObject that has a Mesh in shape of the cat, has a Skeleton used by that mesh, an Animator that drives the skeleton, and Behavior that drives both Thing and Animator. It can also play Sounds attached to it and has Collider.that prevents it from falling through the world.

    No hierarchies or very shallow hierarchies.(2-3 levels deep)

    No hierarchies.
     
  5. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,192
    You shouldn't have any issues with making an abstract Scriptable Object and then deriving other classes from it. I've done this before without having any issues. Copy and paste (in code tags) your abstract class and the code for a child class if you would like some help debugging what is going on.