Skip to main content

アイテムを拾う

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

コイン

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

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

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

image.png

※注目:3Dモデル coin-gold の位置は「親に対して 0, 0, 0」であることを確認してください。3D空間の中で動かすのは、親の Coin である!

アニメーション

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

フレーム 0 60 120 位置 0, 1, 0 0, 0.5, 0 0, 1, 0 回転 0, 0, 0 0, 180, 0 0, 360, 0

タグ

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

プレハブ化

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

image.png

インベントリ

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

スクリプト

using UnityEngine;

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

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

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

アイテム削除

一応、これで正しく数えられることが確認できるが、コインが消えないので、何度も拾うことができてしまう。拾った後に、アイテムをシーンから廃止しましょう。ここの注目ポイントは、削除するのはコインの「親」であること(コライダーは子オブジェクトにあるから)

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

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

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

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

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

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

    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}");
            }
        }
    }

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

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

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

      この作り方は大きな問題2つがある:

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

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

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

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

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

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

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

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

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

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

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

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

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

            書式

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

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

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

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

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

            // 学生の点数
            // キー:文字列
            // 要素:整数
            Dictionary<string, int> studentScore = new Dictionary<string, int>();
            
            // 代入
            studentScore["太郎"] = 75;
            studentScore["大原"] = 91;
            
            // 読み込む
            int score = studentScore["太郎"];
            Debug.Log($"太郎さんの点数は{score}");

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

            // 
            // キー:文字列
            // 要素:整数
            Dictionary<string, int> studentScore = new Dictionary<string, int>();
            
            // 代入
            studentScore["太郎"] = 75;
            studentScore["大原"] = 91;
            
            // 読み込む
            int score = studentScore["太郎"];
            Debug.Log($"太郎さんの点数は{score}");