【Unity】ScriptableObjectの基本と応用について

今回はScriptableObjectの基本機能の解説と、Editor拡張と合わせた応用事例の紹介をします。

こんにちは、ソーシャルゲーム事業部所属エンジニアのぴーちんです!!宜しくお願いします

この記事はカヤックUnityアドベントカレンダー2016の6日目の記事になります。

ScriptableObjectの基本と応用について

ScriptableObjectは、Unityによってシリアライズされたデータ群をアセットとして保持する為の仕組みです。 Prefabと一見似てる様に思われますが、Prefabの様にシーン上に配置する使い方は出来ません。

詳細は公式のマニュアルを見ると良いでしょう。

ScriptableObjectの作り方

ここでコードを交えて作り方の紹介

ScriptableObjectにしたい場合は、 ScriptableObjectを継承する必要があります。 今回はScriptableObjectにしたいclassと、そのScriptableObjectのinstanceを作成するEditorToolを以下に書いてみました。

using UnityEngine;
using UnityEditor;

public class TestScriptableObject : ScriptableObject
{
    public string imageUrl;

    public Texture2D icon;
}
using UnityEngine;
using UnityEditor;


public class TestScriptableObjectCreater : Editor
{
    [MenuItem ("Test/CreateScriptableObject")]
    static void Create()
    {
        var instance = CreateInstance<TestScriptableObject>();

        AssetDatabase.CreateAsset(instance, "Assets/00TestScriptableObject/TestScriptableObject.asset");
        AssetDatabase.Refresh();
    }
}

UnityのMenuにある Test→CreateScriptableObject を選択すると、Assets/00TestScriptableObject/TestScriptableObject.asset が生成されました。

f:id:pchin:20161206102223p:plain

以上がScriptableObjectを作る方法でした。

Editor拡張と組み合わせる

ScriptableObjectは主にUnityのEditor拡張機能と組み合わせて使う場合が多いです。 例えば、以下の様な場合があります。

  • ツールの設定ファイル
  • マスターデータ

ツールの設定ファイルとしての使用例

今回はFacebook SDK for Unityを参考にして紹介しましょう。

FacebookのAPIを使用するための設定項目をScriptableObjectで設定可能な設計になっています。 SDKなどの様にコードをDLLにまとめるケースが多いと、設定ファイルを外出し出来て、しかもGUIで設定を行えるのは便利ですね。

f:id:pchin:20161206102221p:plain

マスターデータ

ScriptableObjectをモックゲームのマスターデータとして扱う場合もあります。

社内の本番環境での使用例はまだありませんが、小規模なゲームやモックを作る場合での使用はアリだと思います。 以下の様なオススメする理由があります。

  • ScriptableObjectはUnityEngneの内部(C++)で実装されてるので読み込みが早い
  • UnityEditor上でデータをInspectorから編集可能なので、ゲームを実行して確認して修正するサイクルを早く回せる

以下はサウンドのマスターデータを格納してるScriptableObjectの例です。 小規模なゲームプロジェクトで、サウンドに関するマスターデータをScriptableObjectに保持される事例を紹介します。

f:id:pchin:20161206102218p:plain

UnityのシリアライズされたAssetは人間が読みやすいテキスト形式にする事が可能です。

yaml形式ならば、Unity以外の場所でもデータの検証がしやすいので便利ですね!

データの更新があった場合でも、行単位でgitのdiffが出るのでレビューもしやすいです。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 0}
  m_GameObject: {fileID: 0}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: c5a9d5d57f4c8457a9b5d4cbc08c8ccc, type: 3}
  m_Name: sound
  m_EditorClassIdentifier: 
  sheetName: "\u30DE\u30B9\u30BF\u30FC\u30C7\u30FC\u30BF\uFF08\u30E2\u30C3\u30AF\u7528\uFF09"
  worksheetName: sound
  dataArray:
  - id: 1
    category: 1
    soundname: battle_normal01_loop
    filename: battle_normal01_loop.wav
    channel: 0
    minvolume: 40
    maxvolume: 40
    minpitch: 100
    maxpitch: 100
    priority: 0
    limitrepeatms: 0
    loop: 1
    startdelayms: 0

Asset Serializationの設定について

Unityでシリアライズされたアセットは、標準設定だとバイナリ形式で保存されるので人間が読めない事が多いです。 弊社では、基本的にすべてのアセットをyaml形式で保存する設定を有効にしています。

この設定は、 Edit->ProjectSettings->Editor から開けるWindowで行えます。 ここで Asset Serializaton の項目で ForceText を選択すると、人間が読める形式でアセットが保存されます。

f:id:pchin:20161206102215p:plain

この事に関する詳細は、公式マニュアルでも説明されています。

おわりに

如何でしたでしょうか? ScriptableObjectという手段を知ってるだけでも、技術的な問題解決の引き出しが増えるのでご活用ください。

明日はUnityでC#を使うときのヒント集についての記事になります。 担当は権くんになります。 お楽しみに。