Search Unity

[bug?] Scriptableobject Permanent Class Relation

Discussion in 'Scripting' started by FFaUniHan, Apr 14, 2019.

  1. FFaUniHan

    FFaUniHan

    Joined:
    Feb 26, 2018
    Posts:
    14
    Greeting! I'm in love with ScriptableObject, especially considering how it makes game architecture very clean and singleton-free. But I came across a bug (maybe?)

    I have 3 scripts: a normal class containing data, a ScriptableObject class, and a Monobehavior class

    Code (CSharp):
    1. //Class containing data
    2. [System.Serializable]
    3. public class Data
    4. {
    5.     public float variable_x;
    6.     public float variable_y;
    7. }
    Code (CSharp):
    1. //ScriptableObject class
    2. using UnityEngine;
    3. [CreateAssetMenu(fileName = "Scriptable", menuName = "Test/Scriptable")]
    4. public class Scriptable : ScriptableObject
    5. {
    6.     public Data scriptableData;
    7. }
    Code (CSharp):
    1. //Monobehavior Component Class
    2. using UnityEngine;
    3. public class GameobjectComponent : MonoBehaviour
    4. {
    5.     public Scriptable referenceToScriptableObject;
    6.     public Data componentData;
    7.  
    8.     public void Start()
    9.     {
    10.         componentData = referenceToScriptableObject.scriptableData;
    11.     }
    12. }
    - As usual, I created an instance of ScriptableObject, then fill the variables in the inspector.
    - Then, I create an empty gameobject and attach the GameobjectComponent monobehavior to it.
    - Still in the component, I drag and drop the ScriptableObject into the inspector Scriptable field.
    - Then I run the game.

    The component will get the value of the ScriptableObject class to its own class ONCE in the Start() function. No problem here.

    But then, if we modify the ScriptableObject value, the value in the component also change. This also happens when we modify the monobehavior value, the scriptable value also change!

    So somehow, both Monobehavior and ScriptableObject now shares the same value even without any Update() function to do so. To my knowledge, the value from scriptable SHOULD only be assigned once in Start() function to monobehavior.

    So to undo this problem and break the "connection", I need to change Start() function, so that it assigns the Data class variables one by one. It's still assigning value from ScriptableObject once when the game runs, but the connection doesn't happen.

    Code (CSharp):
    1. //Monobehavior Component Class
    2. using UnityEngine;
    3.  
    4. public class GameobjectComponent : MonoBehaviour
    5. {
    6.     public Scriptable referenceToScriptableObject;
    7.  
    8.     public Data componentData;
    9.  
    10.     public void Start()
    11.     {
    12.         componentData.variable_x = referenceToScriptableObject.scriptableData.variable_x;
    13.         componentData.variable_y = referenceToScriptableObject.scriptableData.variable_y;
    14.     }
    15. }
    Was this a feature or a bug?
     
  2. Shack_Man

    Shack_Man

    Joined:
    Jun 7, 2017
    Posts:
    372
    It's a feature ;-) You are copying the REFERENCE to the class data, the scriptable object and the Gameobject are both pointing to the same place in memory. There is a super simple fix:
    Rename "public class Data" to public struct Data". You should do that anyway when you have a class that only contains data, as a struct is not a reference type, but a value type.
     
    FFaUniHan likes this.
  3. FFaUniHan

    FFaUniHan

    Joined:
    Feb 26, 2018
    Posts:
    14
    Thanks for confirming this. In my case, I have a very complicated system that would be better to use a class since the same data structure is used multiple times. Thank you!