見出し画像

【Unity】ミニマップを自作してみよう(3Dプロジェクト版)

アセットストアで買うのもいいけど、簡単に実装できるからやってみよう

ゲームを開発する際、ミニマップを実装することは、プレイヤーがゲーム内での位置を把握しやすくするための重要な機能です。
アセットストアでミニマップ実装アセットが販売されていますが
せっかくなら自作してみようかな、ということで作成してみました
この記事では、ミニマップの基本的な設定に加えて、プレイヤーや敵の位置をマップ上に表示するためのスクリプトを詳しく解説します。


1. ミニマップの基礎設定

前置きはこの辺で今回は実装手順をどんどん書いていきますので
参考にしてみてください
まず、ミニマップの基礎となるカメラとUIを設定します。

1.1 ミニマップカメラの作成

  1. 新しいカメラを作成
    Unityのヒエラルキーで右クリックし、Create > Cameraを選択して新しいカメラを作成します。このカメラは、ミニマップ専用のカメラとして機能します。

  2. カメラの設定
    カメラを選択し、インスペクターで以下の設定を行います:

    • 名前: MinimapCamera と名付けます。

    • Projection: Orthographic(平行投影)を選択します。

    • Position: カメラをプレイヤーの真上に配置します(例: Y軸に10~20)
      まぁ実際は後でスクリプトで制御しますので適当でOKです

    • Rotation: X軸を90度に設定し、カメラが真下を向くようにします。

    • Culling Mask: ミニマップに表示したいオブジェクトだけを表示するように設定します。

1.2 ミニマップUIの設定

次に、ミニマップを表示するためのUIを設定します。

  1. Canvasの作成
    ヒエラルキーで右クリックし、Create > UI > Canvasを選択してキャンバスを作成します。このキャンバスがミニマップの表示領域になります。

  2. Canvasの設定
    作成したキャンバスをMinimapCanvasと命名し、以下の設定を行います:

    • Render Mode: Screen Space - Overlayに設定します。
      これにより、ミニマップが常に画面の上に表示されるようになります。

  3. Raw Imageの追加
    MinimapCanvasの子オブジェクトとしてRaw Imageを追加し、MinimapRawImageと命名します。これがミニマップの表示領域となります。

  4. Render Textureの設定
    MinimapCameraのインスペクターでTarget Textureを設定し、新しいRender Textureを作成して割り当てます。このRender TextureをMinimapRawImageのTextureフィールドに設定します。これにより、ミニマップカメラの映像がMinimapCanvas上に表示されます。

2. ミニマップ用ポインターの作成とプレファブ化

ミニマップ上に表示されるプレイヤーや敵の位置を示すポインターを作成し、それをプレファブ化して再利用できるようにします。

2.1 ポインター(UI)の作成

  1. イメージオブジェクトの作成
    ヒエラルキーで右クリックし、Create > UI > Imageを選択して新しいイメージオブジェクトを作成します。このオブジェクトがミニマップ上のポインターとして機能します。

  2. ポインターの設定
    作成したイメージオブジェクトに次の設定を行います:

    • 名前: プレイヤー用にはPlayerPointer、敵用にはEnemyPointerと命名します。

    • Source Image: インスペクターのImageコンポーネントで、適切なスプライト(例えば、青い丸や赤い丸)を設定します。これがミニマップ上で表示されるアイコンになります。

    • サイズ: RectTransformのWidthとHeightを調整して、ポインターのサイズを設定します。通常は10x10ピクセル程度に設定します。

  3. ポインターの配置
    ポインターオブジェクトをMinimapCanvasの子オブジェクトとして配置します。これにより、ミニマップ上で正しく表示されるようになります。

2.2 ポインターのプレファブ化

  1. ポインターをプレファブ化
    作成したPlayerPointerやEnemyPointerオブジェクトをプロジェクトビューにドラッグして、プレファブとして保存します。これにより、複数のシーンで簡単に再利用できるようになります。

  2. プレファブの利用
    今後、他のシーンやオブジェクトでこのポインタープレファブを利用する際には、プロジェクトビューからプレファブをヒエラルキーにドラッグするだけで使用できます。

3. スクリプトによるミニマップ制御

ミニマップの基本設定とポインターの作成が完了したら、プレイヤーの位置をミニマップ上で表示し、動的に敵キャラクターの位置を反映するためのスクリプトを実装します。
今回は全部で3つのスクリプトを作成します、
内容がわからない方はとりあえずコピペで作成してみましょう

3.1 プレイヤーポインターフォローの実装

プレイヤーが移動するとき、ミニマップ上で常にプレイヤーの位置が中央に表示されるようにするスクリプトを実装します。

using UnityEngine;

public class PlayerPointerFollow : MonoBehaviour
{
    public Transform player; // プレイヤーのTransform
    public RectTransform canvasRect; // ミニマップキャンバスのRectTransform
    public Vector3 offset = new Vector3(0, 5, 0); // プレイヤーの上に表示するオフセット

    void Start()
    {
        // playerがnullの場合、"Player"タグを持つオブジェクトを探す
        if (player == null)
        {
            GameObject playerObject = GameObject.FindGameObjectWithTag("Player");
            if (playerObject != null)
            {
                player = playerObject.transform;
            }
            else
            {
                Debug.LogError("Playerタグが付いたオブジェクトが見つかりませんでした。");
            }
        }
    }

    void Update()
    {
        if (player != null && canvasRect != null)
        {
            // ワールド座標をビューポート座標に変換
            Vector2 viewportPosition = Camera.main.WorldToViewportPoint(player.position + offset);
            Vector2 worldObjectScreenPosition = new Vector2(
                (viewportPosition.x * canvasRect.sizeDelta.x) - (canvasRect.sizeDelta.x * 0.5f),
                (viewportPosition.y * canvasRect.sizeDelta.y) - (canvasRect.sizeDelta.y * 0.5f)
            );

            // ポインタの位置を更新
            GetComponent<RectTransform>().anchoredPosition = worldObjectScreenPosition;
        }
    }
}

アタッチ方法:

  • PlayerPointerFollow スクリプトは、ミニマップ上でプレイヤーを表示するポインター(UIオブジェクト)にアタッチします。このポインターはMinimapCanvasの子オブジェクトとして配置します

3.2 ミニマップカメラフォローの実装

ミニマップカメラがプレイヤーの上に追従し、プレイヤーの動きに合わせて常に同じ視点を保つようにします。

using UnityEngine;

public class MinimapCameraFollow : MonoBehaviour
{
    public Transform player; // プレイヤーのTransform
    public Vector3 offset = new Vector3(0, 10, 0); // カメラの位置をプレイヤーからのオフセットで調整

    void LateUpdate()
    {
        if (player != null)
        {
            // プレイヤーの位置に基づいてカメラの位置を更新
            Vector3 newPosition = player.position + offset;
            newPosition.y = offset.y; // Y軸だけは固定
            transform.position = newPosition;
        }
    }
}

アタッチ方法:

  • MinimapCameraFollow スクリプトは、ミニマップ用のカメラオブジェクト(MinimapCamera)にアタッチします。これにより、ミニマップカメラがプレイヤーの位置に追従するようになります。

3.3 エネミーポインターマネージャーの実装

ミニマップ上で、敵キャラクターの位置を赤いポインターで表示するスクリプトです。プレイヤーの位置を基準にして、敵の相対的な位置を計算し、ミニマップ上で動的に表示します。

using UnityEngine;
using System.Collections.Generic;

public class EnemyPointerManager : MonoBehaviour
{
    public GameObject enemyPointerPrefab; // 敵ポインタのプレハブ
    private RectTransform minimapRect; // MinimapMaskのRectTransform
    private Transform player; // プレイヤーのTransform
    private Camera minimapCamera; // ミニマップ専用のカメラ
    public float mapScale = 1.0f; // マップのスケール調整

    private Dictionary<GameObject, GameObject> enemyPointerMap = new Dictionary<GameObject, GameObject>();

    void Start()
    {
        // MinimapMaskのRectTransformを自動的に設定
        minimapRect = GameObject.Find("MinimapMask")?.GetComponent<RectTransform>();
        if (minimapRect == null)
        {
            Debug.LogError("MinimapMaskが設定されていません。");
        }

        // プレイヤーオブジェクトを自動的に設定
        player = GameObject.FindGameObjectWithTag("Player")?.transform;
        if (player == null)
        {
            Debug.LogError("Playerタグが付いたオブジェクトが見つかりませんでした。");
        }

        // ミニマップカメラを自動的に設定
        minimapCamera = GameObject.Find("MinimapCamera")?.GetComponent<Camera>();
        if (minimapCamera == null)
        {
            Debug.LogError("ミニマップカメラが設定されていません。");
        }
    }

    void Update()
    {
        GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");

        foreach (GameObject enemy in enemies)
        {
            if (!enemyPointerMap.ContainsKey(enemy))
            {
                GameObject pointer = Instantiate(enemyPointerPrefab, minimapRect);
                enemyPointerMap[enemy] = pointer;
            }

            // 敵の相対位置を計算
            Vector3 relativePosition = enemy.transform.position - player.position;

            // カメラのY軸回転を考慮して相対位置を回転
            Vector3 rotatedPosition = Quaternion.Euler(0, -minimapCamera.transform.eulerAngles.y, 0) * relativePosition;

            // ミニマップのサイズとスケーリングを調整して位置を計算
            float scale = minimapRect.sizeDelta.x / (2 * minimapCamera.orthographicSize * mapScale);
            Vector2 minimapPosition = new Vector2(
                rotatedPosition.x * scale,
                rotatedPosition.z * scale
            );

            // ポインタの位置を更新
            enemyPointerMap[enemy].GetComponent<RectTransform>().anchoredPosition = minimapPosition;
        }

        // 存在しない敵オブジェクトに対応するポインタを削除
        List<GameObject> keysToRemove = new List<GameObject>();
        foreach (var pair in enemyPointerMap)
        {
            if (pair.Key == null)
            {
                Destroy(pair.Value);
                keysToRemove.Add(pair.Key);
            }
        }
        foreach (var key in keysToRemove)
        {
            enemyPointerMap.Remove(key);
        }
    }
}

アタッチ方法:

  • EnemyPointerManager スクリプトは、ミニマップ上で敵の位置を示す赤いポインターを管理するオブジェクトにアタッチします。このオブジェクトはミニマップの表示領域(MinimapCanvas)の子オブジェクトとして配置します

スクリプトの説明

  • MinimapMaskのRectTransform設定: スクリプトがシーン内のMinimapMaskオブジェクトを自動的に探して設定します。このマスクは、ミニマップの表示領域を制限するために使用されます。

  • プレイヤーオブジェクトの設定: スクリプトがシーン内で"Player"タグが付いたオブジェクトを探し、プレイヤーのTransformを設定します。

  • ミニマップカメラの設定: スクリプトがシーン内のMinimapCameraを自動的に探し出して設定し、ミニマップカメラの視点に基づいて敵の位置をミニマップ上に表示します。

  • 敵の相対位置計算と回転の補正: プレイヤーの位置を基準に、敵の相対位置を計算します。さらに、ミニマップカメラのY軸の回転を考慮して、相対位置を正確にミニマップ上に反映させます。

  • 動的ポインタ管理: スクリプトは敵キャラクターが動くたびにその位置を更新し、倒された敵に対応するポインターを削除します。

まとめ

この記事では、Unityでミニマップを実装し、プレイヤーや敵の位置をミニマップ上に動的に表示する方法について解説しました。
今回はプレイヤーキャラクター周辺状況を操作する人が把握できるような仕組みのミニマップです、死角になる背後の敵の位置などを簡易に直感的につかんでもらうのが目的です、そのためカーナビのようにメインカメラのカメラ方向にミニマップの向きも同期するようなプログラムを作りました
こういったタイプのミニマップはFPSやMMORPGなどで使えると思います。
別のタイプでMOBAなどミニマップが固定されていて、かつ全体が見渡せる必要があるミニマップは少しカスタマイズが必要になりますね。
また、いま私が作っているゲームでは立体的なダンジョンを探索するものなのでこれも少し工夫が必要です。
いずれにしてもこの記事で紹介した手法をカスタムすることで実装ができますので、有料アセットを買う前に一度自作を検討してみてください!

今後も、実用性のあるシステムの記事を書いていきますので参考になったらフォローもお願いいたします!


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