1
\$\begingroup\$

I created three Scriptable Objects for my Unity word game:

  1. FeemData - This is to hold information on letters
  2. NeemData - This is to hold information on pronunciation
  3. SuperNeemData - This is to hold #1 and #2 together in a single Scriptable Object.

Here's the C# code for the SuperNeemData SO:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "New SuperNeemData", menuName = "Super Neem Data", order = 51)]

public class SuperNeemData : ScriptableObject
{
    [SerializeField]
    public FeemData actualFeem;

    [SerializeField]
    public NeemData superNeem;

}

So far, so good. But then I created a LevelData, which is meant to hold an arbitrary number of SuperNeemDatas:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "New LevelData", menuName = "Level Data", order = 51)]

public class LevelData : ScriptableObject
{
    [SerializeField]
    public List<SuperNeemData> SuperNeemForThisLevel;

}

When I go to the Inspector allows me to view and change the SuperNeemDatas in there, like this:

enter image description here

This works OK, but it's not the best workflow. In order to create a SuperNeemData, first I have to go into a separate folder and generate a SuperNeemData Scriptable Object and then drag the FeemData into there... and then drag a NeemData into there... and then go back to LevelData and drag the SuperNeemData Scriptable Object into there.

The whole process takes a lot of extra time and clicks. I'm hoping to change things so that I can drag FeemData and NeemData Scriptable Objects directly into the LevelData Scriptable Object.

In short (I think), I would like the LevelData Scriptable Object to have a List of an Array (with two items: first one is a FeemData and second one is a NeemData). Then if I am understanding things correctly, I could drag a FeemData So and a NeemData SO directly into the LevelData SO... a much easier workflow.

Any advice on how to structure a Scriptable Object so that it has a List of an Array of 2 other Scriptable Objects? Thank you!

\$\endgroup\$
1

1 Answer 1

3
\$\begingroup\$

Hmmm, I'm not sure getting the exact behaviour you want is possible. The thing is that Scriptable Objects, like other UnityEngine.Object, are serialized as references. That is, the information that gets serialized is a reference to the SO, rather than the SO itself, and thus the SO needs to already exist somewhere else. That's why we have this whole drag-the-object-into-a-box business, that is how you handle the references.

Now, a potentially really easy option is to make SuperNeemData not be a scriptable object at all, just a plain old C# class. This has some important downsides (there is no way to save instances as assets to share them between scenes, for example), buuut it makes it so that you can create new instances directly in the inspector of your LevelData class. Whether this works well for your project or not, I don't know.

The other, slightly more involved, solution that I can think of is to create a method in your LevelData class (that you could call with a button or something like that) which creates the SuperNeemData instance in your project and adds it to the List. It's still the same workflow, but faster. Trouble is you would need to have a look into creating Custom Editors (although it's way less scary than it sounds, and a good skill to have in general).

You could even combine the two options and have a locally used, serialized, non-SO class to hold the references to both NeemData and FeemData, and then a method that transforms that into a SuperNeemData, instantiates that in your project, and adds the reference to it to your List. But this is my least favourite option, it's kind of messy.

Edit: The idea discussed in the comments:

public class SuperNeemData : ScriptableObject
{
    [SerializeField]
    List<AuxNeem> list;

    [System.Serializable]
    public class AuxNeem{
        [SerializeField]
        public FeemData actualFeem;
    
        [SerializeField]
        public NeemData superNeem;
    }
}
\$\endgroup\$
11
  • \$\begingroup\$ Thanks for the detailed answer!! I could create two separate Lists... one for Feems and one for Neems. And then match them up so that the [0] slot on both Lists gets run together through a Super Neem Prefab... hoping there's a less kludgy way though? \$\endgroup\$
    – kanamekun
    Jul 7 at 8:36
  • \$\begingroup\$ Ah, well, following that same idea you could have the SuperNeem scriptable object, which contains a List of... let's call it AuxNeem, which is a normal c# class marked as System.Serializable that has the references to both Neem and Feem. If you serialze that list, you now have the SuperNeem SO containing the formed pairs, editable through the inspector. \$\endgroup\$
    – PepeOjeda
    Jul 7 at 9:09
  • \$\begingroup\$ That sounds amazing! But beyond my abilities... any advice or pointers would be greatly appreciated!! \$\endgroup\$
    – kanamekun
    Jul 7 at 9:22
  • 1
    \$\begingroup\$ I added an edit with the general shape of how I would implement it. \$\endgroup\$
    – PepeOjeda
    Jul 7 at 9:29
  • \$\begingroup\$ That is absolute perfection, thank you so so much!! I will be using this pattern a lot in my Scriptable Objects in the years to come!!! \$\endgroup\$
    – kanamekun
    Jul 7 at 10:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .