Search Unity

Losing ScriptableObject reference after editing scripts while playing.

Discussion in 'Scripting' started by HiddenMonk, Mar 30, 2015.

  1. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    I have a ScriptableObject that holds key bindings. I then have a script that loads the ScriptableObject with Resources.Load and stores it into a static variable so that I can easily access the key bindings. All works fine and well except when I am editing my scripts while still in play mode. After I make an edit, the scripts get recompiled and the reference to the key bindings seem to get lost and I start getting nullreference errors. Can someone explain to me why this is happening and how to avoid/fix it?
    The SO_InputDataUse class is attached to a GameObject.

    Here are the scripts
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SO_InputDataUse : MonoBehaviour
    5. {
    6.     string assetPath = "ScriptableObjects/InputDatabase/InputData";
    7.     public static SO_InputData key;
    8.  
    9.     void Awake()
    10.     {
    11.         key = Resources.Load<SO_InputData>(assetPath);
    12.     }
    13. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [System.Serializable]
    5. public class SO_InputData : ScriptableObject
    6. {
    7.     public KeyCode forward;
    8.     public KeyCode left;
    9.     public KeyCode backward;
    10.     public KeyCode right;
    11.     public KeyCode jump;
    12. }

    I noticed that after the scripts recompile while still in play mode, the Awake method does not get recalled. This leads me to believe the static variable lost its reference and is not able to recreate a new. How can this be avoided?
     
    Last edited: Mar 31, 2015
  2. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    I haven't tried what I'm about to suggest, but I'm imagining the problem might be because Unity doesn't serialize static variables. In your case, try making it just public (or private with the attribute [SerializeField])
     
  3. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    I would like it to be static so that I can easily access the key variable.
     
  4. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    Why not just reload it if it's lost its reference?
    Code (csharp):
    1.  
    2. private static SO_InputData _Key;
    3. public static SO_InputData Key {
    4.     get{
    5.         if (_Key == null) _Key = Resources.Load<SO_InputData>(assetPath);
    6.         return _Key;
    7.     }
    8. }
    9.  
     
  5. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    I changed my script to...
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SO_InputDataUse
    5. {
    6.     const string assetPath = "ScriptableObjects/InputDatabase/InputData";
    7.  
    8.     static SO_InputData _key;
    9.     public static SO_InputData key
    10.     {
    11.         get
    12.         {
    13.             if(_key == null) _key = Resources.Load<SO_InputData>(assetPath);
    14.             return _key;
    15.         }
    16.     }
    17. }
    ...and I think it has fixed the problem. I still have other problems to fix though. It seems many things I have are breaking and losing its references (such as any dictionary I have) so I will have to either go through them all, or just lose out on being able to edit while in play mode.

    Anyways, thank you!
    If there is a better way of doing this without needing to do a check every time for null, please let us know =)
     
    Last edited: Mar 31, 2015
  6. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    If you'd like to keep data serialized and have access to key members via static fields, you might try using a singleton pattern.
     
  7. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    I did originally use a singleton, but doing something like SO_InputDataUse.instance.key is annoying compared to InputDataUse.key (even if I make it SO_InputDataUse.i.key its still annoying)