Introduction to Scriptable Objects
Tutorial
·
Beginner
·
+10XP
·
65 mins
·
(402)
Unity Technologies

Scriptable Objects are amazing data containers. They don't need to be attached to a GameObject in a scene. They can be saved as assets in our project. Most often, they are used as assets which are only meant to store data, but can also be used to help serialize objects and can be instantiated in our scenes. We won't cover serialization in depth in this session, but will just touch on the subject and how Scriptable Objects can help us. We will cover not only what Scriptable Objects are, but show some very simple examples using Scriptable Objects.
Languages available:
1. Introduction to Scriptable Objects - February 2016 Live Training
Live Training 16th February 2016 - Introduction to Scriptable Objects
MyScriptableObjectClass
using UnityEngine;
using System.Collections;
[CreateAssetMenu(fileName = "Data", menuName = "Inventory/List", order = 1)]
public class MyScriptableObjectClass : ScriptableObject {
public string objectName = "New MyScriptableObject";
public bool colorIsRandom = false;
public Color thisColor = Color.white;
public Vector3[] spawnPoints;
}
UseMyScriptableObject
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class UseMyScriptableObject : MonoBehaviour {
public MyScriptableObjectClass myScriptableObject;
private List<Light> myLights;
// Use this for initialization
void Start ()
{
myLights = new List<Light>();
foreach (Vector3 spawn in myScriptableObject.spawnPoints)
{
GameObject myLight = new GameObject("Light");
myLight.AddComponent <Light>();
myLight.transform.position = spawn;
myLight.GetComponent<Light>().enabled = false;
if (myScriptableObject.colorIsRandom)
{
myLight.GetComponent<Light>().color = new Color (Random.Range (0.0f, 1.0f), Random.Range (0.0f, 1.0f), Random.Range (0.0f, 1.0f));
}
else
{
myLight.GetComponent<Light>().color = myScriptableObject.thisColor;
}
myLights.Add (myLight.GetComponent<Light>());
}
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown ("Fire1"))
{
foreach (Light light in myLights)
{
light.enabled = !light.enabled;
}
}
if (Input.GetButtonDown("Fire2"))
{
UpdateLights();
}
}
void UpdateLights ()
{
foreach (var myLight in myLights)
{
myLight.color = new Color(Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f));
}
}
}
MakeScriptableObject
using UnityEngine;
using System.Collections;
using UnityEditor;
public class MakeScriptableObject {
[MenuItem("Assets/Create/My Scriptable Object")]
public static void CreateMyAsset()
{
MyScriptableObjectClass asset = ScriptableObject.CreateInstance<MyScriptableObjectClass>();
AssetDatabase.CreateAsset(asset, "Assets/NewScripableObject.asset");
AssetDatabase.SaveAssets();
EditorUtility.FocusProjectWindow();
Selection.activeObject = asset;
}
}
InventoryItem
using UnityEngine;
using System.Collections;
[System.Serializable] // Our Representation of an InventoryItem
public class InventoryItem
{
public string itemName = "New Item"; // What the item will be called in the inventory
public Texture2D itemIcon = null; // What the item will look like in the inventory
public Rigidbody itemObject = null; // Optional slot for a PreFab to instantiate when discarding
public bool isUnique = false; // Optional checkbox to indicate that there should only be one of these items per game
public bool isIndestructible = false; // Optional checkbox to prevent an item from being destroyed by the player (unimplemented)
public bool isQuestItem = false; // Examples of additional information that could be held in InventoryItem
public bool isStackable = false; // Examples of additional information that could be held in InventoryItem
public bool destroyOnUse = false; // Examples of additional information that could be held in InventoryItem
public float encumbranceValue = 0; // Examples of additional information that could be held in InventoryItem !!!
}
InventoryItemList
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class InventoryItemList : ScriptableObject
{
public List<InventoryItem> itemList;
}
InventoryItemEditor
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
public class InventoryItemEditor : EditorWindow {
public InventoryItemList inventoryItemList;
private int viewIndex = 1;
[MenuItem ("Window/Inventory Item Editor %#e")]
static void Init ()
{
EditorWindow.GetWindow (typeof (InventoryItemEditor));
}
void OnEnable () {
if(EditorPrefs.HasKey("ObjectPath"))
{
string objectPath = EditorPrefs.GetString("ObjectPath");
inventoryItemList = AssetDatabase.LoadAssetAtPath (objectPath, typeof(InventoryItemList)) as InventoryItemList;
}
}
void OnGUI () {
GUILayout.BeginHorizontal ();
GUILayout.Label ("Inventory Item Editor", EditorStyles.boldLabel);
if (inventoryItemList != null) {
if (GUILayout.Button("Show Item List"))
{
EditorUtility.FocusProjectWindow();
Selection.activeObject = inventoryItemList;
}
}
if (GUILayout.Button("Open Item List"))
{
OpenItemList();
}
if (GUILayout.Button("New Item List"))
{
EditorUtility.FocusProjectWindow();
Selection.activeObject = inventoryItemList;
}
GUILayout.EndHorizontal ();
if (inventoryItemList == null)
{
GUILayout.BeginHorizontal ();
GUILayout.Space(10);
if (GUILayout.Button("Create New Item List", GUILayout.ExpandWidth(false)))
{
CreateNewItemList();
}
if (GUILayout.Button("Open Existing Item List", GUILayout.ExpandWidth(false)))
{
OpenItemList();
}
GUILayout.EndHorizontal ();
}
GUILayout.Space(20);
if (inventoryItemList != null)
{
GUILayout.BeginHorizontal ();
GUILayout.Space(10);
if (GUILayout.Button("Prev", GUILayout.ExpandWidth(false)))
{
if (viewIndex > 1)
viewIndex --;
}
GUILayout.Space(5);
if (GUILayout.Button("Next", GUILayout.ExpandWidth(false)))
{
if (viewIndex < inventoryItemList.itemList.Count)
{
viewIndex ++;
}
}
GUILayout.Space(60);
if (GUILayout.Button("Add Item", GUILayout.ExpandWidth(false)))
{
AddItem();
}
if (GUILayout.Button("Delete Item", GUILayout.ExpandWidth(false)))
{
DeleteItem(viewIndex - 1);
}
GUILayout.EndHorizontal ();
if (inventoryItemList.itemList == null)
Debug.Log("Inventory is empty");
if (inventoryItemList.itemList.Count > 0)
{
GUILayout.BeginHorizontal ();
viewIndex = Mathf.Clamp (EditorGUILayout.IntField ("Current Item", viewIndex, GUILayout.ExpandWidth(false)), 1, inventoryItemList.itemList.Count);
//Mathf.Clamp (viewIndex, 1, inventoryItemList.itemList.Count);
EditorGUILayout.LabelField ("of " + inventoryItemList.itemList.Count.ToString() + " items", "", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal ();
inventoryItemList.itemList[viewIndex-1].itemName = EditorGUILayout.TextField ("Item Name", inventoryItemList.itemList[viewIndex-1].itemName as string);
inventoryItemList.itemList[viewIndex-1].itemIcon = EditorGUILayout.ObjectField ("Item Icon", inventoryItemList.itemList[viewIndex-1].itemIcon, typeof (Texture2D), false) as Texture2D;
inventoryItemList.itemList[viewIndex-1].itemObject = EditorGUILayout.ObjectField ("Item Object", inventoryItemList.itemList[viewIndex-1].itemObject, typeof (Rigidbody), false) as Rigidbody;
GUILayout.Space(10);
GUILayout.BeginHorizontal ();
inventoryItemList.itemList[viewIndex-1].isUnique = (bool)EditorGUILayout.Toggle("Unique", inventoryItemList.itemList[viewIndex-1].isUnique, GUILayout.ExpandWidth(false));
inventoryItemList.itemList[viewIndex-1].isIndestructible = (bool)EditorGUILayout.Toggle("Indestructable", inventoryItemList.itemList[viewIndex-1].isIndestructible, GUILayout.ExpandWidth(false));
inventoryItemList.itemList[viewIndex-1].isQuestItem = (bool)EditorGUILayout.Toggle("QuestItem", inventoryItemList.itemList[viewIndex-1].isQuestItem, GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal ();
GUILayout.Space(10);
GUILayout.BeginHorizontal ();
inventoryItemList.itemList[viewIndex-1].isStackable = (bool)EditorGUILayout.Toggle("Stackable ", inventoryItemList.itemList[viewIndex-1].isStackable , GUILayout.ExpandWidth(false));
inventoryItemList.itemList[viewIndex-1].destroyOnUse = (bool)EditorGUILayout.Toggle("Destroy On Use", inventoryItemList.itemList[viewIndex-1].destroyOnUse, GUILayout.ExpandWidth(false));
inventoryItemList.itemList[viewIndex-1].encumbranceValue = EditorGUILayout.FloatField("Encumberance", inventoryItemList.itemList[viewIndex-1].encumbranceValue, GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal ();
GUILayout.Space(10);
}
else
{
GUILayout.Label ("This Inventory List is Empty.");
}
}
if (GUI.changed)
{
EditorUtility.SetDirty(inventoryItemList);
}
}
void CreateNewItemList ()
{
// There is no overwrite protection here!
// There is No "Are you sure you want to overwrite your existing object?" if it exists.
// This should probably get a string from the user to create a new name and pass it ...
viewIndex = 1;
inventoryItemList = CreateInventoryItemList.Create();
if (inventoryItemList)
{
inventoryItemList.itemList = new List<InventoryItem>();
string relPath = AssetDatabase.GetAssetPath(inventoryItemList);
EditorPrefs.SetString("ObjectPath", relPath);
}
}
void OpenItemList ()
{
string absPath = EditorUtility.OpenFilePanel ("Select Inventory Item List", "", "");
if (absPath.StartsWith(Application.dataPath))
{
string relPath = absPath.Substring(Application.dataPath.Length - "Assets".Length);
inventoryItemList = AssetDatabase.LoadAssetAtPath (relPath, typeof(InventoryItemList)) as InventoryItemList;
if (inventoryItemList.itemList == null)
inventoryItemList.itemList = new List<InventoryItem>();
if (inventoryItemList) {
EditorPrefs.SetString("ObjectPath", relPath);
}
}
}
void AddItem ()
{
InventoryItem newItem = new InventoryItem();
newItem.itemName = "New Item";
inventoryItemList.itemList.Add (newItem);
viewIndex = inventoryItemList.itemList.Count;
}
void DeleteItem (int index)
{
inventoryItemList.itemList.RemoveAt (index);
}
}
CreateInventoryItemList
using UnityEngine;
using System.Collections;
using UnityEditor;
public class CreateInventoryItemList {
[MenuItem("Assets/Create/Inventory Item List")]
public static InventoryItemList Create()
{
InventoryItemList asset = ScriptableObject.CreateInstance<InventoryItemList>();
AssetDatabase.CreateAsset(asset, "Assets/InventoryItemList.asset");
AssetDatabase.SaveAssets();
return asset;
}
}