-
Notifications
You must be signed in to change notification settings - Fork 40
FAQ
It's really hard to make sure those features work perfectly with the system since it depends on to catch up the GUIDs of the collectables, ALWAYS try to use the Add New / Deleting by the inspector itself
For most of the cases, you don't need these objects to be fully serialized when using the references on Save Data and other cases, I recommend taking a look into the fsCollectableScriptableObjectConverter
inside the package, this uses FullSerializer to only serialize the necessary data, and rebuild the connection properly when serialize/deserialize the object
Since the CollectionsRegistry is inside the Resources folder, every reference this has to a collection and to all the collectables will be inside the Unity Resources bundle, and if have a lot of references for expensive stuff, this can decrease your startup time significantly, there's 2 things you should keep in mind:
- Use the Automatically Loaded items for items that should be available for the lifetime of your game
2.- If you want to use this for more expensive stuff, let's say all the gameplay prefabs, you can uncheck the automatic initialization of this collection, and register the collection on your loading by using
CollectionsRegistry.Instance.RegisterCollection(Collection);
and removing it when they are not necessary anymore.
You can use the Collection Creating Wizzard by right click on the project panel and going into: Assets/Create/Scriptable Object Collection/New Collection
this will create 3 items and respective folder: YourCollectionName.cs
YourCollectableName.cs
and the Collection Scriptable Object
When your collection it's selected you can Add/Remove items and re-organize their position on the list:
When you add a reference to a Collectable you may choose how you want this to be displayed by adding [CollectionItemEditorOptions]
.
There are two Draw Types for now:
-
DropDown
the default option which displays all the available options in a convenient drop-down, like an enum field -
AsReference
standard Scriptable Object field where you select the asset in a browser
You can generate a static file that will enable you to access any of your collections by code, for doing that, just click on the Generate Static File
on Inspector:
For non automatically loaded items, I suggest using the TryGetAccess static generation type, you can define this on the CollectionRegistry
file, this will provide TryGet methods instead of direct access to the collections itself, I think this helps since those objects can be not loaded in memory, so you are more conscious about it.
Defining a generic Scriptable Object Collection and having a game-specific collection with static access
Let's say that you have a re-usable animation system that uses SOC items for defining Animation Events. The AnimationEventConfig
/ AnimationEventConfigCollection
are defined in the generic Animation System submodule or package in their own assembly, and then your game has an Animation Event Config Collection
asset with game-specific Animation Events defined in it.
How would you set that up? This is a supported use case actually. The nuance lies in the fact that normally you might define the collection type and the static access class in the same assembly, and then have exactly one static access class. Then you can generate the static access as a partial class, and then the syntax for statically accessing an instance becomes something like AnimationEventConfig.NameOfEvent
.
Because in this case the collection and the static access are generated in different assemblies, you cannot make it a partial class because C# doesn't allow partial classes across assemblies. If you would then generate the static access with the same name as the collection or collection item, it will cause a name conflict. If you choose a different name (I personally like using a plural version of the item name in this case) then you can statically access using something like AnimationEventConfigs.NameOfEvent
without any conflicts.
Any addressable asset that has a reference to a scriptableObject
, when is bundled a copy of that scriptable object will be created inside of the bundle, so if you are not doing anything fancy with the scriptableObject
should be fine, but if you are updating references or anything else, I recommend using the indirect reference. When creating a new Collection by the wizard, make sure you let the Generate Indirect Access
toggle on, and when adding references inside the scriptable objects, make sure you use the CollectableIndirectReferece
this only store the GUIDs of the target collectable without the actual reference to the object, so avoiding creating a relationship between items and avoiding bundling then together.
Some scriptable objects that you want to manage may inherit from a Scriptable Object-derived type that you yourself do not manage. Either one from Unity or perhaps from some plugin. This does not stop you from managing those items via a Scriptable Object Collection
. The SOC system internally manages its items via the ISOCItem
interface. ScriptableObjectCollectionItem
in turn implements that interface for an 'out-of-the-box' implementation of SOC functionality.
So if you wish to make a Scriptable Object usable, you need only make your class implement ISOCItem
and then copy the implementation of that interface from ScriptableObjectCollectionItem
. Here's an example of that:
public sealed class SomeCustomScriptableObject : ScriptableObject, ISOCItem
{
#region ISOCItem implementation
[SerializeField, HideInInspector]
private LongGuid guid;
LongGuid ISOCItem.GUID
{
get
{
if (guid.IsValid())
return guid;
((ISOCItem)this).GenerateNewGUID();
return guid;
}
}
[SerializeField, HideInInspector]
private LongGuid collectionGUID;
[NonSerialized] private bool hasCachedCollection;
[NonSerialized] private ScriptableObjectCollection cachedCollection;
public ScriptableObjectCollection Collection
{
get
{
if (!hasCachedCollection)
{
if (collectionGUID.IsValid())
{
cachedCollection = CollectionsRegistry.Instance.GetCollectionByGUID(collectionGUID);
}
else
{
CollectionsRegistry.Instance.TryGetCollectionFromItemType(GetType(), out cachedCollection);
if (cachedCollection != null)
{
collectionGUID = cachedCollection.GUID;
ObjectUtility.SetDirty(this);
}
}
hasCachedCollection = cachedCollection != null;
}
return cachedCollection;
}
}
void ISOCItem.SetCollection(ScriptableObjectCollection collection)
{
cachedCollection = collection;
collectionGUID = cachedCollection.GUID;
ObjectUtility.SetDirty(this);
}
void ISOCItem.GenerateNewGUID()
{
guid = LongGuid.NewGuid();
ObjectUtility.SetDirty(this);
}
}
#endregion ISOCItem implementation
You can now define a collection like so:
[CreateAssetMenu(menuName = "ScriptableObject Collection/Collections/Create SomeCustomScriptableObjectCollection", fileName = "SomeCustomScriptableObjectCollection", order = 0)]
public class SomeCustomScriptableObjectCollection : ScriptableObjectCollection<SomeCustomScriptableObject>
{
}