【Unity】インベントリのアイテムを合成して新しいアイテムを作る

投稿者: | 2021-02-04

ドラッグアンドロップでアイテムを合成して新しいアイテムにしてみました。

まず、取得アイテムの情報を持つための、ScriptableObjectを継承したクラスに、合体できるかどうか、合体情報の配列のフィールドとゲットメソッドを追加しました。

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


[Serializable]
[CreateAssetMenu(fileName = "Item", menuName = "CreateItem")]
public class Item : ScriptableObject
{
    [SerializeField] string itemName; // アイテムの名前
    [SerializeField] Sprite icon; // アイテムの画像
    [SerializeField] string information; // アイテムの情報
    [SerializeField] bool isWeapon; // 武器かどうか
    [SerializeField] bool isCombinable; // 合体できるかどうか
    [SerializeField] Combinable[] combinable; // 合体情報の配列
    [SerializeField] GameObject prefab; // アイテムのプレハブ

    public string GetItemName()
    {
        return itemName;
    }

    public Sprite GetIcon()
    {
        return icon;
    }

    public string GetInformation()
    {
        return information;
    }

    public bool GetIsWeapon()
    {
        return isWeapon;
    }

    public bool GetIsCombinable()
    {
        return isCombinable;
    }

    public Combinable[] GetCombinable()
    {
        return combinable;
    }

    public GameObject GetPrefab()
    {
        return prefab;
    }

    // 対象のアイテム名から、合体してできるアイテムを検索
    public Item GetCombinableInto(string withItem)
    {
        foreach (var comb in GetCombinable())
        {
            if (withItem == comb.GetWithItem())
            {
                // 見つかった時
                return ItemManager.GetInstance().GetItem(comb.GetIntoItem());
            }
        }

        // 見つからなかった時
        return null;
    }

}

// 合体できる対象と作られるアイテムの名前を持つクラス
[Serializable]
public class Combinable
{
    [SerializeField] string withItem; // 対象のアイテムの名前
    [SerializeField] string intoItem; // 合体してできるアイテムの名前

    public string GetWithItem()
    {
        return withItem;
    }

    public string GetIntoItem()
    {
        return intoItem;
    }
}

対象のアイテム名を渡すと、合体してできるアイテムのアイテム情報が返るメソッドも作りました。

配列には、対象のアイテムと合体してできるアイテムの名前を持つためのクラスのオブジェクトを入れます。Serializable属性を付けているので、インスペクタで設定できます。

ドラッグアンドロップしたときに、合成可能のチェックが入っているときだけ配列を検索するためにチェックを入れました。また、Sizeを1にして1つ目の要素を設定し、黄色い箱がドロップされた時に、オレンジの箱ができるようにしました。

個別のアイテム情報に設定すると、両方向の合成ができるようにしたいときに面倒ですが、検索時間が短くなると思って今回はこうしてみました。

ドラッグアンドドロップでアイテムの順番を並び替えるときに、ドロップ先のアイテムが合成可能なときは、配列を検索して、合体してできるアイテム情報を取得します。ドラッグしていたアイテム名が配列になければ、アイテムの順番を入れ替えます。

// アイテム画像をドラッグ中に他のアイテム画像の上でクリックを放した時
else if (Input.GetMouseButtonUp(0) && isDragging)
{
    // 掴んでいない状態にする
    isDragging = false;

    // 合体可能なとき
    if (ItemManager.GetInstance().GetItem(goods.GetItemName()).GetIsCombinable())
    {   

        // 合体してできるアイテム情報を取得
        Item item = ItemManager.GetInstance().GetItem(goods.GetItemName()).GetCombinableInto(currentImage.GetItemName());

        // 見つからない時
        if (item == null)
        {
            SwapIndex(goods);

        }
        // 見つかった時
        else
        {
            // アイテムを拾うための情報とメソッドを含むオブジェクトを作る
            Obtainable obt = new Obtainable(item.GetItemName());

            // 取得メソッドを呼ぶと、合体してできるアイテムのインスタンスがインベントリに入る
            obt.Obtain(Instantiate(item.GetPrefab(), transform.position, Quaternion.identity), goods.transform.GetSiblingIndex());

            // 掴んでいたアイテムを削除
            ThrowAway(currentImage);

            // ドロップ先のアイテムを削除
            ThrowAway(goods);

            // 透明画像を非表示にする
            emptyImage.gameObject.SetActive(false);
        }
    }
    // 合体可能でないとき
    else
    {
        SwapIndex(goods);
    }
}

// ---
// 並び順を入れ替える
void SwapIndex(Goods goods)
{
    // 元の親の子に戻す
    currentImage.transform.parent = previousParent;

    // レイに当たるようにする
    currentImage.SetRaycastTarget(true);

    // 順番を入れ替える
    currentImage.transform.SetSiblingIndex(goods.transform.GetSiblingIndex());
    goods.transform.SetSiblingIndex(index);

    // 空にする
    currentImage = null;

    // 透明画像を非アクティブにする
    emptyImage.gameObject.SetActive(false);
}

合成してできるアイテムを取得するときは、アイテムを拾うときに使うデータと処理を定義したクラスのインスタンスを作って、取得メソッドを呼びます。

普段はこのオブジェクトを、拾えるアイテムのクラスに持たせて、拾う時に使っていますが、上のようにも使えるように、アイテム名をコンストラクタで設定できるようにしました。

また、新しく作られるアイテムのインベントリでの表示順を指定できるように、取得メソッドに既定値のある引数を追加しました。

using UnityEngine;
using System;

[Serializable]
public class Obtainable
{
    [SerializeField] string itemName;
    GameObject gameObject;

    // コンストラクタ
    public Obtainable(string itemName)
    {
        this.itemName = itemName;
    }

    // 取得メソッド
    internal void Obtain(GameObject item, int index = -1)
    {

        this.gameObject = item;       
        Inventory.GetInstance().Obtain(this, index);
        
    }

    internal string GetItemName()
    {
        return itemName;
    }

    internal GameObject GetGameObject()
    {
        return gameObject;
    }
}

取得メソッドでは、引数に取得したいアイテムのゲームオブジェクトも渡します。アイテムを合成するときは、合成してできるアイテムのプレハブをスクリプタブルオブジェクトから得て、それをインスタンス化して渡します。

第2引数には、Transform.GetSiblingIndexメソッドを使って、ドロップ先のアイテム画像の表示順を渡しています。インベントリの取得メソッドでTransform.SetSiblingIndexメソッドを使って、新しくできたアイテムの表示順を設定します。

そして、掴んでいたアイテムとドロップ先のアイテムを両方削除します。これでアイテムを合成して新しいアイテムを作れました。

合成できないときは順番を入れ替えて、合成できるときは新しいアイテムと置き換わります。

コメントを残す

メールアドレスが公開されることはありません。