Unity

【脱出ゲーム制作10】アイテム合成機能の作成

アイテムの合成機能の作成

拡大表示しているアイテムに別のアイテムを使用し、新しいアイテムを生成させます。

赤いタイルを拡大表示し、その状態で青いタイルを選択します。そのまま画面の赤いタイルをクリックすると合成され、新しく紫のタイルが生成されるといった仕組みです。

①赤いタイルを選択し、拡大表示
②青いタイルを選択
③拡大している赤いタイルをクリックし合成
④紫タイルが生成

新規アイテムの作成

合成用に新しくアイテムを作成します。
今回は合成の仕組みをわかりやすくするために3つの色のついたタイルを作成し使用します。

ゲームのボリュームを増やすためにも新規アイテムの追加は必要なので、手順の確認のためにも繰り返し行えるようにしましょう。

Tileオブジェクトの作成

Hierarchyに3DObject→Cubeで2つ作成し、サイズを調整し取得しやすい位置に配置します。(画像ではScaleのZが0.1になっていますが、もっと薄い0.01にします。)
作成したオブジェクトの名前を「RedTile」、「BlueTile」にします。

Assetsに3つMaterialを作成
それぞれ赤、青、紫のMaterialにします。

配置したTileに赤と青のMaterialを適用します。

RedTile、BlueTileのHierarchyに作成したMaterialをドラッグ!

PickUpObj.csとEventTriggerを追加し設定します。

EventTriggerはPointerClickにし、PickUpObjの『OnClick』を実行する設定

Layerを『ItemObj』にします。

レイヤーを変えないとクリックしてもスクリプトが実行されないから注意

アイテムTypeの追加

Item.csに新しくアイテムTypeを追加します。

using UnityEngine;
using System;

[Serializable]
public class Item
{
    public enum Type
    {
        Cube,
        Sphere,
        Key,
        RedTile,  // 追加
        BlueTile,  // 追加
        PurpleTile,  // 追加
    }

    public Type type;
    public Sprite sprite;
    public GameObject zoomPrefab;

    public Item(Item item)
    {
        this.type = item.type;
        this.sprite = item.sprite;
    }
}

RedTile,BlueTileのTypeをそれぞれ設定します。

RedTileとBlueTileをPrefab化します。

Spriteの作成

画面下のUIに表示する画像を3つ作成します。
スクリーンショットなどでキャプチャーし画像を用意します。

紫のタイルは用意していないので、Prefab化したRedTileなどを複製し、紫のMaterialを適用しキャプチャーします。

3つの画像をプロジェクトにドラッグしインポート

インポートした画像を選択し、TextureTypeを『Sprite(2D and UI)』にし、SpriteModeを『Single』にしApplyします。

Ctrl+クリックで画像をまとめて選択してから変更すると楽チン

ズームオブジェの作成

ズームした際のTileを作成します。

ZoomCanvasの中のZoomObjParentに、作成したRedTileのPrefabを配置し「Unpack」を選択。Prefab化を解除します。

表示位置がおかしい場合はPositionを調整します。
サイズが小さすぎるので大きくします。

Scaleの横のアイコンをクリックし調整すると比率を維持したまま変えることができるので活用します。

今回は1.5倍のサイズにした

PickUpObj.csは不要なので削除します。

ズーム用のタイルが用意できたので、『ZoomObj』フォルダに入れPrefab化します。

わかりにくいので名前を「ZoomRedTile」にします。

HierarchyのRedTile(ZoomObjParent下のもの)は不要なので削除しておきましょう。

Prefab Variant

青タイル、紫タイルも用意する必要があるので、Prefab Variantを活用し作成します。

ZoomRedTileを右クリックし、Create→『Prefab Variant

ZoomRedTileをもとに複製されます。

2つ作成し、それぞれ名前とMaterialを変えます

この場合、ZoomRedTileが親になっています。
親の内容を変更した場合、子のZoomBlueTileとZoomPurpleTileにも変更した内容が反映されるようになります。
(間違ってZoomRedTileのMaterialを変えると子のMaterialも変更されてしまいます)

Prefab Variantを上手く活用することで効率よく製作が行えます。

上手く作成できているか確認。大丈夫そう

データベースに登録

UIに表示する画像とズーム画面に生成するPrefabが作成できたのでデータベースに登録します。

ItemDatabaseEntityに3つのタイルを登録

Scriptsフォルダにある『ItemDatabaseEntity』を選択
新しく項目を追加します。

それぞれTypeを選択し、キャプチャーした画像をSpriteへ入れ、ZoomObjフォルダにあるPrefabをZoomPrefabへ登録。

データベースに登録が完了しました。

実行

新しく作ったけど、ここまでは今までと同じ

スクリプトによるアイテム合成機能の作成

新規アイテムの作成とデータベースへの登録が完了しました。
ここからはスクリプトを追加、変更しアイテムを合成できるようにします。

ZoomItemスクリプトの作成

まずは拡大中のアイテムをクリックした際に実行されるスクリプトを作成します。

新しくZoomItem.csを作成します。

ZoomItem.cs
using UnityEngine;

public class ZoomItem : MonoBehaviour
{
    public void OnClick()
    {
        Debug.Log("アイテムをクリック");
    }
}

ZoomRedTileのPrefabにZoomItem.csをアタッチします。

Prefab VariantになっているのでZoomBlueTileとZoomPurpleTileにも適応されていると思います。

EventTriggerにZoomItemのOnClickを設定

実行するとConsoleにログが表示されるようになりました。

ログが出ない場合、Layerの設定やCameraのMaskが正しくなっているか確認しましょう。

拡大表示中のアイテムと選択中のアイテムを判定する

現在、選択中のアイテムの情報は「selectSlot」が保持しています。
拡大表示しているアイテムの情報はまだないので新たに「showSlot」を変数とし、別々に保持するようにします。

ItemBox.cs
using UnityEngine;

public class ItemBox : MonoBehaviour
{
    [SerializeField] Slot[] slots;

    public static ItemBox instance;
    Slot selectSlot;
    
    Slot showSlot;  // 追加:拡大表示しているアイテムスロット

    private void Awake()
    {
        instance = this;
    }

    public void SetItem(Item item)
    {
        for (int i = 0; i < slots.Length; i++)
        {
            Slot slot = slots[i];
            if (slot.IsEmpty())
            {
                slot.Set(item);
                break;
            }
        }
    }

    public void OnSlotClick(int position)
    {
        for (int i = 0; i < slots.Length; i++)
        {
            slots[i].HideBackPanel();
        }
        slots[position].OnSelect();
        selectSlot = slots[position];
    }

    public bool CheckSelectItem(Item.Type useItemType)
    {
        if (selectSlot == null)
        {
            return false;
        }
        if (selectSlot.GetItem().type == useItemType)
        {
            return true;
        }
        return false;
    }

    // 追加:送られてきたアイテムタイプが『拡大表示』されているかどうか判定する関数
    public bool CheckShowItem(Item.Type useItemType)
    {
        if (showSlot == null)
        {
            return false;
        }
        if (showSlot.GetItem().type == useItemType)
        {
            return true;
        }
        return false;
    }

    public void UseSelectItem()
    {
        selectSlot.RemoveItem();
        selectSlot = null;
    }
    
    // 追加:使ったshowSlotのアイテムを消す
    public void UseShowItem()
    {
        showSlot.RemoveItem();
        showSlot = null;
    }

    public Item GetSelectItem()
    {
        if (selectSlot == null)
        {
            return null;
        }
        return selectSlot.GetItem();
    }

    // 追加
    public void SetShowSlot()
    {
        // 現在選択中のスロットを拡大表示スロットとする
        showSlot = selectSlot;
    }
}

CheckShowItemメソッドは拡大表示しているアイテムが引数と同じものかどうか判定します。

SetShowSlotメソッドは拡大表示した時に実行されselectSlotの情報をshowSlotに渡します。

UseShowItemメソッドは合成後に使用した拡大中のアイテムを消すためのものです。

ZoomPanel.cs
using UnityEngine;

public class ZoomPanel : MonoBehaviour
{
    [SerializeField] GameObject zoomPanel;
    Canvas canvas;

    [SerializeField] Transform zoomObjParentt;
    GameObject zoomItem;

    public static ZoomPanel instance;
    private void Awake()
    {
        instance = this;
    }

    void Start()
    {
        canvas = GetComponent<Canvas>();
        HideZoomPanel();
    }

    public void SetRenderCamera(Camera camera)
    {
        canvas.worldCamera = camera;
    }

    public void OnClickZoom()
    {
        Item selectItem = ItemBox.instance.GetSelectItem();
        if (selectItem == null)
        {
            return;
        }
        zoomPanel.SetActive(true);
        ShowItem();
    }

    void ShowItem()
    {
        if (zoomItem != null)
        {
            Destroy(zoomItem);
        }
        Item selectItem = ItemBox.instance.GetSelectItem();
        zoomItem = ItemDatabase.instance.CreateZoomItem(selectItem.type);
        zoomItem.transform.SetParent(zoomObjParentt, false);
        
        // 追加:SetShowSlotメソッドを実行する
        ItemBox.instance.SetShowSlot();

        ItemRotation.instance.ResetRotation();
    }

    public void HideZoomPanel()
    {
        zoomPanel.SetActive(false);
    }

    public Item GetCurrentZoomItem()
    {
        return zoomItem?.GetComponent<Item>();
    }
}

拡大表示した時にSetShowSlotメソッドを実行するように変更

ZoomItem.cs
using UnityEngine;

public class ZoomItem : MonoBehaviour
{
    public void OnClickObj()
    {
        Debug.Log("アイテムをクリック");
        // 拡大中のもの:青(or 赤) :ItemBox:showSlot
        // 選択中のもの:赤(or 青) :ItemBox:selectSlot
        // => 紫を取得

        if ((ItemBox.instance.CheckShowItem(Item.Type.BlueTile)) && ItemBox.instance.CheckSelectItem(Item.Type.RedTile)
            || (ItemBox.instance.CheckShowItem(Item.Type.RedTile)) && ItemBox.instance.CheckSelectItem(Item.Type.BlueTile)
            )
        {
            ItemBox.instance.UseSelectItem();
            ItemBox.instance.UseShowItem();
            // 紫を取得:生成してBoxにセット
            Item purpleItem = ItemDatabase.instance.Spawn(Item.Type.PurpleTile);
            ItemBox.instance.SetItem(purpleItem);
        }
    }
}

IF文の流れ
(拡大中が青で選択中が赤)または(拡大中が赤で選択中が青)の場合、アイテム欄の2つのアイテムを使用し紫を取得。

実行

紫のタイルを生成!・・・あれ?

拡大表示しているアイテムを合成結果のアイテムにする

今の仕組みだと、合成後に拡大画面に前のアイテムが残ってしまっています。なので合成結果のアイテムに変更するようにします。

まずはZoomPanel.csShowItemメソッドを二つに分けます。
ShowClickItemメソッドをselectItemを取得するためのものにし、ShowItemメソッドはpublicにし引数を変更。
OnClickZoomメソッドはShowClickItemを実行するように変更します。

ZoomPanel.cs
using UnityEngine;

public class ZoomPanel : MonoBehaviour
{
    [SerializeField] GameObject zoomPanel;
    Canvas canvas;

    [SerializeField] Transform zoomObjParentt;
    GameObject zoomItem;

    public static ZoomPanel instance;
    private void Awake()
    {
        instance = this;
    }

    void Start()
    {
        canvas = GetComponent<Canvas>();
        HideZoomPanel();
    }

    public void SetRenderCamera(Camera camera)
    {
        canvas.worldCamera = camera;
    }

    public void OnClickZoom()
    {
        Item selectItem = ItemBox.instance.GetSelectItem();
        if (selectItem == null)
        {
            return;
        }
        zoomPanel.SetActive(true);
        ShowClickItem(); // 実行するメソッド名を変更
    }

    // クリックした時に selectItem を取得するメソッド
    void ShowClickItem()
    {
        if (zoomItem != null)
        {
            Destroy(zoomItem);
        }
        Item selectItem = ItemBox.instance.GetSelectItem();
        ShowItem(selectItem);
    }

    // アイテムを生成するメソッド
    public void ShowItem(Item item) // 引数を追加
    {
        if (zoomItem != null)
        {
            Destroy(zoomItem);
        }
        zoomItem = ItemDatabase.instance.CreateZoomItem(item.type); // 引数を変更
        zoomItem.transform.SetParent(zoomObjParentt, false);
        ItemBox.instance.SetShowSlot();
        ItemRotation.instance.ResetRotation();
    }

    public void HideZoomPanel()
    {
        zoomPanel.SetActive(false);
    }

    public Item GetCurrentZoomItem()
    {
        return zoomItem?.GetComponent<Item>();
    }
}

次にZoomItem.csを変更します。
purpleItemの引数を渡してShowItemを実行し紫Tileを生成します。

ZoomItem.cs
using UnityEngine;

public class ZoomItem : MonoBehaviour
{
    public void OnClickObj()
    {
        Debug.Log("Tileをクリック");
        
        if ((ItemBox.instance.CheckShowItem(Item.Type.BlueTile)) && ItemBox.instance.CheckSelectItem(Item.Type.RedTile)
            || (ItemBox.instance.CheckShowItem(Item.Type.RedTile)) && ItemBox.instance.CheckSelectItem(Item.Type.BlueTile)
            )
        {
            ItemBox.instance.UseSelectItem();
            ItemBox.instance.UseShowItem();
            Item purpleItem = ItemDatabase.instance.Spawn(Item.Type.PurpleTile);
            ItemBox.instance.SetItem(purpleItem);

            // 拡大画面を紫にする
            ZoomPanel.instance.ShowItem(purpleItem);
        }
    }
}

実行

オッケイ!!

スクリプトをシンプルにし汎用性を持たせる

ZoomItem.csを見ると、『ItemBox.instance』がたくさんあります。
なのでItemBox.csに処理を移しシンプルにします。

    public void OnClickObj()
    {
        Debug.Log("Tileをクリック");
        
        if ((ItemBox.instance.CheckShowItem(Item.Type.BlueTile)) && ItemBox.instance.CheckSelectItem(Item.Type.RedTile)
            || (ItemBox.instance.CheckShowItem(Item.Type.RedTile)) && ItemBox.instance.CheckSelectItem(Item.Type.BlueTile)
            )
        {
            ItemBox.instance.UseSelectItem();
            ItemBox.instance.UseShowItem();
            Item purpleItem = ItemDatabase.instance.Spawn(Item.Type.PurpleTile);
            ItemBox.instance.SetItem(purpleItem);

            // 拡大画面を紫にする
            ZoomPanel.instance.ShowItem(purpleItem);
        }
    }

ごちゃごちゃしすぎ

ItemBox.csにFusionメソッドを追加
引数は3つのアイテム情報を受け取り、IF文で2つのアイテム情報を使用し判定を行い、正しければ3番目のアイテムを生成します。

ItemBox.cs
using UnityEngine;

public class ItemBox : MonoBehaviour
{
    [SerializeField] Slot[] slots;

    public static ItemBox instance;

    Slot selectSlot;
    Slot showSlot;

    private void Awake()
    {
        instance = this;
    }

    public void SetItem(Item item)
    {
        for (int i = 0; i < slots.Length; i++)
        {
            Slot slot = slots[i];
            if (slot.IsEmpty())
            {
                slot.Set(item);
                break;
            }
        }
    }

    public void OnSlotClick(int position)
    {
        for (int i = 0; i < slots.Length; i++)
        {
            slots[i].HideBackPanel();
        }
        slots[position].OnSelect();

        selectSlot = slots[position];
    }

    public bool CheckSelectItem(Item.Type useItemType)
    {
        if (selectSlot == null)
        {
            return false;
        }
        if (selectSlot.GetItem().type == useItemType)
        {
            return true;
        }
        return false;
    }

    public bool CheckShowItem(Item.Type useItemType)
    {
        if (showSlot == null)
        {
            return false;
        }
        if (showSlot.GetItem().type == useItemType)
        {
            return true;
        }
        return false;
    }

    public void UseSelectItem()
    {
        selectSlot.RemoveItem();
        selectSlot = null;
    }

    public void UseShowItem()
    {
        showSlot.RemoveItem();
        showSlot = null;
    }

    public Item GetSelectItem()
    {
        if (selectSlot == null)
        {
            return null;
        }
        return selectSlot.GetItem();
    }

    public void SetShowSlot()
    {
        showSlot = selectSlot;
    }
    
    // 追加
    public void Fusion(Item.Type item0, Item.Type item1, Item.Type spawnItem) //3つの引数を追加
    {
        if ((CheckShowItem(item0)) && CheckSelectItem(item1)
    || (CheckShowItem(item1)) && CheckSelectItem(item0)
    )
        {
            UseSelectItem();
            UseShowItem();
            Item newItem = ItemDatabase.instance.Spawn(spawnItem);
            SetItem(newItem);
            ZoomPanel.instance.ShowItem(newItem);
        }
    }
}

ZoomItem.csでは3つの引数を送りFusionメソッドを実行します。

ZoomItem.cs
using UnityEngine;

public class ZoomItem : MonoBehaviour
{
    public void OnClickObj()
    {
        Debug.Log("Tileをクリック");

        ItemBox.instance.Fusion(Item.Type.BlueTile, Item.Type.RedTile, Item.Type.PurpleTile);
    }
}

こっちは引数を送ってFusionを実行するだけ

シンプルにしたことで、別のアイテムの合成の処理も追加しやすくなりました。

まとめ

今回の記事では、アイテムの追加方法のおさらいと、アイテムの合成機能の実装を行いました。いくつも反復して作業を行うことで手順を見ないでも追加ができるようになると思います。

とりあえず今回はここまで

参考にさせていただきました。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です