Scriptable Object 入門

Tutorial

·

Beginner

·

+10XP

·

65 mins

·

Unity Technologies

Scriptable Object 入門

Scriptable Objects は素晴らしいデータコンテナです。Scriptable Objects は、シーン内のゲームオブジェクトにアタッチする必要がなく、プロジェクトのアセットとして保存することができます。多くの場合、データを保存するためだけのアセットとして使用されますが、オブジェクトをシリアライズするために使用することもでき、シーンの中でインスタンス化することもできます。このセッションではシリアライズについては詳しく説明しませんが、このテーマに触れ、Scriptable Objects がどのように役立つかを説明します。Scriptable Objects とは何かを説明するだけでなく、Scriptable Objects を使った非常に簡単な例をいくつか紹介します。

Languages available:

1. Scriptable Objects 入門 - ライブトレーニング(2016年2月)

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;
    }
}

Complete this tutorial