わかりやすいUnityゲーム開発解説

【マスタ管理】ScriptableObjectでアイテムなどのバリエーションを増やそう

ころもちゃん

敵や装備みたいな、バリエーションがたくさんあるものは、どうやって作ればいいの??

本記事の内容

・データベースとはなにか?
・データベースScriptableObjectを使おう

同系統のバリエーションを増やすにはScriptableObjectを使おう!

ScriptableObjectを使って、設定値をまとめて管理しよう!

ゲームを作っていると、敵・アイテム・装備・スキルなど、同じような機能を持ったパラメータ違いのオブジェクトが複数必要になることがあります。
ポケモンを例にすると、「モンスターボール」、「スーパーボール」など捕獲率のパラメータ違いのアイテムが出てきますよね。このように同じ系統のオブジェクトを複数管理するのに適したUnityの機能が「ScriptableObject」です。

たとえば、「モンスターボール」・「スーパーボール」・「きずぐすり」・「まんたんのくすり」、というアイテムをゲームに実装するとします。

これらのアイテムには以下のパラメータを持たせるとします。

  • アイテムID(こういったリストを作るときには、IDがあるとなにかと便利)
  • アイテムのアイコン
  • アイテムの種類
  • アイテムの名前
  • アイテムの説明
  • 効果値(例えばモンスターボールなら50%、スーパーボールなら70%、きずぐすりなら20、まんたんのくすりなら999)

すると、以下のような表が出来上がります。

ID

 アイコン画像

 種類

 名前

 説明

 効果値

100

ボール

モンスターボール

低確率で捕まえる

50

101

ボール

スーパーボール

中確率で捕まえる

70

200

回復

きずぐすり

HPを20回復する

20

201

回復

まんたんのくすり

HPを満タンまで回復する

999

これらをUnity内で管理できるのが、ScriptableObjectです。

ScriptableObjectのサンプル

実際にこれらのアイテムをUnity内で使う方法を解説します。

スクリプトファイルを作って、以下サンプルのコードを貼り付けます。

using UnityEngine;

// アイテムの種類を表す列挙型
public enum ItemType
{
    Ball,   // ボール
    Heal    // 回復
}

[System.Serializable]
public class Item
{
    public int id;             // アイテムのID
    public Sprite icon;        // アイテムのアイコン画像
    public ItemType itemType;  // アイテムの種類
    public string itemName;    // アイテムの名前
    [TextArea]
    public string description; // アイテムの説明
    public int effectValue;    // 効果値
}

[CreateAssetMenu(fileName = "ItemList", menuName = "Inventory/ItemList")]
public class ItemList : ScriptableObject
{
    public Item[] items;

    /// <summary>
    /// 指定されたIDのアイテムを返す
    /// </summary>
    /// <param name="id">検索するアイテムのID</param>
    /// <returns>該当するアイテム。見つからなければnull。</returns>
    public Item GetItemById(int id)
    {
        foreach (var item in items)
        {
            if (item.id == id)
            {
                return item;
            }
        }
        Debug.LogWarning($"Item with ID {id} not found.");
        return null;
    }
}

ScriptableObjectは通常のC#のスクリプトとは書き方が違います。
特徴としては、冒頭に[CreateAssetMenu(...)]とあるところです。

これはScriptableObjectを作るためのメニューを設定するというコードです。このコードによって、プロジェクトビューで右クリックすると、ScriptableObjectを生成することができます。

また、ScriptableObjectには、メソッドを入れ込むことができます。
GetItemByIDメソッドでは、IDを渡すとそれに該当するItemのデータを返してくれるメソッドです。

Step1のスクリーンショットにあるメニューからScriptableObjectが作成されると、以下のような青い箱が表示されます。

これが、ScriptableObjectです。ここに設定値を登録します。
先程の例にあるような設定値を登録します。

これらのScriptableObjectが設定できたら、最後にScriptableObjectで設定した値を取得する方法です。
今回はサンプルとして、ScriptableObjectから値を取得し、UIに表示するスクリプトを作ってみます。
新規でスクリプトを作成し、以下のコードを作りました。

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class SampleItemDataSetter : MonoBehaviour
{
    [SerializeField] private ItemList itemList; // ScriptableObjectをアタッチ
    [SerializeField] private Image itemIconImage; // アイコン表示用
    [SerializeField] private int itemId;       // 表示したいアイテムのID
    [SerializeField] private TMP_Text itemNameText;    // アイテム名表示用
    [SerializeField] private TMP_Text itemDescriptionText; // 説明表示用
    [SerializeField] private TMP_Text itemEffectValueText; // 効果値表示用

    private void Start()
    {
        DisplayItemDetails(itemId);
    }

    private void DisplayItemDetails(int id)
    {
        // IDに該当するアイテムを取得
        var item = itemList.GetItemById(id);

        if (item != null)
        {
            itemIconImage.sprite = item.icon;
            itemNameText.text = item.itemName;
            itemDescriptionText.text = item.description;
            itemEffectValueText.text = $"Effect: {item.effectValue}";
        }
    }
}

ヒエラルキーウィンドウに対応するTextMeshPro、Imageオブジェクトを配置します。

親オブジェクトのItemに、先程作成したSampleItemDataSetterをアタッチし、インスペクタから対応する項目をアタッチします。

これで再生してみましょう。以下のようにUIにScriptableObjectで設定した値が表示されていれば成功です。

ScriptableObjectの上手な向き合い方

最後に、個人的にScriptableObjectを作る時の気をつけていることをまとめておきます。

ScriptableObjectの値は更新しないものだけを設定する

ScriptableObjectは基本的に静的なデータを扱うためのものですが、ゲーム中に値が変動するものを扱うのには適していません。レベルごとのパラメータ値など、ゲームプレイ次第で値が変わることが無いようなデータを設定するようにしましょう。

逆に、シーンを跨いでも同じ値でセットしておきたいなどの場合には、ScriptableObjectを使うと整合性の取れたデータを扱うことができるのでオススメです。

ScriptableObjectから欲しいデータを取得するメソッドを入れておく

自作のScriptableObjectは、配列(リスト)形式になることが多いです。
配列(リスト)からデータ取得する場合、取得するためのメソッドをScriptableObject側に仕込んでおくと、設計がキレイになりやすいです。

今回のサンプルだと、以下の部分です。

    private void DisplayItemDetails(int id)
    {
        // IDに該当するアイテムを取得
        var item = itemList.GetItemById(id);

        if (item != null)
        {
            itemIconImage.sprite = item.icon;
            itemNameText.text = item.itemName;
            itemDescriptionText.text = item.description;
            itemEffectValueText.text = $"Effect: {item.effectValue}";
        }
    }

ほかにも、条件に応じてフィルタリングして対応するリストを返すメソッドなど、必要に応じて必要なデータを取得するロジックを仕込んでおくとよいでしょう。

まとめ

ScriptableObjectを使うと、設定値を一律管理できるようになるので、バリエーションを増やすことが容易になります。内容が充実したゲームを作るには必須の機能でしょう。
ぜひ使い方をマスターしてみてください。

この記事がよかったら、ぜひX(@mitakamikata)もフォローしてくださいね。
それでは素敵なゲーム制作ライフを!

ゲームの素材探しに困っていませんか?

ゲームのUI素材探しなら、Free Game UI Assets がオススメです!
完全無料で著作権フリーな、UIのアセット素材がなんと1700以上使い放題!

ぜひ、こちらもチェックしてみてください。