【Unity】ScriptableObjectの作り方・使い方

ScriptableObjectの作り方・使い方 ゲーム制作メモ
スポンサーリンク

最近、今までUnityでよく分かっていなかったScriptableObjectを使う機会があり使い方などを学びました。今回はそのScriptableObjectについて、備忘録を兼ねて特徴や作り方・使い方を書いていきます。

ScriptableObjectとは?

それではまず、そもそもScriptableObjectとは何なのか?という話をします。

ScriptableObjectは、基本的にゲーム中に変化しない値を登録しておくのに使うファイルのようなものです。例えば、敵の最大HPやアイテムの得点などはゲーム中に変化することがあまりないですよね?ScriptableObjectはそういったデータを格納しておき、必要な時に読み込んで使うのに便利です。

ScriptableObjectを使うメリット

それでScriptableObjectを使うメリットは次の3つがあります。

  1. メモリを節約できる
  2. パラメータをインスペクター上で簡単に管理できる
  3. 簡単に作ったり使ったりできる

メモリを節約できる

まずScriptableObjectを使うメリットとして一番大きいのがメモリの節約になる、ということだと思います。

これはどういうことかというと…例えば次のような敵キャラクターのプレハブがあるとしましょう。

スライム(プレハブ)
最大HP 100
攻撃力 10

そしてこのスライムのインスタンスを作るとすると、当然パラメータは次のようになります。

スライム(インスタンス)
最大HP 100
攻撃力 10

当たり前ですが「スライム(インスタンス)」のパラメータは元のプレハブと同じですね。ところが両者は全く同じパラメータではありますが、プレハブとインスタンスのパラメータは別々に扱われるため、インスタンスを作った分だけメモリを食ってしまうのです(下図)。

ScriptableObjectを使わずにインスタンス化したときの例

そこでScriptableObjectが役立ちます。ScriptableObjectを使えば共通の値を必要な時だけ読み込んで使えるので、余分なパラメータを作る必要がなくなってメモリを節約できるというわけです。

ScriptableObjectを使った場合の例

パラメータをインスペクター上で簡単に管理できる

2つ目のメリットは、ScriptableObjectはインスペクター上で簡単に値を変更したり管理したりできる点です。

一つ目のメリットのように、単にデータを外部に切り分けるというとJSONなどが思い浮かびますが、例えばJSONの場合はUnity用のファイルではないのでインスペクターから直接変更することはできません。しかしScriptableObjectを使えば、下の画像のようにインスペクターにフォームが表示されるので直接パラメータの値を変更することができます。

ScriptableObjectのパラメータの表示例

簡単に作ったり使ったりできる

3つ目のメリットは、ScriptableObjectは簡単に作ったり使ったりできるということです。具体的にどのように作ったり使ったりするかは↓で説明していきますね。

ScriptableObjectの作り方

それではScriptableObjectの具体的な作り方を見ていきましょう。手順は次の通りです。

  1. ScriptableObjectクラスを継承したクラスを作る
  2. プロジェクトビューからScriptableObjectファイルを作成する

手順1:ScriptableObjectクラスを継承したクラスを作る

まず、ScriptableObjectを作るためにはScriptableObjectクラスを継承したクラスを作成し、必要なパラメータをそのクラスに書いておく必要があります。具体的には次のようなコードになります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class EnemyStatusData : ScriptableObject
{

  public List<EnemyStatus> enemyStatusList = new List<EnemyStatus>();

}

[System.Serializable]
public class EnemyStatus
{

  [SerializeField]
  string name = "";
  [SerializeField]
  int maxHP = 1;
  [SerializeField]
  float defaultSpeed = 0;
  [SerializeField]
  int defaultPower = 0;
  [SerializeField]
  bool enableSperArmor = false;
  [SerializeField]
  float superArmorActiveTime = 0;
  [SerializeField]
  int score = 0;
  [SerializeField]
  GameObject dropItem;
  [SerializeField]
  GameObject deadEffect;

  public string Name
  {
    get
    {
      return name;
    }
  }

  public int MaxHp
  {
    get
    {
      return maxHP;
    }
  }

  public float DefaultSpeed
  {
    get
    {
      return defaultSpeed;
    }
  }

  public int DefaultPower
  {
    get
    {
      return defaultPower;
    }
  }

  public bool EnableSuperArmor
  {
    get
    {
      return enableSperArmor;
    }
  }

  public float SuperArmorActiveTime
  {
    get
    {
      return superArmorActiveTime;
    }
  }

  public int Score
  {
    get
    {
      return score;
    }
  }

  public GameObject DropItem
  {
    get
    {
      return dropItem;
    }
  }

  public GameObject DeadEffect
  {
    get
    {
      return deadEffect;
    }
  }

}

ここでは「EnemyStatusData」と「EnemyStatus」という2つのクラスを作りました。実際のパラメータはEnemyStatusクラスに登録し、EnemyStatusDataクラスでScriptableObjectをインスペクタで表示したときに下の図のように敵のデータを一覧表示できるようにしてあります(画像再掲)。

ScriptableObjectのパラメータの表示例

また、EnemySatusDataクラスに「CreateAssetsMenu」属性を付与することで、プロジェクトビューで右クリックメニューからファイルを作成できるようにしてあります。


※なお実際のパラメータを登録する方のクラスに「System.Serializable」属性をつけ忘れないようにしてください(インスペクタに表示されなくなってしまうので)。

手順2:ScriptableObjectファイルを作成する

スクリプトを用意出来たら、あとはファイルを作るだけです。プロジェクトビューの何もないところで右クリックすると「EnemyStatusData」ファイルを作成するメニューが出るようになるので、「Resources」フォルダの中にScriptableObjectファイルを作っておきましょう(※別のフォルダの中ではダメです)。

ScriptableObjectの使い方

最後にScriptableObjectの使い方についてですが、Resources.LoadでScriptableObjectファイルを読み込んで、それを変数に格納しておくだけです。

protected override void Start()
  {
    enemyStatusData = Resources.Load<EnemyStatusData>("EnemyStatusData");
    enemyStatus = enemyStatusData.enemyStatusList[enemyId];
  }

ここまでできればenemyStatus.○○でパラメータの値にアクセスできるので、あとは好きなところで呼び出せばOKです。