#scriptable objects

1 messages · Page 1 of 1 (latest)

hushed sable
#

making a thread

#

so, first, about the lifecycle of scriptable objects

#

ScriptableObject lets you define new kinds of assets.

#

that's why you usually have the [CreateAssetMenu] attribute on their declarations

#

for example...

#
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Localization;

public abstract class ConfigItem : Identifiable, IDescribable
{
    [field : SerializeField]
    public LocalizedString Label { get; private set; } = new("Config Names", "");
    [field : SerializeField]
    public LocalizedString Description { get; private set; } = new("Config Descriptions", "");
 
    public ConfigCategory category;
}
#

wait this isn't an example lmao

#

this is an abstract class, so it can't be created

#
[CreateAssetMenu(fileName = "New Float Config Item", menuName = "Configs/Float Config Item"]
public class FloatConfigItem : ConfigItem
{
  ...
}
#

So, I have created several FloatConfigItem assets.

#

Just like any other kind of asset -- prefabs, materials, scripts -- I can reference them elsewhere

leaden scarab
#

okay

#

and if i have 2 gameobjects in different scenes i cant acces these?

hushed sable
#

to be pedantic: if you have two components attached to game objects in two different scenes, both of those components can reference the same ScriptableObject asset

#

That's fine.

#

If you reference an asset from anywhere in a scene, the asset will be loaded when the scene loads.

#

in the situation you're describing, it'll also work like you expect

#

you'll be referencing the same object in both scenes

#

Once the object loads, it sticks around until you unload every scene that uses the asset.

#

So let's do a practical example

#
public class FloatHolder : ScriptableObject {
  public float myFloat;
}
#

Say you have a reference to this in both Scene A and Scene B

#

Your component in Scene A does this:

#
holder.myFloat = 123;
#

Then you load Scene B.

#

The component in Scene B will see a value of 123 in holder.myFloat

#

because it's the exact same object

leaden scarab
#

oh okay

#

i understand

#

thank you so much

hushed sable
#

The "gotcha" is when you don't have a reference in Scene B

#

Scene A -> Scene B -> Scene A

#

when scene B loads, the object unloads

#

when scene A loads, the object loads again

#

and now the value is gone!

#

it's back to whatever the asset originally contained

#

If you log the instance ID of the object, you'll see that it changes

#

now, back to your question about dictionaries

#

I got around this problem by just making sure that the objects are never allowed to unload.

#

They can only unload when:

  • no scene is using the Unity object
  • you've lost every reference to the C# object
#

so, if you load a bunch of scriptable objects and stick them in a list, those objects will survive for as long as the list does

#

now, if that list was on a component in a scene, it would die when the scene unloaded

#

but if that list is stored in a static field, it will live forever

#

you'll always have a reference to the object, so it will never be allowed to unload

hushed sable
leaden scarab
#

thank you again

hushed sable
#

np!

#

so what kind of data are you trying to store here?

leaden scarab
#

i only need to store some prefabs that i want to acces from some scripts bc i dont want to have too many objects in every script.

#

i was worried that the file content will be deeted once i load another scene

#

but i understand now

#

what you meant when you said that the file will load again

#

thank you so much for guiding me through this!

hushed sable
#

Oh! Okay, so you aren't storing mutable data in there in the first place 😅

#

ha, well it's good to know anyhow. you're welcome!

#

I mostly use SOs for immutable data like that

#

also, here's a neat trick

#
using UnityEngine;

public abstract class SingletonSO<T> : ScriptableObject where T : SingletonSO<T>
{
    private static T _instance;
    public static T Instance 
    {
        get
        {
            if (_instance == null)
            {
                _instance = Resources.Load<T>("SingletonSO" + "/" + typeof(T).Name);
            }

            return _instance;
        }
    }
}