【Unity入門】アイテムを拾って持ち物に表示する最小コード

広告

「アイテムを拾って、持ち物画面に並べたい」。でも、全部のコードを見ると難しそう…。そんな方のために、この記事では動かすために必要な最小限のコードだけを使います。

保存やアニメーションなどは、思い切って省きました。考え方や、省いた部分の説明は、こちらの記事で解説しています。まずはこの記事で動かしてみましょう。

この記事で作るもの

  • 木や石に触れると、アイテムが消える
  • メニューのボタンを押すと、持ち物画面が開く
  • 拾ったアイテムが、絵と個数つきでマスに並ぶ(例:木 ×3)

全体の流れ

作るスクリプトは4つです。役割は「拾う」「覚える」「表示する」の3つに分かれます。

ワールドのアイテム、データのメモ帳、画面の3つの役割と、書き込みと読み取りの向きを示した図
アイテムを拾うと「メモ帳」に書かれ、画面は「メモ帳」を読んで表示する
役割スクリプトやること
覚えるOwnedItemsData何を何個持っているかのメモ帳
拾うItem触れたらメモ帳に足して、自分は消える
表示するItemsDialog / ItemButtonメモ帳を読んで、マスに並べる

用意しておくもの

  • Unityのプロジェクト(3Dのシーンで、地面とプレイヤーがいるもの)
  • プレイヤーに、Player タグを付け、CharacterController を付けておく
  • アイテムの絵(木と石の画像を2枚。なければ、四角い画像でも大丈夫です)

Step 1:持ち物のメモ帳を作る(OwnedItemsData)

まず、「何を何個持っているか」を覚えるメモ帳です。OwnedItemsData.cs という名前で、スクリプトを作ります。

using System.Collections.Generic;

public class OwnedItemsData
{
    // どこからでも使える、1冊だけのメモ帳
    public static OwnedItemsData Instance { get; } = new OwnedItemsData();

    // 持ち物のリスト(種類と個数)
    public List<OwnedItem> OwnedItems { get; } = new List<OwnedItem>();

    // 外部からnewできないようにする
    private OwnedItemsData()
    {
    }

    // アイテムを1個追加する
    public void Add(Item.ItemType type)
    {
        // もう持っている種類なら、個数を1つ増やして終わる
        foreach (var item in OwnedItems)
        {
            if (item.Type == type)
            {
                item.Number++;
                return;
            }
        }

        // 見つからなかった=初めて拾った種類なので、新しい行を作る
        var newItem = new OwnedItem(type);
        newItem.Number = 1;
        OwnedItems.Add(newItem);
    }

    // アイテム1種類ぶんの「種類と個数」
    public class OwnedItem
    {
        public OwnedItem(Item.ItemType type)
        {
            Type = type;
        }

        public Item.ItemType Type { get; }

        public int Number { get; set; }
    }
}
  • Instance:ゲームの中に1冊だけあるメモ帳です。どこからでも OwnedItemsData.Instance と書けば使えます
  • OwnedItems:持ち物のリストです。1行に「種類」と「個数」が入ります
  • Add:もう持っている種類なら個数を1つ増やし、初めての種類なら新しい行を作ります

※ { get; } は「読み取り専用」という意味です。外から勝手に差し替えられないようにしています。

Step 2:拾えるアイテムを作る(Item)

次に、地面に置くアイテムです。Item.cs を作ります。

using UnityEngine;

public class Item : MonoBehaviour
{
    // アイテムの種類
    public enum ItemType
    {
        Wood,
        Stone
    }

    [SerializeField] private ItemType type;

    // プレイヤーが触れたら拾う
    private void OnTriggerEnter(Collider other)
    {
        if (!other.CompareTag("Player"))
        {
            return;
        }

        // メモ帳に追加して、地面のアイテムは消す
        OwnedItemsData.Instance.Add(type);
        Destroy(gameObject);
    }
}
  • ItemType:アイテムの種類です。木と石の2つにしました
  • OnTriggerEnter:何かが触れたときに呼ばれます。Player タグのものだけを相手にします
  • 触れたらメモ帳に Add して、Destroy で自分を消します

※ この仕組みが動くには、アイテムの Collider の Is Trigger をオンにしておく必要があります。

Step 3:1マスぶんの表示を作る(ItemButton)

持ち物画面の、マス1つぶんです。ItemButton.cs を作ります。

using UnityEngine;
using UnityEngine.UI;

public class ItemButton : MonoBehaviour
{
    [SerializeField] private Image image;
    [SerializeField] private Text number;
    [SerializeField] private Sprite woodSprite;
    [SerializeField] private Sprite stoneSprite;

    // このマスに持ち物を表示する(空のマスはnullを渡す)
    public void SetItem(OwnedItemsData.OwnedItem ownedItem)
    {
        if (ownedItem == null)
        {
            image.gameObject.SetActive(false);
            number.gameObject.SetActive(false);
            return;
        }

        image.gameObject.SetActive(true);
        number.gameObject.SetActive(true);
        image.sprite = GetSprite(ownedItem.Type);
        number.text = ownedItem.Number.ToString();
    }

    // アイテムの種類に合う画像を返す
    private Sprite GetSprite(Item.ItemType type)
    {
        if (type == Item.ItemType.Wood)
        {
            return woodSprite;
        }

        return stoneSprite;
    }
}
  • SetItem:持ち物を渡すと、絵と個数を表示します。null を渡すと、空のマスとして隠します
  • GetSprite:アイテムの種類に合う絵を返します

Step 4:持ち物画面を作る(ItemsDialog)

最後に、マスをまとめる持ち物画面です。ItemsDialog.cs を作ります。

using UnityEngine;

public class ItemsDialog : MonoBehaviour
{
    // 持ち物画面のマス(Inspectorで全部入れる)
    [SerializeField] private ItemButton[] itemButtons;

    // 持ち物画面の表示/非表示を切り替える
    public void Toggle()
    {
        gameObject.SetActive(!gameObject.activeSelf);

        if (gameObject.activeSelf)
        {
            Refresh();
        }
    }

    // 全マスを、メモ帳の内容で更新する
    private void Refresh()
    {
        var ownedItems = OwnedItemsData.Instance.OwnedItems;

        for (int i = 0; i < itemButtons.Length; i++)
        {
            if (i < ownedItems.Count)
            {
                // i番目の持ち物があれば表示する
                itemButtons[i].SetItem(ownedItems[i]);
            }
            else
            {
                // なければ空にする
                itemButtons[i].SetItem(null);
            }
        }
    }
}
  • Toggle:画面を開いたり閉じたりします。開くときに、中身を更新します
  • Refresh:メモ帳を上から順に読んで、各マスに割り当てます。持ち物の数より後ろのマスは、空にします

Step 5:シーンに配置してつなぐ

スクリプトができたら、Unityのエディターで配置します。

  1. アイテム:Cube などを置いて、Item を付けます。Type を「Wood」にします。Box Collider の Is Trigger をオンにします。石も同じように作り、Type を「Stone」にします
  2. 1マス:Canvas の中に、Panel を作って ItemsDialog と名前をつけます。その子に、Image(背景)を1つ作って、さらにその子に Image(アイテムの絵)と Text(個数)を作ります。この背景に ItemButton を付けて、Inspector の Image と Number、木と石の絵を、それぞれドラッグして入れます
  3. マスを15個にする:作ったマスを、複製して15個にします。Panel に Grid Layout Group を付けると、きれいに並びます
  4. つなぐ:ItemsDialog の Inspector で、Item Buttons の欄に、15個のマスを全部入れます。(Inspector の右上の鍵アイコンでロックしてから、15個を選んで、欄にドラッグすると、まとめて入ります)
  5. 開くボタン:Canvas に、「持ち物」ボタンを作ります。Button の On Click に ItemsDialog を入れて、関数に Toggle を選びます
  6. 最初は非表示:ItemsDialog の Panel を、Hierarchy で非アクティブにしておきます

動かしてみよう

  1. ゲームを再生します
  2. プレイヤーを動かして、木に触れます。木が消えます
  3. 「持ち物」ボタンを押します。「木 ×1」と表示されます
  4. もう1個拾ってからもう一度開くと、「木 ×2」になります

うまくいかないときは

  • 拾えない:アイテムの Is Trigger がオンか、プレイヤーに Player タグが付いているかを確認します
  • 画面が開かない:ボタンの On Click に、ItemsDialog と Toggle が入っているかを確認します
  • エラーが出る:ItemsDialog の Item Buttons と、ItemButton の Image・Number・絵が、空になっていないかを確認します
  • 絵や個数が出ない:マスの Text は、UnityEngine.UI の Text(Legacy)を使っています。TextMeshPro の Text は入りません

ここまでで省いたこと

この記事では、動かすことを優先して、次のものを省きました。

  • セーブ(ゲームを閉じても持ち物が残る仕組み)
  • アイテムが、ぽんと弾んで出てくるアニメーション
  • 敵を倒したときのドロップ
  • アイテムを使う処理

これらを追加していく方法や、なぜデータと画面を分けるのかという考え方は、【Unity入門】アイテム所持の仕組みを作ろうで解説しています。ぜひ続けて読んでみてください。

訪問数 1 回, 今日の訪問数 1回

広告

C#

Posted by hidepon