【Unity入門】持ち物リストをプレイヤーに持たせる ― プレイヤーごとのインベントリ
前回の記事「アイテムを拾って持ち物に表示する最小コード」では、持ち物のメモ帳をゲーム全体に1冊だけ置く形(static)で作りました。動かすまでは最短ですが、「持ち物は誰のもの?」を表せないという弱点があります。
この記事では、持ち物リストをプレイヤー自身に持たせる形に作り替えます。プレイヤーが2人になっても、敵や宝箱に持ち物を持たせても、そのまま使える作りです。
この記事で作るもの
- 前回と同じ動き(木や石に触れると消えて、持ち物画面に「木 ×3」のように並ぶ)
- ただし、持ち物リストはプレイヤーのオブジェクトに付いている
- 持ち主が増えても、持ち物が混ざらない
前回との違い

| 前回(static のメモ帳) | 今回(プレイヤーが持つ) | |
|---|---|---|
| 持ち物リストの場所 | ゲーム全体に1冊 | 持ち主ごとに1つ |
| 追加の書き方 | OwnedItemsData.Instance.Add(type) | inventory.Add(type) |
| 持ち主が2人いると | 持ち物が混ざる | 別々に持てる |
| 拾える相手の判定 | Player タグ | 持ち物リストを持っているか |
変えるのは、スクリプトの中のほんの数か所です。「誰の持ち物か」が、コードの形ではっきり表れるようになります。
全体の流れ
役割は前回と同じ「拾う」「覚える」「表示する」です。変わるのは、「覚える」の置き場所だけです。

| 役割 | スクリプト | やること |
|---|---|---|
| 覚える | Inventory | 持ち主に付けて、何を何個持っているかを覚える |
| 拾う | Item | 触れた相手の Inventory に足して、自分は消える |
| 表示する | ItemsDialog / ItemButton | 指定された Inventory を読んで、マスに並べる |
用意しておくもの
- 前回の記事で作ったプロジェクト(Item、ItemButton、ItemsDialog、シーンの配置まで済んだもの)
- プレイヤーに
CharacterControllerが付いていること
前回の OwnedItemsData.cs は、この記事の最後で削除します。先に4つのスクリプトを書き換えてから消すと、途中で赤いエラーが出ずに進められます。
Step 1:持ち物リストをプレイヤーに付ける(Inventory)
Inventory.cs というスクリプトを新しく作ります。前回の OwnedItemsData とほとんど同じ中身ですが、ゲームオブジェクトに付けられる形(MonoBehaviour)になっています。
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
// 持ち物のリスト(種類と個数)
public List<OwnedItem> OwnedItems { get; } = new List<OwnedItem>();
// アイテムを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; }
}
}
前回との違いは3つです。
public static OwnedItemsData Instanceがなくなりました。「ゲームに1冊」ではなく、付けたオブジェクトごとに1つになりますprivateのコンストラクタがなくなりました。MonoBehaviour は Unity が作るので、自分でnewしませんMonoBehaviourを継承したので、プレイヤーに「Add Component」で付けられます
※ 持ち主に付けるスクリプトなので、名前は PlayerInventory ではなく Inventory にしました。あとで敵や宝箱に付けても、名前が合わなくなりません。
Step 2:拾う側を書き換える(Item)
Item.cs の OnTriggerEnter を書き換えます。
using UnityEngine;
public class Item : MonoBehaviour
{
// アイテムの種類
public enum ItemType
{
Wood,
Stone
}
[SerializeField] private ItemType type;
// 何かが触れたら、持ち物リストを持っている相手だけが拾える
private void OnTriggerEnter(Collider other)
{
if (!other.TryGetComponent(out Inventory inventory))
{
return;
}
// 触れた相手の持ち物に追加して、地面のアイテムは消す
inventory.Add(type);
Destroy(gameObject);
}
}
TryGetComponentは、触れた相手にInventoryが付いていれば取り出し、付いていなければfalseを返します- 前回の
CompareTag("Player")は要らなくなりました。「Player という名前のタグ」ではなく、「持ち物を持てる相手かどうか」で判断できるからです - 追加先が
OwnedItemsData.Instanceから、触れた相手のinventoryに変わりました。これが、持ち主ごとに持ち物が分かれるいちばんのポイントです
※ Inventory は、Collider と同じオブジェクトに付けてください。Collider が子オブジェクトにあるときは、TryGetComponent を GetComponentInParent<Inventory>() に変えると、親に付いた Inventory を探せます。
Step 3:1マスぶんの表示を直す(ItemButton)
ItemButton.cs で変えるのは、型の名前1か所だけです。
// 変更前
public void SetItem(OwnedItemsData.OwnedItem ownedItem)
// 変更後
public void SetItem(Inventory.OwnedItem ownedItem)
残りの中身(画像と個数を表示する処理)は、前回のままで動きます。
Step 4:持ち物画面に「誰の持ち物を見るか」を教える(ItemsDialog)
ItemsDialog.cs には、どの Inventory を表示するかを持たせます。前回は OwnedItemsData.Instance に直接アクセスしていましたが、今回は Inspector で渡してもらいます。
using UnityEngine;
public class ItemsDialog : MonoBehaviour
{
// 誰の持ち物を表示するか(Inspectorで入れる)
[SerializeField] private Inventory inventory;
// 持ち物画面のマス(Inspectorで全部入れる)
[SerializeField] private ItemButton[] itemButtons;
// 持ち物画面の表示/非表示を切り替える
public void Toggle()
{
gameObject.SetActive(!gameObject.activeSelf);
if (gameObject.activeSelf)
{
Refresh();
}
}
// 全マスを、指定された Inventory の内容で更新する
private void Refresh()
{
var ownedItems = inventory.OwnedItems;
for (int i = 0; i < itemButtons.Length; i++)
{
if (i < ownedItems.Count)
{
// i番目の持ち物があれば表示する
itemButtons[i].SetItem(ownedItems[i]);
}
else
{
// なければ空にする
itemButtons[i].SetItem(null);
}
}
}
}
変わったのは、次の2か所だけです。
[SerializeField] private Inventory inventory;を追加しましたRefreshの中で、OwnedItemsData.Instance.OwnedItemsをinventory.OwnedItemsに変えました
これで持ち物画面は、「渡された持ち主の持ち物」を表示する作りになります。持ち主を差し替えるだけで、別の人の持ち物画面にもなります。
Step 5:シーンに配置してつなぐ
- プレイヤーに付ける:Hierarchy でプレイヤーを選び、Inspector の「Add Component」から
Inventoryを追加します - 持ち物画面とつなぐ:
ItemsDialogを選び、Inspector のInventoryの欄に、プレイヤーをドラッグして入れます(ItemsDialogが非アクティブでも、Hierarchy から選べば設定できます) - 古いスクリプトを消す:ここまでできたら、前回の
OwnedItemsData.csを削除します。4つのスクリプトからの参照がなくなっているので、エラーは出ません
アイテムのシーン配置(Cube に Item、Is Trigger オン)と、持ち物ボタンの On Click は、前回のままで大丈夫です。



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

ここまでは前回と同じ動きです。見た目は変わらず、中身だけが「プレイヤーが持つ」形に変わりました。
もう1人の持ち主で試してみよう
持ち主ごとに持ち物が分かれることを、実際に確かめてみましょう。ここでは、元のプレイヤーを Player1、新しく置く Cube を Player2 と呼びます。
- Cube を1つ置き、
RigidbodyとInventoryを付けます(名前は「Player2」にします) - 再生して、Scene ビューで Player2 をアイテムに触れさせます。アイテムが消えます
- プレイヤーを動かさずに「持ち物」ボタンを押します(いまは Player1 の持ち物が表示されます)。Player1 の持ち物は増えていません
- 再生を止めて、
ItemsDialogのInventoryの欄を、Player2 に差し替えます - もう一度、Player2 にアイテムを拾わせてから「持ち物」ボタンを押します。今度は Player2 の持ち物が表示され、Player2 が拾った分だけが並びます
前回の static のメモ帳だと、誰が拾っても同じメモ帳に書かれていました。今回は、拾った本人の Inventory にだけ書き込まれます。
うまくいかないときは
- 拾えない:アイテムの Is Trigger がオンか、触れる側に
Inventoryが付いているかを確認します。前回と違って、Player タグは関係なくなっています - 持ち物画面を開くとエラーが出る:
ItemsDialogのInventoryの欄が空になっていないかを確認します - プレイヤーをゲーム中に生成している:Inspector でドラッグできないので、生成したあとにコードで探して渡します。たとえば
ItemsDialogに次のように書きます
private void Start()
{
inventory = FindFirstObjectByType<Inventory>();
}
([SerializeField] を付けたままなので、Inspector で入れた場合は上書きされる点に注意してください。生成型の場合だけ使います)
なぜ「持ち主が持つ」形が使われるのか
- 持ち主が増えても、そのまま使える:プレイヤー、敵、宝箱、ショップの店主に、同じ
Inventoryを付けるだけです - 「誰の」がコードに現れる:
inventory.Add(type)と書くと、どの持ち物に足しているかが読めば分かります - 複数プレイヤーやオンラインに広げやすい:持ち物が持ち主ごとに独立しているので、同期やセーブの単位も「持ち主ごと」にそろえられます
一方で、持ち主が1人だけの小さなゲームなら、前回の static の形でも十分です。「持ち主が増える可能性があるか」が、どちらを選ぶかの目安になります。
ここまでで省いたこと
前回に引き続き、動かすことを優先して次のものは省きました。次に進むときの課題として、気になるものから試してみてください。
- セーブ:
Inventoryの中身(種類と個数)を保存・読み込みする仕組み - アイテムの種類を ScriptableObject にする:
enumではなく、アセットとして作ると、コードを触らずにアイテムを増やせます - 持ち物が変わったら画面を更新する(イベント):画面を開き直さなくても、拾った瞬間に更新できます
- データを普通のクラスに分ける:
Inventoryの中身を MonoBehaviour でないクラスに移すと、セーブやテストがしやすくなります - オンライン対戦:持ち物の追加はサーバー側で行い、結果を各プレイヤーに同期する形にします
「なぜデータと画面を分けるのか」という考え方は、【Unity入門】アイテム所持の仕組みを作ろうで解説しています。あわせて読むと、この記事の作りの理由がよりつかめます。












ディスカッション
コメント一覧
まだ、コメントがありません