目次
オリジナルのボクセルを使って脱出ゲーム制作に挑戦!
用意するもの
- Unity
- VSCode,VisualStudioなど
- 3Dモデル
この記事ではUnity6を使用しています。
前回は左右に視点を変更するところまでやりました。
カメラをズームさせる機能を作成する
今回はオブジェクトをクリックした時に視点をズームする機能を実装します。

今回はドアをクリックしたらズームさせるよ
ドアをクリックしたらズームさせる

当たり判定とEventTriggerを設定

Box Colliderを追加
3Dモデルのドアを選択し、Add ComponentからBox Colliderを追加
EditColliderから当たり判定を設定

緑の枠が当たり判定になる
EventTriggerを追加
Add ComponentからEventTriggerを追加
EventTypeはPointerClickを選択

ズームカメラを作成

SubCameraを作成
まずはHierarchyにCameraを作成

OverlayMenuからワイプを表示し、カメラを切り替え

CameraのTransformを調整する

ワイプを見ながらドアの正面まで移動させよう
Game画面でUIが映った状態でも確認

名前をSubCameraに変更

SubCameraにAdd ComponentからPhysicsRaycasterを追加
当たり判定を取得するのに必要なのであらかじめ付けておきましょう

ズームするためのスクリプトを作成
クリックした時に実行するためのスクリプトを作成します
ZoomObj.csを作成
まずは新しくZoomObjのスクリプトを作成します

ZoomObj.cs
using UnityEngine;
public class ZoomObj : MonoBehaviour
{
[SerializeField] Camera subCamera;
private void Start()
{
subCamera.gameObject.SetActive(false);
}
public void OnClick()
{
subCamera.gameObject.SetActive(true);
}
}
Startメソッド | ゲーム開始時にSubカメラを非表示にします。 |
OnClickメソッド | クリックしたらSubカメラを表示させます。 |
ドアにスクリプトをアタッチ
ZoomObj.csをDoorへドラッグしてアタッチさせます。

ZoomObjのSubCameraの項目へHierarchyのSubCameraをドラッグし設定します。

EventTriggerにスクリプトを設定し、OnClickを選択

実行してみる
うまくできた
MainCameraを非表示にする
ズームした時にエラーが出るので、MainCameraを非表示にする
CameraManagerでシングルトンの実装し、ZoomObjのOnClickからChangeCameraメソッドを実行しMainCameraを非表示にする
CameraManager.cs
using UnityEngine;
public class CameraManager : MonoBehaviour
{
//ここから追加
//シングルトンの実装
public static CameraManager instance;
private void Awake()
{
instance = this;
}
//ここまで
[SerializeField] Transform[] cameraPositions = default;
int currentIndex = 0;
void Start()
{
currentIndex = 0;
SetCameraPosition(currentIndex);
}
public void TurnRight()
{
currentIndex ++;
if (currentIndex >= cameraPositions.Length)
{
currentIndex = 0;
}
SetCameraPosition(currentIndex);
}
public void TurnLeft()
{
currentIndex--;
if (currentIndex < 0)
{
currentIndex = cameraPositions.Length -1;
}
SetCameraPosition(currentIndex);
}
void SetCameraPosition(int index)
{
Camera.main.transform.position = cameraPositions[index].position;
Camera.main.transform.rotation = cameraPositions[index].rotation;
}
//ここから追加
Camera subCamera;
public void ChangeCamera(Camera subCamera)
{
this.subCamera = subCamera;
Camera.main.gameObject.SetActive(false);
}
//ここまで
}
ZoomObj.cs
using UnityEngine;
public class ZoomObj : MonoBehaviour
{
[SerializeField] Camera subCamera;
private void Start()
{
subCamera.gameObject.SetActive(false);
}
public void OnClick()
{
//ここから追加
CameraManager.instance.ChangeCamera(subCamera);
//ここまで
subCamera.gameObject.SetActive(true);
}
}
シングルトンの実装 | 他のスクリプトからアクセスできるようにするための「お決まりの記述」です。 CameraManager.instanceを使えば、どこからでも現在のCameraManagerのインスタンスにアクセスできます。 |
引数 subCamera | 引数を渡すことで汎用性を高めることができます。 例えば、CameraManagerに引数としてsubCameraを渡すことで、サブカメラを非表示にすることができます。 |
戻るボタンを作成
元の視点へ戻るためのボタンを作成します。
BackPanel
前回作ったBackPanelを使用します。
BackPanelを押したら元の視点へ戻るようにします。

SerializeFieldを使ってBackPanelのUIを取得し、ChangeCameraメソッドが実行されたときに表示させるようにします。
OnBackButtonメソッドでは、BackPanelとSubCameraを非表示にし、MainCameraを表示するようにします。
CameraManager.cs
using UnityEngine;
public class CameraManager : MonoBehaviour
{
//ここから追加
[SerializeField] GameObject backPanel;
//ここまで
public static CameraManager instance;
private void Awake()
{
instance = this;
}
[SerializeField] Transform[] cameraPositions = default;
int currentIndex = 0;
void Start()
{
currentIndex = 0;
SetCameraPosition(currentIndex);
}
public void TurnRight()
{
currentIndex ++;
if (currentIndex >= cameraPositions.Length)
{
currentIndex = 0;
}
SetCameraPosition(currentIndex);
}
public void TurnLeft()
{
currentIndex--;
if (currentIndex < 0)
{
currentIndex = cameraPositions.Length -1;
}
SetCameraPosition(currentIndex);
}
void SetCameraPosition(int index)
{
Camera.main.transform.position = cameraPositions[index].position;
Camera.main.transform.rotation = cameraPositions[index].rotation;
}
Camera subCamera;
public void ChangeCamera(Camera subCamera)
{
this.subCamera = subCamera;
//ここから追加
backPanel.SetActive(true);
//ここまで
Camera.main.gameObject.SetActive(false);
}
//ここから追加
public void OnBackButton()
{
backPanel.SetActive(false);
this.subCamera.gameObject.SetActive(false);
Camera.main.gameObject.SetActive(true);
}
//ここまで
}
ポイント解説
public void ChangeCamera(Camera subCamera)
{
//↓
this.subCamera = subCamera;
なぜthisを使うのか?
ローカル変数とフィールド変数を区別するため
メソッドの引数やローカル変数の名前がクラスのフィールド変数と同じ場合、thisを使うことでクラスのフィールド変数であることを明示的に区別できます。
Camera subCamera; //フィールド変数
public void ChangeCamera(Camera subCamera //ローカル変数)
{
this.subCamera = subCamera;
//ここから追加
backPanel.SetActive(true);
//ここまで
Camera.main.gameObject.SetActive(false);
}
ローカル変数
ローカル変数は、ZoomObjから受け取った引数で、このメソッドの中だけで使える一時的なもの。
フィールド変数
フィールド変数は、クラス内のすべてのメソッドからアクセス可能で、このクラス(CameraManager
)が存在している間は保持されます。
フィールド変数を定義することで、受け取ったChangeCameraメソッド以外でもsubCameraを使うことができる
スクリプトを実行できるようにする
CameraManagerの項目にBackPanelをアタッチ

BackPanelのボタンにCameraManagerをドラッグし、OnBackButtonを選択


実行してみる
ズームした後BackPanelを押すとエラーが出る

MainCameraが非表示になっていて切り替えることができないのが原因らしい。

CameraManagerを修正する
エラーを回避するためにCameraManagerを修正します
- Startメソッドに「mainCamera = Camera.main;」を追加し、メインカメラを保持します。
- フィールド変数として「Camera mainCamera;」を定義します。
- 各箇所の「Camera.main」を「mainCamera」に変更します。
using UnityEngine;
public class CameraManager : MonoBehaviour
{
[SerializeField] GameObject backPanel;
public static CameraManager instance;
private void Awake()
{
instance = this;
}
[SerializeField] Transform[] cameraPositions = default;
int currentIndex = 0;
void Start()
{
currentIndex = 0;
// メインカメラを一度だけ取得し、mainCameraに保持することで再利用可能にする
mainCamera = Camera.main;
SetCameraPosition(currentIndex);
}
public void TurnRight()
{
currentIndex ++;
if (currentIndex >= cameraPositions.Length)
{
currentIndex = 0;
}
SetCameraPosition(currentIndex);
}
public void TurnLeft()
{
currentIndex--;
if (currentIndex < 0)
{
currentIndex = cameraPositions.Length -1;
}
SetCameraPosition(currentIndex);
}
void SetCameraPosition(int index)
{
// Camera.main→mainCameraに変更
mainCamera.transform.position = cameraPositions[index].position;
mainCamera.transform.rotation = cameraPositions[index].rotation;
}
Camera subCamera;
// MainCameraをフィールド変数として定義し、一度だけ検索して再利用する
Camera mainCamera;
public void ChangeCamera(Camera subCamera)
{
this.subCamera = subCamera;
backPanel.SetActive(true);
// Camera.main→mainCameraに変更
mainCamera.gameObject.SetActive(false);
}
public void OnBackButton()
{
backPanel.SetActive(false);
this.subCamera.gameObject.SetActive(false);
// Camera.main→mainCameraに変更
mainCamera.gameObject.SetActive(true);
}
}
ポイント解説
StartメソッドでMainCameraを一度だけ検索し、mainCamera フィールドに保持します。これにより、それ以降はmainCameraを直接操作できるため、毎回検索処理を行う必要がなくなり、効率的なコードになります。
実行
できたけど、ズームした時に左右のボタンがあるのはよくない
ズーム時のUIを調整
ドアにズームした際、左右のボタンは必要ないので表示させないようにする
左右のPanelをまとめる
まずは左右のパネルをまとめます。
CreateEmpty→名前を「MovePanels」にする
RightPanel、LeftPanelをMovePanelsにまとめる

CameraManagerを修正する
[SerializeField]でMovePanelsを取得し、ChangeCameraとOnBackButtonそれぞれにMovePanelsを非表示,表示させるようにする
using UnityEngine;
public class CameraManager : MonoBehaviour
{
[SerializeField] GameObject backPanel;
// MovePanelsを取得
[SerializeField] GameObject movePanels;
public static CameraManager instance;
private void Awake()
{
instance = this;
}
[SerializeField] Transform[] cameraPositions = default;
int currentIndex = 0;
void Start()
{
currentIndex = 0;
mainCamera = Camera.main;
SetCameraPosition(currentIndex);
}
public void TurnRight()
{
currentIndex ++;
if (currentIndex >= cameraPositions.Length)
{
currentIndex = 0;
}
SetCameraPosition(currentIndex);
}
public void TurnLeft()
{
currentIndex--;
if (currentIndex < 0)
{
currentIndex = cameraPositions.Length -1;
}
SetCameraPosition(currentIndex);
}
void SetCameraPosition(int index)
{
mainCamera.transform.position = cameraPositions[index].position;
mainCamera.transform.rotation = cameraPositions[index].rotation;
}
Camera subCamera;
Camera mainCamera;
public void ChangeCamera(Camera subCamera)
{
this.subCamera = subCamera;
backPanel.SetActive(true);
mainCamera.gameObject.SetActive(false);
// MovePanelsを非表示
movePanels.SetActive(false);
}
public void OnBackButton()
{
backPanel.SetActive(false);
this.subCamera.gameObject.SetActive(false);
mainCamera.gameObject.SetActive(true);
// MovePanelsを表示
movePanels.SetActive(true);
}
}
CameraManagerに項目にMovePanelsをアタッチ

完成

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