見出し画像

短編RPG制作(Unity2D)【第26回】メニューの作成その4


インベントリの作成

インベントリに実装したい機能としては、

  • 手に入れたアイテムを表示する

  • アイテムの個数を表示する

  • アイテムを並べ替えできるようにする

  • 持っていないアイテムは表示されないようにする

  • アイテム画面をスクロールできるようにする(おそらく画面サイズが足りないため)

こんな感じです。
調べていると、思ったより複雑なスクリプトだったので頭が痛いです……。
少しずつ理解しながら実装していきます。

全アイテムリストの作成

ゲームのアイテムを管理するための中継地点として、すべてのアイテムを格納するリストを作成します。

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "ItemList", menuName = "ScriptableObjects/ItemList")]
public class ItemList : ScriptableObject
{
    [SerializeField] private List<ItemData> itemList = new List<ItemData>();

    public List<ItemData> GetItemLists()
    {
        return itemList;
    }
}

個々のアイテムを格納するためのリストを、例のごとくScriptableObjectクラスを継承して作成しました。
"List<ItemData> itemList"と変数を定義しました。これは同じデータ型の変数をまとめて扱うことができる変数です。この中に、別途作ったデータをinspectorウィンドウから格納します。

リストにデータを格納

アイテムデータを適当にいくつか作成して、それらをリストに入れておきます。

所持品リストの追加

「PlayerStatus」に、ドロップアイテムを保存するためのリストを追加します。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerStatus : MonoBehaviour
{
    [SerializeField] private Image _image;
    [SerializeField] private int maxHP = 10;
    [SerializeField] private int currentHP;
    [SerializeField] private int upHP = 10;
    [SerializeField] private int level = 1;
    [SerializeField] private int experience = 0;
    [SerializeField] private int needExperience = 100;
    [SerializeField] private int gold = 0;
    [SerializeField] private List<ItemData> itemList = new List<ItemData>();

    private void Start()
    {
        currentHP = maxHP;
    }

    // ダメージ計算・死亡判定
    public void Damage()
    {
        currentHP = Mathf.Clamp(currentHP - 1, 0, maxHP);    
        UpdateBar();

        // 死亡判定
        if (currentHP == 0)
        {
            Destroy(gameObject);
        }
    }

    // HPバーの更新
    private void UpdateBar()
    {
        _image.fillAmount = Mathf.Clamp01((float)currentHP / (float)maxHP);
    }

    // 報酬獲得処理
    public void Result(int Experience, int Gold, ItemData Item)
    {
        experience += Experience;
        gold += Gold;
        Debug.Log(experience);
        LevelUp();
        itemList.Add(Item);
    }

    // レベルアップ処理
    private void LevelUp()
    {
        while (experience >= needExperience)
        {
            level++;
            experience = experience - needExperience;
            maxHP += upHP;
            currentHP += upHP;
            UpdateBar();
        }
    }
}

「ItemData」をまとめるリスト「itemList」を宣言しました。
更に、報酬獲得処理でドロップアイテムを「itemList」に格納します。
Resultメソッドの引数を追加したので、このメソッドを呼び出しているEnemyControllerクラスも書き換えます。
呼び出している場所を探したいとき、VisualStudioだとメソッドから飛べるから便利ですね。

using UnityEngine;
using UnityEngine.UI;

// 敵キャラクターの生成・破棄を管理する
public class EnemyController : MonoBehaviour
{
    // プレイヤーの参照格納用
    [SerializeField] private PlayerAttack _playerAttack;
    [SerializeField] private PlayerStatus _playerStatus;

    // 敵の参照格納用
    private GameObject _enemyObject;
    private EnemyStatus _enemyStatus;

    // 生成可能な敵オブジェクト格納用
    [SerializeField] private GameObject _enemyObjectlist;

    // HPバーのImageコンポーネント格納用
    [SerializeField] private Image _imageMaxHP;
    [SerializeField] private Image _imageCurrentHP;
    public Image ImageCurrentHP
    {
        get { return _imageCurrentHP; } // ゲッターを設定
    }

    private Vector3 position = new (4.0f, -2.4f, 0.0f); // 敵オブジェクト生成位置
    private float interval = 1.0f; // 敵再生成までののインターバル

    private void Start()
    {        
        enemySpawn();
    }

    // EnemyControllerオブジェクトの子要素として、敵オブジェクトを生成
    public void enemySpawn()
    {
        // 敵オブジェクト生成・参照取得
        Instantiate(_enemyObjectlist, position, Quaternion.identity, this.transform);
        _enemyObject = transform.GetChild(0).gameObject;
        _enemyStatus = _enemyObject.GetComponent<EnemyStatus>();

        // HPバーの表示
        _imageMaxHP.enabled = true;
        _imageCurrentHP.enabled = true;

        // 敵オブジェクトをプレイヤーに認識させる
        _playerAttack.GetEnemy();
    }

    // 敵オブジェクトを破棄・再生成
    public void enemyDestroy()
    {
        // 報酬の獲得
        _playerStatus.Result(_enemyStatus.GetDropExperience(), _enemyStatus.GetDropGold(), _enemyStatus.GetDropItem());
        
        // HPバーの非表示
        _imageMaxHP.enabled = false;
        _imageCurrentHP.enabled = false;

        // 敵オブジェクトを破棄し、一定時間後に再生成
        Destroy(_enemyObject);
        Invoke("enemySpawn", interval);
    }
}

メソッド部分の変数を増やしただけです。
敵オブジェクトにドロップアイテムを設定しなくてはいけないので、「EnemyStatus」も変更します。

using UnityEngine;
using UnityEngine.UI;

public class EnemyStatus : MonoBehaviour
{
    [SerializeField] private int maxHP = 3;
    [SerializeField] private int dropExperience = 50;
    [SerializeField] private int dropGold = 10;
    [SerializeField] private ItemData dropItem;
    [SerializeField] private float dropRate = 0.5f;
    public int GetDropExperience()
    {
        return dropExperience;
    }
    public int GetDropGold()
    {
        return dropGold;
    }
    public ItemData GetDropItem()
    {
        if (dropRate > Random.value) // 一定確率でアイテムをドロップ
        {
            return dropItem;
        }
        else
        {
            return null;
        }
    }

    private EnemyController _enemyController;
    private Image _imageCurrentHP;

    private int currentHP;

    private void Start()
    {
        _enemyController = GetComponentInParent<EnemyController>();
        _imageCurrentHP = _enemyController.ImageCurrentHP;
        _imageCurrentHP.fillAmount = 1;
        currentHP = maxHP;
    }
    // ダメージ計算とHP表示の更新
    public void Damage()
    {
        currentHP = Mathf.Clamp(currentHP - 1, 0, maxHP);
        _imageCurrentHP.fillAmount = Mathf.Clamp01((float)currentHP / (float)maxHP);

        // 死亡判定
        if (currentHP == 0)
        {
            _enemyController.enemyDestroy();
        }
    }
}

「dropItem」と「dropRate」を宣言しました。
「dropRate」で、アイテムドロップの確率を決めています。

ゲームの再生

敵キャラクターにInspectorウィンドウからドロップアイテムをセットして、いざ実行!

敵を倒すたびにリストの中身が増える

リストの中身が増えていくのが確認できました。
しかし、確率でドロップがない場合にも「None」で追加されてしまっているので、その部分は条件分岐で対応します。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerStatus : MonoBehaviour
{
    [SerializeField] private Image _image;
    [SerializeField] private int maxHP = 10;
    [SerializeField] private int currentHP;
    [SerializeField] private int upHP = 10;
    [SerializeField] private int level = 1;
    [SerializeField] private int experience = 0;
    [SerializeField] private int needExperience = 100;
    [SerializeField] private int gold = 0;
    [SerializeField] private List<ItemData> itemList = new List<ItemData>();

    private void Start()
    {
        currentHP = maxHP;
    }

    // ダメージ計算・死亡判定
    public void Damage()
    {
        currentHP = Mathf.Clamp(currentHP - 1, 0, maxHP);    
        UpdateBar();

        // 死亡判定
        if (currentHP == 0)
        {
            Destroy(gameObject);
        }
    }

    // HPバーの更新
    private void UpdateBar()
    {
        _image.fillAmount = Mathf.Clamp01((float)currentHP / (float)maxHP);
    }

    // 報酬獲得処理
    public void Result(int Experience, int Gold, ItemData Item)
    {
        experience += Experience;
        gold += Gold;
        Debug.Log(experience);
        LevelUp();
        if (Item != null)
        {
            itemList.Add(Item);
        }        
    }

    // レベルアップ処理
    private void LevelUp()
    {
        while (experience >= needExperience)
        {
            level++;
            experience = experience - needExperience;
            maxHP += upHP;
            currentHP += upHP;
            UpdateBar();
        }
    }
}

まとめ

これで、アイテムをプレイヤーが保持できるようになりました。
現状、同じアイテムを拾ってもリストの別の枠に格納してしまうので、次回はアイテムを重ねて持つことができるようにしたいです。


この記事が気に入ったらサポートをしてみませんか?