C#スキル別、Inventory(インベントリ)持ち物システム

2023年5月19日

持ち物の仕組みを作り込みたいと思った場合、自分のプログラムスキルによって理解できる範囲が変わります
出来合いのアセットを活用するとしても、仕組みを理解していることでカスタムもできますので一度はコードの仕組みを学習しておきましょう

前提条件

Unityの基本的なチュートリアルは進めることがで着ること

C#は、まだ初めて

ゲーム上で使えるケース

何かが衝突したことがわかればいい場合
たとえば、当たり判定で敵やアイテムを消したい場合など

サンプルシーン

オブジェクト同士を衝突させるために次の条件を満たすようにします

  • 両方のオブジェクトにコライダーをアタッチ
  • どちらかのオブジェクトにRigidbodyをアタッチ
  • コライダーのisTriggerをon
  • コライダーがアタッチされてりるオブジェクトにスクリプトをアタッチ(スクリプトにはOntriggerEnterイベントを記述)

全体のオブジェクト配置とコンポーネントのアタッチ

コライダー

スクリプト

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("何か当たりました");
    }
}

実行結果

実行後、シーンウィンドウでプレイヤーをつまんで(マウスでドラッグ)、ボールに近づけます

コンソールに何か当たりましたと表示されます

C#は変数と算術演算子、代入演算子まで習得

ゲーム上で使えるケース

幾つ取得したかの情報を保持したい場合
アイテムを取るとポイント(スコア)をアップさせたい場合

サンプルシーン

上記と同じです

スクリプト

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private int counter;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        counter++;
        Debug.Log(counter + "回、何か当たりました");
    }
}

実行結果

上記ビデオと同じようにプレイヤーをりんごに接触させて、離してを繰り返します

次の結果は3回繰り返した場合

1回、何か当たりました
2回、何か当たりました
3回、何か当たりました

C#は条件式まで習得

ゲーム上で使えるケース

目的の数の取得がなされた場合
特定の数のアイテムを取得すると条件を達成(ゴール)

サンプルシーン

上記と同じです

スクリプト

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private int counter;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        counter++;
        Debug.Log(counter + "回、何か当たりました");

        if (counter == 3)
        {
            Debug.Log("3個揃いました");
        }
    }
}

実行結果

上記ビデオと同じようにプレイヤーをりんごに接触させて、離してを繰り返します

次の結果は3回繰り返した場合

1回、何か当たりました
2回、何か当たりました
3回、何か当たりました
3個揃いました

C#はコレクション(List)まで習得(1)

ゲーム上で使えるケース

行動の履歴(アイテムの取得履歴)を保持したい

サンプルシーン

上記と同じです

スクリプト

using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private List<string> items = new List<string>();

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("何か当たりました");

        items.Add(collision.name);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.L))
        {
            for (int i = 0; i < items.Count; i++)
            {
                Debug.Log(items[i]);
            }

            Debug.Log("アイテムの個数は、" + items.Count + "個です");
        }
    }
}

実行結果

上記ビデオと同じようにプレイヤーをりんごに接触させて、離してを繰り返します

次の結果は3回繰り返したあと、ゲームウィンドウをクリックして(そうしないとゲーム画面での入力にならない)、Lキーを押します

何か当たりました
何か当たりました
何か当たりました
アイテムの個数は、3個です

C#はコレクション(List)まで習得(2)

ゲーム上で使えるケース

複数のアイテムがあった場合、アイテムごとの取得数を保持したい

サンプルシーン

上記にみかんを追加します
これが複数(2つ目)のアイテムがあった場合に相当します

スクリプト

using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private List<string> items = new List<string>();

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("何か当たりました");

        items.Add(collision.name);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.L))
        {
            int appleCount = 0;
            int orangeCount = 0;

            for (int i = 0; i < items.Count; i++)
            {
                if (items[i] == "Apple")
                {
                    appleCount++;
                }
                else if (items[i] == "Orange")
                {
                    orangeCount++;
                }
            }

            Debug.Log("りんごの個数は、" + appleCount + "個です");
            Debug.Log("みかんの個数は、" + orangeCount + "個です");
        }
    }
}

実行結果

プレイヤーをりんごに1回、みかんに2回接触させて、離してを繰り返します

ゲームウィンドウをクリックして(そうしないとゲーム画面での入力にならない)、Lキーを押します

何か当たりました
何か当たりました
何か当たりました
りんごの個数は、1個です
みかんの個数は、2個です

C#はLINQまで習得(Countメソッド)

ゲーム上で使えるケース

複数のアイテムがあった場合、アイテムごとの取得数を保持したい
Listの場合のコードを簡略化したい

サンプルシーン

上記と同じです

スクリプト

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private List<string> items = new List<string>();

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("何か当たりました");

        items.Add(collision.name);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.L))
        {
            int appleCount = items.Count(name => name == "Apple");
            int orangeCount = items.Count(name => name == "Orange");

            Debug.Log("りんごの個数は、" + appleCount + "個です");
            Debug.Log("みかんの個数は、" + orangeCount + "個です");
        }
    }
}

実行結果

上記と同じ操作で同じ結果になります

何か当たりました
何か当たりました
何か当たりました
りんごの個数は、1個です
みかんの個数は、2個です

C#はクラスとオブジェクトを習得
C#はLINQまで習得(Where,Selectメソッド)

ゲーム上で使えるケース

複数のアイテムがあった場合、得点が違うアイテムの個別の取得数と得点を保持したい
Listの場合のコードを簡略化したい

サンプルシーン

りんごとみかんのオブジェクトにアイテムのスクリプトを追加して、それぞれの得点を設定します

スクリプト

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private List<Item> items = new List<Item>();

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("何か当たりました");

        items.Add(collision.GetComponent<Item>());
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.L))
        {
            int appleCount = items.Count(item => item.name == "Apple");
            int orangeCount = items.Count(item => item.name == "Orange");

            int applePoint = items.Where(item => item.name == "Apple").Sum(item => item.Point);
            int orangePoint = items.Where(item => item.name == "Orange").Sum(item => item.Point);

            Debug.Log("りんごの個数は、" + appleCount + "個です。ポイントは、" + applePoint + "です");
            Debug.Log("みかんの個数は、" + orangeCount + "個です。ポイントは、" + orangePoint + "です");
        }
    }
}
using UnityEngine;

public class Item : MonoBehaviour
{
    [HideInInspector]
    public string Name;
    public int Point;

    private void Awake()
    {
        Name = gameObject.name;
    }
}

実行結果

上記と同じ操作で、それぞれのアイテムの種類で分類された情報が保持されているのがわかります

何か当たりました
何か当たりました
何か当たりました
りんごの個数は、1個です。ポイントは、1です
みかんの個数は、2個です。ポイントは、20です

C#はインターフェースまで習得

ゲーム上で使えるケース

継承ではなく、特定の振る舞いをもったグループとしてまとめたい場合
サンプルでは、収集できるものグループとして登録するイメージ

サンプルシーン

りんごとみかんのオブジェクトにAudioSourceコンポーネントを追加します
更新したItemスクリプトのgetSoundに取得した時の音を、AudioSourceにAudio Sourceコンポーネントをアタッチします

スクリプト

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private List<Item> items = new List<Item>();

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.L))
        {
            // Name プロパティの値で重複しない要素だけを抽出する
            var distinctItems = items
                .GroupBy(item => item.Name)
                .Select(group => group.First())
                .ToList();

            foreach (var distinctItem in distinctItems)
            {
                Debug.Log(distinctItem.Name
                    + "の個数は、"
                    + items.Count(item => item.Name == distinctItem.Name)
                    + "個です。ポイントは、"
                    + items.Where(item => item.Name == distinctItem.Name).Sum(item => distinctItem.Point)
                    + "です");
            }
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("何か当たりました");

        items.Add(collision.GetComponent<Item>());

        if (collision.TryGetComponent(out ICollectable collectgableObject))
        {
            collectgableObject.PlayGetSound();
        }
    }

}
using UnityEngine;

public interface ICollectable
{
    AudioClip getSound { get; set; }

    void PlayGetSound();
}
using UnityEngine;

public class Item : MonoBehaviour, ICollectable
{
    public string Name;
    public int Point;

    [field: SerializeField]
    public AudioClip getSound { get; set; }

    [SerializeField]
    AudioSource AudioSource;

    public void PlayGetSound()
    {
        AudioSource.PlayClipAtPoint(getSound, transform.position);
    }
}

実行結果

上記と同じ操作で、それぞれのアイテムの種類で分類された情報が保持されているのがわかります
アイテムを取得した時、登録した音源が再生されます

何か当たりました
何か当たりました
何か当たりました
りんごの個数は、1個です。ポイントは、1です
みかんの個数は、2個です。ポイントは、20です

C#,Unity

Posted by hidepon