Unityゲームの作り方メモ

[Unity]3D脱出ゲームの作り方

Unity

ユニティを使用した脱出ゲームの作り方をまとめたメモです。ゲーム制作の参考にしていただければ嬉しいです。トグルボタンをクリックすると記事が表示されます。小さくて見ずらい画像はクリックで拡大できます。

3Dモデルの準備

部屋を作成するのに必要な床、壁、天井、ドアの3Dモデルを用意します。

私は立体屋さんの物を使用しました。無料で使用できるのでおすすめです。

フローリングの床壁(白)天井ドア3窓(白)ドア用の壁(白)をダウンロードしてきました。

ダウンロードしたファイルを解凍して出てきたフォルダをUnityのフォルダにドラック&ドロップします。

他のモデルやアセットを使用して作成しても問題ありません

素材の配置

素材をドラック&ドロップで並べていき部屋を作成していきます。

立体屋さんの壁などは裏面が透過されているものがあるので向きに注意しながら配置していきます。

並べたものはUnpackでprefab状態を解除して空のオブジェクトを作成してまとめておくと管理しやすいです。

Directional Lightをオフにして天井にポイントライトを設置します。

空のオブジェクトを作成して右クリックからPointLightを作成します。

Intensityで光の強さRangeで光の範囲を調整することができます。

ポイントライトを天井付近に移動させて部屋全体を照らせるように調整します。



アイテムボックスとアイテムの作成

次に部屋のドアを開ける鍵を作っていきます。

こちらのモデルも立体屋さんで用意することができます。

鍵をクリックしたら消える処理を作っていきます。

鍵が用意できたら画面内に配置して下のコード(pickupObj)を鍵に貼り付けます。

using UnityEngine;

public class PickupObj : MonoBehaviour
{
   //クリックしたら消える(取得)
    public void OnClickObj() 
    {
        gameObject.SetActive(false);
    }
}

配置した鍵オブジェクトのinspector画面からaddComponent→Eventtriggerを選択します。

addComponentからColiderを追加します。私はBoxColiderを付けました。

AddNewEventTypeをクリックしてpointerClickを押します。

pickupObjをドラッグ&ドロップして以下のように設定します。

メインカメラをクリックしてAddComponentからphysicsRaycasterを追加します。

EventSystemがない場合は作成してください。

Hierarch画面を右クリックUI→EventSystemから作成できます。

メインカメラを鍵の前に持っていきUnityを再生してアイテムが取得できるかチェックします。

画面から鍵が消えれば成功です。

ほかにもアイテムと作りたい場合は鍵と同じように設定していきます。

アイテムボックスを作成していきます。

inspector画面を右クリックしてUI→canvasを作成して、その子オブジェクトにPanelを作成します。

PanelのRectTransformを変更してアイテムボックスの位置を決めます。

私は画面下のほうに配置しました。

Panelの子オブジェクト空のgameobjectを追加します。名前はSlotにしました。

Slotの子オブジェクトにImageを二つ作成します。名前はBackもう一つはImageにしました。

SlotPanelに収まるようにサイズや位置の調整をしたら、Backのカラーを変更してサイズをImageより少し大きく設定します。Backのカラーは黒に変更しました。

Slotはprefabsフォルダにドラッグ&ドロップprefab化しておきます。

PanelにaddComponentからHorizontal Layout Groupを追加します。

これを追加すると子オブジェクトをきれいに並べてくれます。

左寄りになっていたのでChildAlignmentをMiddleCenterにするときれいに並んでくれると思います。

脱出ゲームの作り方

こんな感じに設定しました。

panelの下にImageを作成してアイテムを拡大表示するためのボタンを作成します。

名前はZoomButtonにしました。ImageはUnityに入っていたものを使用していますがお好みで変更してください。

CanvasとPanelの名前をItemBoxCanvasとItemBoxPanelに変更しておきました。

アイテムボックスのスクリプトを作成します。

using UnityEngine;

public class ItemBox : MonoBehaviour
{    
  //どこからでもアクセスできるようにする変数
    public static ItemBox instance;
    private void Awake()
    {
        instance = this;
    }
    //クリックした時アイテムを受け取る
    public void SetItem(Item.Type item)
    {
        Debug.Log(item);
    }
}

ItemBoxCanvasに作成したスクリプトを貼り付けます。

前に作成した「pickupObj」スクリプトを編集します。

データベースからアイテムを探して生成する

アイテムがクリックされたらアイテムボックスに入れる

using UnityEngine;

public class PickupObj : MonoBehaviour
{
  //アイテムの種類を設定する
    public Item.Type type =default;
  
  //クリックした時の処理
    public void OnClickObj()
    {
        ItemBox.instance.SetItem(type);
        gameObject.SetActive(false);
    }
}

Unityを再生して鍵をクリックして動作をチェックします。鍵が消えてログが表示されればOKです。

ItemというC#Scriptを作成します。

アイテムに種類や画像などを設定していくスクリプトです。

using System;

[Serializable]//inspectorで表示できるようにする
public class Item
{
    //アイテムの種類
    public enum Type
    {
        key,
        Cube,
        Circle,
        //アイテムを追加する場合ここに書き足す
    }
    public Type type;

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

次にItemDatabaseEntityというC#Scriptを作成します。


using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu]
public class ItemDatabaseEntity : ScriptableObject
{
    public List<Item> items = new List<Item>();
}

このスクリプトを作成してProjectの下の+ボタンを押すと

ItemDatabaseEntityという項目が出てくるのでクリックします。

このファイルが作成されればOKです。

作成されたファイルのinspectorを見るとアイテムリストが作れるようになっています。

+ボタンを押してアイテムを設定していきます。

次にItemDatabaseというスクリプトを作成します。

アイテムリストを利用してアイテムを生成するスクリプトです。

using UnityEngine;

public class ItemDatabase : MonoBehaviour
{
    //どこからでもアクセスできるようにする
    public static ItemDatabase instance;

    public void Awake()
    {
        instance = this;
    }

    [SerializeField] ItemDatabaseEntity itemDatabaseEntity = default;
    //itemを生成
    public Item Spawn(Item.Type type)
    {
        for (int i = 0; i < itemDatabaseEntity.items.Count; i++)
        {
            Item itemData = itemDatabaseEntity.items[i];
            //データベースから一致するものを探す
            if (itemData.type == type)
            {
                return new Item(itemData);
                //一致したら生成して渡す
            }
        }
        return null;
    }
}

作ったスクリプトは空のオブジェクトに貼り付けます。

オブジェクトの名前はItemDatabaseにしました。

inspectorを見るとItemDatabaseEntityの項目があるので、

前に作成したNewItemDatabaseEntityをドラッグ&ドロップします。

前に作ったPickupObjとItemBoxを修正します。

using UnityEngine;

public class PickupObj : MonoBehaviour
{
    //アイテムの種類を設定する
    public Item.Type type =default;
    
  //データベースからアイテムを生成
  //クリックしたら消える
  //アイテムボックスに入れる
    public void OnClickObj()
    {
        Item item = ItemDatabase.instance.Spawn(type);
        ItemBox.instance.SetItem(item);
        gameObject.SetActive(false);

    }
}
using UnityEngine;

public class ItemBox : MonoBehaviour
{
    public static ItemBox instance;
    private void Awake()
    {
        instance = this;
    }
    //クリックしたらアイテムを受け取る
    public void SetItem(Item item)
    {
        Debug.Log(item.type);
    }
}

Unityを実行してアイテムをクリックしてログに設定したアイテムのTypeが表示されればOKです。

アイテムを取得したときにアイテムボックスに画像を反映する処理を作っていきます。

まずアイテムの画像を用意します。

私は鍵をprefab化してprefabのScene画面のスクリーンショットを切り抜いて作成しました。

Windowsならこちらのソフトを使うと簡単に切り抜くことができます。

用意した画像をUnityフォルダにドラッグ&ドロップして、

inspector画面からtextureTypeをSpriteに変更してapplyをクリックします。

今のところアイテムはタイプしかもっていないので、

前に作成したItemのスクリプトを開いて、

using UnityEngine;、public Sprite sprite;、this.sprite = item.sprite;を書き足します。

using System;
using UnityEngine;

[Serializable]//inspectorで表示できるようにする
public class Item
{
    //アイテムの種類
    public enum Type
    {
        key,
        Cube,
        Circle,
        //アイテムを追加する場合ここに書き足す
    }
    //タイプを持たせる
    public Type type;
    //画像を持たせる
    public Sprite sprite;

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

New Item Database Entityのinspector画面に画像を設定する場所ができているので、用意したアイテム画像をドラッグ&ドロップします。

スロットにコードを付けていき、slotの子オブジェクトのImageを変更することで

アイテムを取得したときにアイテムボックスに画像を表示できるようにしていきます。

SlotというC#Scriptを作成します。

using UnityEngine;
using UnityEngine.UI;

public class Slot : MonoBehaviour
{
    [SerializeField] Image image = default;
    Item item = null;
    public void Set(Item item) 
    {
        this.item = item;
        image.sprite=item.sprite;
    }

    public bool IsEmpty() 
    {
        if(item == null) 
        {
            return true;        
        }
        return false;
    }
}

Slotのprefabを開いて作成したスクリプトをSlotに貼り付けます。

Imageを設定する場所ができるのでドラッグ&ドロップして設定します。

アイテムボックスがすべてのスロットを把握して左詰めで画像を表示していくようにコードを変更します。

using UnityEngine;

public class ItemBox : MonoBehaviour
{
    //アイテムボックスがすべてのスロットを取得
    [SerializeField] Slot[] slots = default;

    //どこからでもアクセスできる
    public static ItemBox instance;
    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;
            }
        }
    }
}

変更したらinspector画面にスロットを入れる場所ができるのでドラッグ&ドロップしていきます。

Unityを再生してアイテムをクリックしてアイテムボックスに画像が表示されればOKです。



カメラの設定

ボタンをクリックしたらカメラを回転,ズームさせるスクリプトを作成します。

CameraManagerというC#Scriptと空のオブジェクトを作成して、

空のオブジェクトにスクリプトを貼り付けます。

using UnityEngine;

public class CameraManager : MonoBehaviour
{
    [SerializeField] Transform[] cameraPositions;
    int currentIndex = 0;

    private void Start()
    {
        currentIndex= 0;
        SetCameraPosition(currentIndex);
    }
    public void TurnRight() 
    {
        currentIndex++;
        if(currentIndex >= cameraPositions.Length) 
        {
            currentIndex= 0;
        }
        SetCameraPosition(currentIndex);
    }

    public void TurnLeft() 
    {
        currentIndex--;
        if (currentIndex <= -1)
        {
            currentIndex = cameraPositions.Length-1;
        }
        
        SetCameraPosition(currentIndex);
    }

    void SetCameraPosition(int index) 
    {
        Camera.main.transform.position = cameraPositions[index].position;
        Camera.main.transform.rotation = cameraPositions[index].rotation;
    }
}

Canvasを作成して子オブジェクトPanelを3つを追加します。

名前はCameraMoveCanvas、LeftPanel、RightPanel、BackPanelにしました。

3つのPanelにaddComponentからButtonを追加します。

パネルを配置します。LeftPanelは赤RightPanelは青BackPanelは黄にしました。

BackPanelは一旦非表示にしておきます。

inspector画面のチェックを外すと非表示にできます。

LeftPanelとRightPanelのボタン設定をしていきます。

OnClickの+ボタンを押してCameraManagerをドラッグ&ドロップします。

それぞれCameraManagerのturnLeft、turnRightを設定します。

移動Panelをクリックした時のカメラのポジションを作成していきます。

CameraPositionsという空のオブジェクトを作成します。

その子オブジェクトにゲームオブジェクトを作成します。

空のゲームオブジェクトだとわかりにくかったのでCubeを作成しました。

このキューブの位置にメインカメラを移動させることでカメラを回転させます。

それぞれ4方向の壁を向くように角度や位置を調整して配置していきます。

青の矢印のほうが正面です。

カメラマネージャーにオブジェクトをセットして

メインカメラのポジションを全て0にして

LeftPanel、RightPanelを押しながらカメラ位置を調整していきます。

Cubeなどで作った場合は最終的にmeshRendererをオフにします。

部屋がみわたせるようになればOKです。

部屋にあるものをクリックしたらズームさせる機能を付けていきます。

メインカメラとは別にズームカメラを用意して、クリックした時に切り替えることでズームさせます。

ドアにズーム機能を付けていきます。

まずドアの子オブジェクトに空のオブジェクトを作成してAddComponentからColiderを付けます。私はBoxColiderを付けました。

名前はDoorZoomにしました

このコライダーをクリックした時にドアにズームするようにします。

コライダーをドアのサイズより少し大きめに調整します。

新しくカメラを作成してドアにズームさせておきます。

位置が決まったらオフにしておいて大丈夫です

次にZoomCameraSetterというC#Scriptを作成して。

先ほど作成したDoorZoomに貼り付けます。

CameraManagerとZoomCameraSetterを編集します。

using UnityEngine;

public class ZoomCameraSetter : MonoBehaviour
{
    [SerializeField] Camera zoomCamera = default;
    public void OnClickObj() 
    {
        zoomCamera.gameObject.SetActive(true);
        CameraManager.instance.SetZoomCamera(zoomCamera);
    }
}
using UnityEngine;

public class CameraManager : MonoBehaviour
{
    public static CameraManager instance;

    [SerializeField] GameObject backButton =default;
    [SerializeField] GameObject RightButton=default;
    [SerializeField] GameObject LeftButton = default;
    [SerializeField] Transform[] cameraPositions;
    Camera zoomCamera = default;
    Camera mainCamera = default;
    int currentIndex = 0;

    private void Awake()
    {
        instance= this;
    }

    private void Start()
    {
        mainCamera=Camera.main;
        currentIndex= 0;
        SetCameraPosition(currentIndex);
        backButton.SetActive(false);
    }
    public void TurnRight() 
    {
        currentIndex++;
        if(currentIndex >= cameraPositions.Length) 
        {
            currentIndex= 0;
        }
        SetCameraPosition(currentIndex);
    }

    public void TurnLeft() 
    {
        currentIndex--;
        if (currentIndex <= -1)
        {
            currentIndex = cameraPositions.Length-1;
        }
        
        SetCameraPosition(currentIndex);
    }

    public void OnBack() 
    {
        backButton.SetActive(false);
        LeftButton.SetActive(true);
        RightButton.SetActive(true);
        this.zoomCamera.gameObject.SetActive(false);
        mainCamera.gameObject.SetActive(true);
    }

    void SetCameraPosition(int index) 
    {
        Camera.main.transform.position = cameraPositions[index].position;
        Camera.main.transform.rotation = cameraPositions[index].rotation;
    }

    public void SetZoomCamera(Camera zoomCamera) 
    {
        this.zoomCamera = zoomCamera;
        backButton.SetActive(true);
        LeftButton.SetActive(false);
        RightButton.SetActive(false);
        Camera.main.gameObject.SetActive(false);
    }
}

DoorZoomのinspector画面のZoomCameraSetterにzoomカメラを入れる場所ができているので、ドラッグ&ドロップして先ほど作ったzoomカメラをセットします。

DoorZoomにEventtriggerを追加して設定します。

カメラをマネージャーにLeftPanel、RightPanel、BackPanelを入れる場所があるので設定します。

ズームしたときにBackPanelがオンになりRightPanel、LeftPanelが非表示になります。

バックボタンを押すとBackPanelが非表示になりRightPanel、LeftPanelが表示されます。

移動ボタンがアイテムボックスより手前に表示される場合はItemBoxCanvasのSortOrderをCameraMoveCanvasの数値より上にすると治ります。

ドアを開く

クリックするとドアが開くようにしていきます。

まずドアの開くアニメーションを作成します。

ドアを右クリックしてWindow→Animation→Animationをクリックします。

アニメーションのウィンドウが開くのでCreateを押してanimファイルを作成できます。名前はDoorにしました。

まず待機モーション(動かない)を作ります。

赤い丸のボタンをクリックします。

ドアのinspector画面のTransfomeを何でもいいので変更して元に戻すと、0秒のところに印が付くのでもう一度赤いボタンを押します。

次にドアの開くモーションを作ります。赤いボタンの下をクリックして、CreateNewClipをクリックすると新しくモーションを作成できます。

ファイル名はDoorOpenにしました。

0秒のところのrotationを0に、1秒のところのrotation.Yを-90に変更してもう一度赤い丸のボタンをクリックします。

再生して、モーションをチェックします。

DoorOpenのファイルをクリックしてinspecterのlooptimeのチェックが入っていると、何度もドアが開くのでチェックを外します。

Doorスクリプトを作成してDoor貼り付けます。

animator.Play(“”);の()の中を再生するanimファイルの名前にします。

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

public class Door : MonoBehaviour
{
    [SerializeField] Animator animator = default;
    public void Open() 
    {
        animator.Play("DoorOpen");

    }
}

作成したスクリプトをドアに貼り付けるとAnimatorを設定する場所があるのでドラッグ&ドロップして設定します。

ドアにAddComponentからEventtriggerを追加して設定します。

ドアが開くかチェックします。

Doorzoomが邪魔なので一度オフにしてチェックします。

ズームしてから開きたい場合はドアとDoorZoomのレイヤーを変更することで可能になります。

何でもいいのでinspector画面を表示してAddLayerから新しいレイヤーを作成できます。

zoomというレイヤーを作りました。

Doorzoomのレイヤーをzoomに変更します。

DoorZoomCameraのPhysicsRaycasterのEventMaskのzoomの項目のチェックを外します。

このチェックを外せばズーム状態でDoorzoomに反応しなくなってズームしているときにドアをクリックしたときだけ開くようになります。



アイテムスロットの選択機能

アイテムを選択する機能を付けて鍵を使用した時だけドアが開くようにしていきます。

アイテムの選択はスロットの黒い枠を全て非表示にして選択した時のみ黒い枠を表示して選択状態にします。

Slot、ItemBox、Doorのスクリプトを編集します。

using UnityEngine;
using UnityEngine.UI;

public class Slot : MonoBehaviour
{
    [SerializeField] GameObject backPanel = default;
    [SerializeField] Image image = default;
    Item item = null;

    private void Start()
    {
        backPanel.SetActive(false);
    }
    public void Set(Item item) 
    {
        this.item = item;
        image.sprite=item.sprite;
    }

    public void RemoveItem() 
    {
        item = null;
        image.sprite = null;      
        HideBackPanel();
    
    }

    public Item GetItem() 
    {
        return item;
    }

    public bool IsEmpty() 
    {
        if(item == null) 
        {
            return true;        
        }
        return false;
    
    }

    public void OnSelect()
    {
        backPanel.SetActive(true);      
    }

    public void HideBackPanel()
    {
        backPanel.SetActive(false);
    }
}
using UnityEngine;

public class ItemBox : MonoBehaviour
{
    //アイテムボックスがすべてのスロットを取得
    [SerializeField] Slot[] slots = default;

    //どこからでもアクセスできる
    public static ItemBox instance;

    Slot selectSlot;
    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) 
    {
        //アイテムがない場合実行しない
        if (slots[position].IsEmpty()) 
        {
            return;
        }
        //一度BackPanelを全て消す
        for(int i =0; i<slots.Length; i++) 
        {
            slots[i].HideBackPanel();
        
        }
        //クリックしたスロットのBackPanelを表示する
        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 void UseSelectItem()
    {
        selectSlot.RemoveItem();
        selectSlot= null;            
    }
}
using UnityEngine;

public class Door : MonoBehaviour
{
    [SerializeField] Animator animator = default;
    public void Open() 
    {
        if (ItemBox.instance.CheckSelectItem(Item.Type.key)) 
        {
            ItemBox.instance.UseSelectItem();
            animator.Play("DoorOpen");
        }
    }
}

Slotのprefabを開くとBackPanelを設定する場所があるのでBackをドラッグ&ドロップして設定します。

slotにaddComponentからButtonを追加します。

ボタンにitemBoxCanvasをドラッグ&ドロップしてOnSlotClickを設定すると、

数字を入力する場所があるのでprefab閉じて一つずつ設定します。

私の場合スロットが6個あるのですべてのスロットに0~5の数字を順番に設定していきます

鍵を選択しているときだけドアが開いて使用したアイテムは消えるようになります。

ズーム用パネルの作成

アイテムを選択している時に+ボタンをクリックすることでアイテムをズームする機能を作成します。

黒いパネルを表示してその前にズーム用のオブジェクトを生成して拡大表示や回転などができるようにします。

右クリックしてUI→Canvasを作成します。

名前はZoomCanvasにしました。

ZoomCanvasのinspector画面のRenderModeをScreenSpace-Cameraに変更して、

renderCameraにMainCameraをドラッグ&ドロップします。

Planedistanceでカメラとキャンバスの距離を調整できます。

私は1に設定しておきました。

ZoomCanvasの子オブジェクトにPanel作成します。名前はBackGroundPanelにしました。

BackGroundPanelは透明にして、その子オブジェクトにPanelを作成します。

名前はBlackPanelにしました。BlackPanelのカラーを黒に設定してBlackPanelのサイズを調整します。

BlackPanelの前にズーム用のオブジェクトを作成したいので、BlackPanelの子オブジェクトにCreateemptyを作成します。

名前はZoomObjParentにしました。

鍵のズームオブジェクト用のprefabを作成して。

ZoomObjParentにドラッグ&ドロップして大きさを調整します。

rotationを変更してもBlackPanelにめり込まないように調整していきます。

Itemスクリプトを編集してアイテムデータベースにズーム用のprefabを設定できるようにします。

using System;
using UnityEngine;

[Serializable]//inspectorで表示できるようにする
public class Item
{
    //アイテムの種類
    public enum Type
    {
        key,
        Cube,
        Circle,
        //アイテムを追加する場合ここに書き足す

    }

    //タイプを持たせる
    public Type type;
    //画像を持たせる
    public Sprite sprite;
    //zoom用のprefab
    public GameObject ZoomPrefab;

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

編集したらNew Item Database Entityのinspecter画面にズームprefabを設定する場所ができるのでドラッグ&ドロップして設定します。

ZoomCanvasにC#Scriptを作成して貼り付けます。

名前はZoomPanelにしました。

using UnityEngine;

public class ZoomPanel : MonoBehaviour
{
    [SerializeField] GameObject backGroundPanel;
    Canvas canvas;
    [SerializeField] Transform zoomObjParent;
    GameObject zoomItem;

    public static ZoomPanel instance;

    private void Awake()
    {
        instance= this;
    }

    private void Start()
    {
        canvas = GetComponent<Canvas>();
        HideZoomPanel();      
    }
    public void OnClickZoom() 
    {
        Item selectItem = ItemBox.instance.GetSelectItem();
        if (selectItem == null)
        {
            return;
        }
        backGroundPanel.SetActive(true);
        ShowItem();
    }

    void ShowItem() 
    {
        if(zoomItem != null) 
        {
            Destroy(zoomItem);        
        }
        Item selectItem = ItemBox.instance.GetSelectItem();
        zoomItem = ItemDatabase.instance.CreateZoomItem(selectItem.type);
        zoomItem.transform.SetParent(zoomObjParent,false);  
    }

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

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

+ボタンを押したときに拡大するようにしたいので、ItemBoxCanvasの+アイコンにボタン機能を付けてOnClickZoomを設定します。

ズーム画面を非表示にするためのボタンを作成します。

BlackPanelの子オブジェクトにUI→Buttonでボタンを作成します。

テキストメッシュがついているので文字をXにするかボタンのImageを変更して閉じるボタンを作成します。

OnClickにZoomPanel.HideZoomPanelを設定します。

右上のほうに配置してみました。

ZoomPanelにBackGroundPanelとZoomObjParentを設定する場所ができているのでドラック&ドロップで追加します。

ItemDatabaseにズームオブジェクトを生成する関数を追加しました。


using UnityEngine;


public class ItemDatabase : MonoBehaviour
{
    //どこからでもアクセスできるようにする
    public static ItemDatabase instance;

    public void Awake()
    {
        instance = this;
    }

    [SerializeField] ItemDatabaseEntity itemDatabaseEntity = default;
    //itemを生成

    public Item Spawn(Item.Type type)
    {
        for (int i = 0; i < itemDatabaseEntity.items.Count; i++)
        {
            Item itemData = itemDatabaseEntity.items[i];
            //データベースから一致するものを探す
            if (itemData.type == type)
            {
                return new Item(itemData);
                //一致したら生成して渡す

            }
        }
        return null;
    }

    public GameObject CreateZoomItem(Item.Type itemType) 
    {
        for(int i = 0; i < itemDatabaseEntity.items.Count; i++)
        {
            Item itemData = itemDatabaseEntity.items[i];
            //データベースから一致するものを探す
            if (itemData.type == itemType)
            {
                return Instantiate(itemData.ZoomPrefab);
                //一致したら生成して渡す
            }
        }
        return null;
    }
}

ItemBoxに選択したアイテムを取得する関数を追加しました。

using UnityEngine;

public class ItemBox : MonoBehaviour
{
    //アイテムボックスがすべてのスロットを取得
    [SerializeField] Slot[] slots = default;

    //どこからでもアクセスできる
    public static ItemBox instance;

    Slot selectSlot;
    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) 
    {
        //アイテムがない場合実行しない
        if (slots[position].IsEmpty()) 
        {
            return;
        }
        //一度BackPanelを全て消す
        for(int i =0; i<slots.Length; i++) 
        {
            slots[i].HideBackPanel();
        
        }
        //クリックしたスロットのBackPanelを表示する
        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 void UseSelectItem()
    {
        selectSlot.RemoveItem();
        selectSlot = null;          
    }

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

CameraManagerで開始時にズームパネルを非表示&メインカメラとズームカメラの切り替えを追加しました。

using UnityEngine;

public class CameraManager : MonoBehaviour
{
    public static CameraManager instance;

    [SerializeField] GameObject backButton =default;
    [SerializeField] GameObject RightButton=default;
    [SerializeField] GameObject LeftButton = default;
    [SerializeField] Transform[] cameraPositions;
    Camera zoomCamera = default;
    Camera mainCamera = default;
    int currentIndex = 0;

    private void Awake()
    {
        instance= this;
    }

    private void Start()
    {
        mainCamera=Camera.main;
        currentIndex= 0;
        SetCameraPosition(currentIndex);
        backButton.SetActive(false);
    }
    public void TurnRight() 
    {
        currentIndex++;
        if(currentIndex >= cameraPositions.Length) 
        {
            currentIndex= 0;
        }
        SetCameraPosition(currentIndex);
    }

    public void TurnLeft() 
    {
        currentIndex--;
        if (currentIndex <= -1)
        {
            currentIndex = cameraPositions.Length-1;
        }
        
        SetCameraPosition(currentIndex);
    }

    public void OnBack() 
    {
        backButton.SetActive(false);
        LeftButton.SetActive(true);
        RightButton.SetActive(true);
        this.zoomCamera.gameObject.SetActive(false);
        mainCamera.gameObject.SetActive(true);
        ZoomPanel.instance.setRenderCamera(mainCamera);
    }

    void SetCameraPosition(int index) 
    {
        Camera.main.transform.position = cameraPositions[index].position;
        Camera.main.transform.rotation = cameraPositions[index].rotation;
    }

    public void SetZoomCamera(Camera zoomCamera) 
    {
        this.zoomCamera = zoomCamera;
        backButton.SetActive(true);
        LeftButton.SetActive(false);
        RightButton.SetActive(false);
        Camera.main.gameObject.SetActive(false);
        ZoomPanel.instance.setRenderCamera(zoomCamera);
    }
}

ズームしたアイテムを回転させる機能を作っていきます。

表示されているものを直接回転させるのではなく、ZoomObjParentをTransformを変更することで、

回転できるようにしていきます。

C#Scriptを作成してZoomObjParentにはりつけます。名前はItemRotationにしました。

using UnityEngine;

public class ItemRotation : MonoBehaviour
{
    [SerializeField] Transform zoomObjParent;
    [SerializeField] Transform zoomCanvas;

    //回転の速度
    public float speed = 100;

    // マウスをドラッグしてズームしたアイテムを回転させる
    private void Update()
    {
        if (Input.GetMouseButton(0)) 
        {
            float dy = -Input.GetAxis("Mouse X") * speed;
            float dx = Input.GetAxis("Mouse Y") * speed;
            zoomObjParent.RotateAround(transform.position, zoomCanvas.transform.rotation * Vector3.up,dy);
            zoomObjParent.RotateAround(transform.position, zoomCanvas.transform.rotation* Vector3.right, dx);
        }             
    }
}

貼り付けると項目ができるのでZoomObjParentとZoomCanvasをドラッグ&ドロップで追加して回転スピードを設定します。

これでズームしたアイテムがマウス操作で回転するようになります。

アイテムがパネルにめり込む場合はZoomObjParentのZを調整したら治りました。

パスワードパネルの作成

まず空のオブジェクトを作成します。

名前はPasswordPanelにしました。

バックパネルの部分を作成します。

PasswordPanelの子オブジェクトにCubeを作成して横長にサイズ調整します。

名前はBackPanelにしました。

BackPanelの子オブジェクトにCubeを作成してサイズと位置を調整します。

名前はNumberPanelにしました。

次にパスワードの部分を作成していきます。

NumberPanelの子オブジェクトにtextmeshproを作成します。

テキストは0にしておきました。

NumberPanelに収まるように位置とサイズを調整します。

NumberPanelにaddComponentからEventtriggerを追加しておきます。

NumberPanelを複製して4つ並べます。

これでパネルは完成です。

NumberPanelというC#Scriptを作成します。

クリックされたときにNumberPanelの数字を変更するスクリプトです。

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

public class NumberPanel : MonoBehaviour
{
    [SerializeField] TMP_Text numberText; //表示する数字
    public int number = 0; //内部の数字

    //クリックされたら数字を増やす
    public void OnClick() 
    {
        number++;
        if(number >= 10) 
        {
            number = 0;       
        }
        numberText.text = number.ToString();    
    }
}

すべてのNumberPanelにスクリプトを貼り付けてEventtriggerにNumberPanel.OnClickを設定し、

NumbertextにTextMeshProをそれぞれ設定して行きます。

次にPasswordPanelというC#Scriptを作成します。

このスクリプトでパスワードギミック全体の管理をしていきます。

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

public class PasswordPanel : MonoBehaviour
{
    //パスワードギミック全体の管理
    //正解の数字
    int[] Answer = { 1, 2, 3, 4 };
    [SerializeField] NumberPanel[] numberPanels = default;

    public void OnClickButton() 
    {
        if (CheckClear())
        {
            Debug.Log("Clear");
        } 
    }

    bool CheckClear() 
    {
        for(int i = 0; i< numberPanels.Length; i++) 
        {
            if (numberPanels[i].number != Answer[i]) 
            {
                return false;
            
            }
        
        }
        return true;
    }
}

作成したスクリプトをBackPanelに貼り付けます。

NumberPanelを入れる場所があるので、4つのNumberPanelをドラック&ドロップで設定します。

全てのNumberPanelのEventTriggerにPasswordPanel.OnClickButtonを設定します。