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
.
Check out the manual for Scriptable Objects.