Scriptable Object in Unity

I’m a quite confused about Scriptable Objects. For example, can I use ‘new’ when I create a Scriptable Object? If I can’t use ‘new’, how can I use it, and how do the code examples I provided below work?

This is my Player script that detects when the player touches the Item.

public class Player : MonoBehaviour
{
    public Inventory inventory;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("Item"))
        {
            int itemId = collision.GetComponent<ItemWorld>().item.id;
            string  itemName = collision.GetComponent<ItemWorld>().item.name;
            int itemAmount  = collision.GetComponent<ItemWorld>().item.amount;
            inventory.AddItem(itemId,itemName,itemAmount);
            Destroy(collision.gameObject);
        }
    }
}

This is the ScriptableObject script that hold Items attributes.

[CreateAssetMenu(fileName = "Item", menuName ="ItemSystem/BasicItem")]
public class Item : ScriptableObject
{
    public int id;
    public string name;
    public int amount;

    public Item(int _id,string _name,int _amount) {

        this.id = _id;
        this.name = _name;
        this.amount = _amount;
    }
}

Here is an inventory script that adds items to a list based on incoming values.

public class Inventory : MonoBehaviour
{
    public List<Item> InventoryList = new List<Item>();

    public void AddItem(int _itemId,string _itemName, int _itemAmount)
    {
        Item newItem = new Item(_itemId,_itemName,_itemAmount);
        InventoryList.Add(newItem);
    }
}

I learned on Internet that I can create Scriptable Objects using CreateInstance, but I didn’t fully understand how to do it.

Scriptable Objects in Unity vs. typical C# objects

The Scriptable Objects in Unity are unique compared to the typical C# objects. They were designed for Unity's ecosystem. The advantage there is, that there is non-dependency on the scene, so they can hold data without having to tie them to a particular scene instance.

Using “new” when creating a Scriptable Object?
You should avoid using new to create instances of Scriptable Objects. Instead of this you should use ScriptableObject.CreateInstance<T>() where T is the type of the Scriptable Object you want to create.

How To: Use CreateInstance
Simple Example on how to use CreateInstance:

Item newItem = ScriptableObject.CreateInstance<Item>();

Then set properties:

newItem.id = _itemId;
newItem.name = _itemName;
newItem.amount = _itemAmount;

How the code example you provided works:
Usually ScriptableObjects don’t have public constructors. So you can initialize them by using methods instead. I would remove the constructor in the Item ScriptableObject. Also instead of creating a new item by using the new keyword, use CreateInstance.

Code Revision

Item Script (ScriptableObject) Code:

[CreateAssetMenu(fileName = "Item", menuName ="ItemSystem/BasicItem")]
public class Item : ScriptableObject
{
    public int id, amount;
    // 'new' keyword was added because 'name' hides a member from parent class
    new public string name;  

    // Constructor removed. Instead we use this method to initialize values.
    public void SetItemDetails(int _id, string _name, int _amount) 
    {
        this.id = _id;
        this.name = _name;
        this.amount = _amount;
    }
}

Inventory Script Code:

public class Inventory : MonoBehaviour
{
    public List<Item> InventoryList = new List<Item>();

    public void AddItem(int _itemId, string _itemName, int _itemAmount)
    {
        Item newItem = ScriptableObject.CreateInstance<Item>();
        newItem.SetItemDetails(_itemId, _itemName, _itemAmount);
        InventoryList.Add(newItem);
    }
}

I hope I could help you to understand ScriptableObjects a bit better. Always mind that ScriptableObjects are not typical C# classes. When you want an instance of one, you will need to go with Unity's provided method. This method is CreateInstance.

Leave a Comment