Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Find ScriptableObject at runtime

Discussion in 'Scripting' started by dhenion65, May 9, 2020.

  1. dhenion65

    dhenion65

    Joined:
    Dec 17, 2019
    Posts:
    21
    I have a ScriptableOject asset that I use to hold general parameters for the scene:

    Code (csharp):
    1. [CreateAssetMenu]
    2. public class GlobalParameters : ScriptableObject
    3. {
    4.     [Header("Player")]
    5.     public GameObject Player;
    6. ...
    7.     [Header("Global game parameters")]
    8.     public int BulletsPoolSize;
    9. ...
    10.     [Header("Player parameters")]
    11.     public float MaxGrabDistance;
    12. ...
    13. }
    I can select the GlobalParameters asset and set the values in the inspector.

    Then on any object in its MonoBehavior I can declare
    Code (csharp):
    1. public GlobalParameters  GlobalParams;
    and drag the GlobalParameters asset in to that field and it works fine. I never make any call in code to instantiate it or anything like that, it just magically works. :)

    However, I'd like to make that reference at runtime - but I can't find a way for a script to find the GlobalParameters scriptable object and set a variable to it.

    This does not work:
    Code (csharp):
    1. GlobalParameters GlobalParams = FindObjectOfType<GlobalParameters>();
    Does dragging it in to a public field in the inspector create a magic instantiate of it somewhere? I'm unclear how that works.
    If I don't add it anywhere in the inspector - do I need to do my own instantiate?

    I ran the code at the bottom of this thread: https://answers.unity.com/questions/1326406/finding-scriptableobject-file-in-gameplay.html

    which basically uses
    Code (csharp):
    1. UnityEngine.Object[] findedAssets = Resources.FindObjectsOfTypeAll(typeof (ScriptableObject));
    to find things, and it does show up in the list of what is found, but can't figure out how to assign it to a variable.

    Tried this - but won't compile:
    Code (csharp):
    1. foreach (var item in findedAssets)
    2.         {
    3.             if (item.name == "GlobalParametersAsset")
    4.             {
    5.                 if (item.GetType() == typeof(ScriptableObject))
    6.                 {
    7.                     GlobalParameters GlobalParams = item;  // Syntax error: Cannot implicitly convert type...
    8.                 }
    9.                  
    10.             }
    11. }
    Any help greatly appreciated!
     
  2. Dextozz

    Dextozz

    Joined:
    Apr 8, 2018
    Posts:
    488
    It won't compile because you have to explicitly cast your item into a GlobalParameter
    Code (CSharp):
    1. GlobalParameters GlobalParams = (GlobalParameters)item
    On line 5 you are checking to see if your item is a scriptable object. Which it has to be since you are only finding the assets of type "ScriptableObject", therefore, that line is useless. You can go ahead and delete it.

    Also, don't use GetType() == typeof(Class) to compare types. Use the "is" keyword:
    item is ScriptableObject


    Also, use String.Compare() == 0 to see if 2 strings match. It's better for performance compared to ==. It won't affect your performance in any meaningful way, but it's more readable and it can't hurt to use it since it's the proper way of comparing strings.

    If this doesn't help, post your new code, and tell us why. We'll go from there.
     
  3. dhenion65

    dhenion65

    Joined:
    Dec 17, 2019
    Posts:
    21
    Thanks for the info Dextozz - hopefully will be able to try this tomorrow, but from what you've said I'm fairly certain what you suggest will work and will definitely use the optimization ideas. This would only get run once, so not too worried on performance, but want to code everything I can as well as possible.

    PS: Yea I knew line 5 was a waste, but I thought if maybe the compiler was super super smart it would see that that assignment should be ok because the types have to match :)
     
  4. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,685
    FYI, note that using Resources.... will only find scriptableobejcts located in a Resources folder. UNLESS, the object has been previously selected and initialised in the editor (or runtime)

    P.S. WIth the asset in any Resources folder in the project, this simplified method will also work:

    Code (CSharp):
    1. var globalParametersAssets = Resources.FindObjectsOfTypeAll(typeof(GlobalParameters));
    2. if (globalParametersAssets.Length > 0)
    3. {
    4.         return globalParametersAssets[0] as GlobalParameters ;
    5. }