# アイテムを拾う

3D シーンの配置できるコインと鍵を拾って、Timmy が持っているアイテムを追跡しましょう。

## コイン

シーンにコインを一つ作ろう（後ほどプレハブにして、何個も配置できるようにする）。まず、「Coin」の名前で空のオブジェクトを作成する。拾う処理を確認しやしくするため、Timmyの近くに配置してください。

次、「Coin」の子オブジェクトとして、3Dモデルを追加しましょう。Meshes の中にある「coin-gold」を「Coin」の中に挿入し、位置は 0, 0, 0 にしてください。

最後、3Dモデルとの接触を確認できるため、SphereCollider 型の トリガーを追加してください

![image.png](https://class.illogic.games/uploads/images/gallery/2026-05/scaled-1680-/vR9image.png)

<span style="color: rgb(186, 55, 42);">**※注目：3Dモデル coin-gold の位置は「親に対して 0, 0, 0」であることを確認してください。3D空間の中で動かすのは、親の Coin である！**</span>

### アニメーション

コインが浮くアニメーションを作成しましょう。coin-gold を選択し、アニメーションパネルを表示してください。ここで２つの値をアニメーションで更新しましょう：位置と回転

<table border="1" class="align-center" id="bkmrk-%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0-0-60-120-%E4%BD%8D%E7%BD%AE-0%2C-" style="border-collapse: collapse; width: 58.2143%; border-width: 1px;"><colgroup><col style="width: 20.6826%;"></col><col style="width: 23.7531%;"></col><col style="width: 26.0079%;"></col><col style="width: 29.4881%;"></col></colgroup><tbody><tr><td>フレーム</td><td>0</td><td>60</td><td>120</td></tr><tr><td>位置</td><td>0, 1, 0</td><td>0, 0.5, 0</td><td>0, 1, 0</td></tr><tr><td>回転</td><td>0, 0, 0</td><td>0, 180, 0</td><td>0, 360, 0</td></tr></tbody></table>

### タグ

何を拾ったのかを確認したいので、SphereCollider が付いている coin-gold には「Coin」というタグを付けてください

### プレハブ化

最後、親の「Coin」を新しく作った「Prefabs」フォルダーの中に入れ、プレハブ化にしてください

![image.png](https://class.illogic.games/uploads/images/gallery/2026-05/scaled-1680-/wckimage.png)

## インベントリ

つぎ、主人公のインベントリ（アイテム管理クラス）を作成しましょう。このクラスは `OnTriggerEnter` を活用し、タグを確認する。「Coin」だったら、持っているコインの数を増やす。Debug.Log で確認しましょう：

### スクリプト

```c#
using UnityEngine;

// アイテムを管理するインベントリ
public class Inventory : MonoBehaviour
{
    // コインの数
    private int coinCount;

    // トリガーが発動した
    private void OnTriggerEnter(Collider other)
    {
        // コインなの？
        if (other.CompareTag("Coin"))
        {
            coinCount++;
            Debug.Log($"コインの数：{coinCount}");
        }
    }
}
```

このスクリプトをPlayerにアタッチし、実行してみてください。

### アイテム削除

一応、これで正しく数えられることが確認できるが、コインが消えないので、何度も拾うことができてしまう。拾った後に、アイテムをシーンから廃止しましょう。ここの注目ポイントは、**<span style="color: rgb(186, 55, 42);">削除するのはコインの「親」</span>**であること（コライダーは子オブジェクトにあるから）

```c#
// トリガーが発動した
private void OnTriggerEnter(Collider other)
{
    // コインなの？
    if (other.CompareTag("Coin"))
    {
        // コライダー「の」トランスフォーム「の」親「の」ゲームオブジェクト
        Destroy(other.transform.parent.gameObject);

        coinCount++;        
        Debug.Log($"コインの数：{coinCount}");
    }
}
```

いくつかのコインを配置し、確認してみてください。

## 鍵

コインと同じ手順を従い、鍵のプレハブを作成してください。ただし：

- 親オブジェクトの名前：Key
- タグ：Key

にしてください。そして、`Inventory` クラスは：

```c#
using UnityEngine;

// アイテムを管理するインベントリ
public class Inventory : MonoBehaviour
{
    // コインの数
    private int coinCount;

    // 鍵の数
    private int keyCount;

    // トリガーが発動した
    private void OnTriggerEnter(Collider other)
    {
        // コインなの？
        if (other.CompareTag("Coin"))
        {
            // コライダー「の」トランスフォーム「の」親「の」ゲームオブジェクト
            Destroy(other.transform.parent.gameObject);
            coinCount++;
            Debug.Log($"コインの数：{coinCount}");
        }
        
        // 鍵なの
        else if (other.CompareTag("Key"))
        {
            Destroy(other.transform.parent.gameObject);
            keyCount++;
            Debug.Log($"鍵の数：{keyCount}");
        }
    }
}
```

## インベントリの改善：統一処理を一体化

この処理で、すぐ眼立つのは、似たような処理２回現れる

- コインの場合：アイテム削除→アイテムを数える→デバッグ用の表示
- 鍵の場合：アイテム削除→アイテムを数える→デバッグ用の表示

この作り方は大きな問題２つがある：

- 新しいアイテムを増やすのは大変：何度も同じ処理を追加しないといけない
- 処理を直すのも手間がかかる：何か直したい場合、１か所ではなく、アイテム１個ずつ直さないといけない。

できる限りに、統一している処理を一体にすると、ゲームの整備が楽になる！このため、新しい C# のクラス「Dictionary」を紹介

### なんでも指数として使える"配列"「Dictionary」

今まで、２つのコレクションを学んできた：

- 配列：決まった数の要素を入れることができる
- リスト：サイズを決めず、自由に伸びる配列

いずれにしても、それぞれの要素を「指数」でアクセスする形になる。先頭の要素を「0番目」の要素であり、そこから連続に次々の要素をアクセスができる。

```c#
// 配列、またはリストは「指数」でアクセス
int [] numbers = new int[5];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
// など…
```

連続にデータを処理する場合は、配列、またはリストは最適であるが、今回のインベントリのように、連続で整理するよりも、何かの「キーワード」でアクセスしたい。具体的に、それぞれのアイテムの数を、そのアイテムの名前でアクセスしたい。

```c#
// これをやりたい…
items["Coin"] = 10; // コイン10個ある
items["Key"] = 0;   // 鍵がない
```

これがあれば、アイテムごとの変数（`coinCount`, `keyCount`）を別々で作成する必要がない。この特別なコレクションに新しい `"アイテム"`を追加すれば、処理が統一できるようになる。

このコレクションは「ディクショナリー（Dictionary）」といい、リストと同様に、変数を作るのは１つだけで、中には要素を自由に追加ができるが、違いとしては、０から連続にアクセスするではなく、何かの「キー」で要素を探す。

ここで「キー」にできるのは、ほとんどなんでもOK！

- 整数（int）
- 文字列（string）
- 他のオブジェクト（GameObject）
- なんでも良い（比較で等しいかどかを確認できれば）

#### 書式

ディクショナリーの宣言は、以下のようになる：

```c#
Dictionary<キーの型、要素の型> ディクショナリー名;
```

そして、新しいディクショナリーを作るには：

```c#
ディクショナリー名 = new Dictionary<キーの型、要素の型>();
```

例えば、文字列→整数のディクショナリーは

```c#
// 学生の点数
// キー：文字列
// 要素：整数
Dictionary<string, int> studentScore = new Dictionary<string, int>();

// 代入
studentScore["太郎"] = 75;
studentScore["大原"] = 91;

// 読み込む
int score = studentScore["太郎"];
Debug.Log($"太郎さんの点数は{score}");
```

または、列挙→文字列でもOKですし：

```c#
// 武器の列挙
public enum Weapon
{
    Sword,
    Pistol,
    Axe,
    Rock
}

// 各武器の日本語表示 
// キー：武器（列挙）
// 要素：文字列
Dictionary<Weapon, string> weaponName = Dictionary<Weapon, string>();

// 代入
weaponName[Weapon.Sword] = "剣";
weaponName[Weapon.Axe] = "斧";

// 読み込む
int name = weaponName[Weapon.Pistol];
```

### Inventory クラスの改善

では、Dictionary を使用し、処理を一体化しましょう：

```c#
using System.Collections.Generic;
using UnityEngine;

// アイテムを管理するインベントリ
public class Inventory : MonoBehaviour
{
    // アイテムの数（タグ → 数）
    private Dictionary<string, int> itemCount;

    private void Start()
    {
        // ディクショナリーを作成
        itemCount = new Dictionary<string, int>();
        
        // 有効なアイテムとその初期の数
        itemCount["Coin"] = 0;
        itemCount["Key"] = 0;
    }

    // トリガーが発動した
    private void OnTriggerEnter(Collider other)
    {
        // 相手のタグを求める
        string itemTag = other.tag;

        // そのタグあるかないかを確認
        // "ContainsKey" は、ディクショナリーの中に
        // 定めた「キー」があると、「true」を返す
        bool isItem = itemCount.ContainsKey(itemTag);

        // 有効なアイテじゃなければ、何もしない
        if (!isItem)
            return; // 終了

        // コライダー「の」トランスフォーム「の」親「の」ゲームオブジェクト
        Destroy(other.transform.parent.gameObject);
        itemCount[itemTag]++;
        Debug.Log($"{itemTag}の数：{itemCount[itemTag]}");
    }
}
```