【Unity】タワーディフェンス(11) 砲台を配置するときにアイコンを追随させる【クソゲー制作】

タワーディフェンスを作る(11)

Unity初心者による2Dタワーディフェンス制作、第11回です。今回は砲台を設置するときにマウスカーソルに砲台アイコンを追随させる処理を実装します。

環境
  • Mac mini (M1, 2020)
  • Unity 2022.3.36f1
目次

マウスカーソルに砲台アイコンを追随させる

マウスに追随する砲台アイコンを用意

STEP

ヒエラルキーで右クリック「2D Object > Sprites > Square」を選択してオブジェクトを作成します。名前を「TurretIcon」にします。

タワーディフェンス130
STEP

TurretIconオブジェクト上でで右クリック「2D Object > Sprites > Square」を選択してTurretIconの配下にオブジェクトを作成します。名前を「TurretHead」にします。

タワーディフェンス131
STEP

TurretIconのインスペクターで「SpriteRenderer > Sprite」に砲台の台座の画像(turret_base1)をドラッグ&ドロップしてアサインします。

「SpriteRenderer > Color」でRGBAのAの値を200にします。これで画像が半透明になります。

「SpriteRenderer > Additional Settings > Sorting Layer」「Object」にし、「Order in Layer」0にします。

タワーディフェンス132
STEP

TurretHeadのインスペクターで「SpriteRenderer > Sprite」に砲台の砲身の画像(turret4)をドラッグ&ドロップしてアサインします。

「SpriteRenderer > Color」でRGBAのAの値を200にします。

「SpriteRenderer > Additional Settings > Sorting Layer」「Object」にし、「Order in Layer」1にします。

タワーディフェンス133

Order in Layerは同じSorting Layer内での重なり順を指定します。この設定で、砲台の台座の上に砲身が表示されるようになります。

STEP

TurretIconのインスペクターで左上のチェックを外し、オブジェクトを非表示にしておきます。

タワーディフェンス134

TurretGeneratorスクリプトの修正

STEP

TurretGeneratorスクリプトを修正します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps; // Tilemapを使うために必要な宣言

public class TurretGenerator : MonoBehaviour
{
    [SerializeField]
    private GameObject turretPrefab; // 砲台のプレハブ
    [SerializeField]
    private Grid grid; // Grid_BaseのGrid、Tilemapの座標を取得するため
    [SerializeField]
    private Tilemap tilemaps; // Grid_WayのTilemap
    // ここから 変数追加
    [SerializeField]
    private GameObject selectedTurretIcon; // 追随する砲台アイコン
    [SerializeField]
    private GameObject selectedTurretHead; // 追随する砲台アイコンの砲身
    // ここまで
    private Vector3Int gridPos;  // Tilemapのセル座標
    private HashSet<Vector3Int> occupiedCells = new HashSet<Vector3Int>(); // 砲台配置済みセルを代入
    private TurretSetting.TurretData selectedTurretData = null; // 選択された砲台のデータ

    void Update()
    {
        // ここから 追加
        // マウスカーソルの位置にアイコンを配置
        Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        selectedTurretIcon.transform.position = new Vector3(mouseWorldPos.x, mouseWorldPos.y, 0);
        // ここまで
        if (Input.GetMouseButtonDown(0)) // 画面をクリックしたら
        {
            // ...省略...
        }
    }

    /// <summary>
    /// 砲台生成
    /// </summary>
    /// <param name="gridPos"></param>
    private void GenerateTurret(Vector3Int gridPos)
    {
        // ...省略...
        // ここから 追加
        selectedTurretIcon.SetActive(false); // 追随アイコンを非表示
        // ここまで
    }

    /// <summary>
    /// 砲台を選択する
    /// </summary>
    public void SelectTurret(int index)
    {
        selectedTurretData = DBManager.instance.turretSetting.turretDataList[index];
        Debug.Log($"{selectedTurretData.name} を選択");
        // ここから 追加
        // アイコンを表示
        selectedTurretIcon.SetActive(true);
        // 砲身のスプライトを設定
        SpriteRenderer iconRenderer = selectedTurretHead.GetComponent<SpriteRenderer>();
        iconRenderer.sprite = selectedTurretData.turretHeadSprite;
        // ここまで
    }
}
STEP

TurretGeneratorオブジェクトのインスペクターで「Turret Generator (Script) > Selected Turret Icon」にTurretIconオブジェクトをドラッグ&ドロップしてアサイン します。

同じく「Turret Generator (Script) > Selected Turret Head」にTurretHeadオブジェクトをドラッグ&ドロップしてアサイン します。

タワーディフェンス135

以上で、砲台を設置するときに半透明の砲台アイコンがマウスカーソルに追随するようになりました。いえい。

砲台アイコンをタイルにスナップさせる

マウスカーソルがマップ上を彷徨っているときに砲台アイコンがタイルにスナップしたら、砲台がどこに設置されるかわかりやすいですよね。

TurretGeneratorスクリプトを修正します。

public class TurretGenerator : MonoBehaviour
{
    // ...省略...

    void Update()
    {
        // ここから
        /*
        // マウスカーソルの位置にアイコンを配置
        Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        selectedTurretIcon.transform.position = new Vector3(mouseWorldPos.x, mouseWorldPos.y, 0);
        if (Input.GetMouseButtonDown(0)) // 画面をクリックしたら
        {
            // クリック位置のスクリーン座標をワールド座標に変換しそれをセル座標に変換
            gridPos = grid.WorldToCell(Camera.main.ScreenToWorldPoint(Input.mousePosition));
            // クリックしたタイルのコライダーがNoneならば
            if (tilemaps.GetColliderType(gridPos) == Tile.ColliderType.None)
            {
                // 砲台を生成
                GenerateTurret(gridPos);
            }
        }
        */
        // マウスカーソルの位置を取得
        Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        // グリッドのセル座標にスナップ
        gridPos = grid.WorldToCell(mouseWorldPos);
        Vector3 snappedWorldPos = grid.CellToWorld(gridPos);
        // タイルの中心に調整
        selectedTurretIcon.transform.position = new Vector3(snappedWorldPos.x + 0.5f, snappedWorldPos.y + 0.5f, 0);
        if (Input.GetMouseButtonDown(0)) // 画面をクリックしたら
        {
            // クリックしたタイルのコライダーがNoneならば
            if (tilemaps.GetColliderType(gridPos) == Tile.ColliderType.None)
            {
                // 砲台を生成
                GenerateTurret(gridPos);
            }
        }
        // ここまで
    }

    // ...省略...
}

以上で、砲台アイコンがマップのタイルにスナップするようになりました。いえい。

砲台が設置できない場合にアイコンにバツ印を表示

砲台を設置できないタイル上でアイコンにバツ印を表示します。

STEP

TurretIconオブジェクト上で右クリック「2D Object > Sprites > Square」を選択してオブジェクトを作成します。名前を「TurretCross」にします。

STEP

インスペクターの「Sprite Renderer > Sprite」にバツ印のアイコンをドラッグ&ドロップしてアサインします。

サイズや色をいい感じに調整します。

タワーディフェンス136
STEP

インスペクターの「Sprite Renderer > Additional Settings > Sorting Layer」「Object」に、「Order in Layer」「2」に設定します。

これでバツ印が砲台アイコンの最前面に表示されます。

STEP

インスペクターの左上のチェックを外してオブジェクトを非表示にしておきます。

タワーディフェンス137
STEP

TurretGeneratorスクリプトを修正します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps; // Tilemapを使うために必要な宣言

public class TurretGenerator : MonoBehaviour
{
    [SerializeField]
    private GameObject turretPrefab; // 砲台のプレハブ
    [SerializeField]
    private Grid grid; // Grid_BaseのGrid、Tilemapの座標を取得するため
    [SerializeField]
    private Tilemap tilemaps; // Grid_WayのTilemap
    [SerializeField]
    private GameObject selectedTurretIcon; // 追随する砲台アイコン
    [SerializeField]
    private GameObject selectedTurretHead; // 追随する砲台アイコンの砲身
    // ここから 変数追加
    [SerializeField]
    private GameObject selectedTurretCross; // バツ印のオブジェクト
    // ここまで
    private Vector3Int gridPos;  // Tilemapのセル座標
    private HashSet<Vector3Int> occupiedCells = new HashSet<Vector3Int>(); // 砲台配置済みセルを代入
    private TurretSetting.TurretData selectedTurretData = null; // 選択された砲台のデータ

    void Update()
    {
        // マウスカーソルの位置を取得
        Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        // グリッドのセル座標にスナップ
        gridPos = grid.WorldToCell(mouseWorldPos);
        Vector3 snappedWorldPos = grid.CellToWorld(gridPos);
        // タイルの中心に調整
        selectedTurretIcon.transform.position = new Vector3(snappedWorldPos.x + 0.5f, snappedWorldPos.y + 0.5f, 0);
        // ここから
        /*if (Input.GetMouseButtonDown(0)) // 画面をクリックしたら
        {
            // クリックしたタイルのコライダーがNoneならば
            if (tilemaps.GetColliderType(gridPos) == Tile.ColliderType.None)
            {
                // 砲台を生成
                GenerateTurret(gridPos);
            }
        }*/
        // 設置可能かチェック
        bool canPlace = (tilemaps.GetColliderType(gridPos) == Tile.ColliderType.None) && !occupiedCells.Contains(gridPos);
        // バツ印の表示切り替え
        selectedTurretCross.SetActive(!canPlace);
        if (Input.GetMouseButtonDown(0) && canPlace) // 設置可能な場合のみ
        {
            // 砲台を生成
            GenerateTurret(gridPos);
        }
        // ここまで
    }

    /// <summary>
    /// 砲台生成
    /// </summary>
    /// <param name="gridPos"></param>
    private void GenerateTurret(Vector3Int gridPos)
    {
        // ...省略...
    }

    /// <summary>
    /// 砲台を選択する
    /// </summary>
    public void SelectTurret(int index)
    {
        // ...省略...
    }
}
STEP

TurretGeneratorオブジェクトのインスペクターで「Turret Generator (Script) > Selected Turret Cross」にTurretCrossオブジェクトをドラッグ&ドロップしてアサインします。

タワーディフェンス138

設置できない場所をクリックしたときに選択解除

サイドバーの砲台アイコンを選択中に、砲台を設置できない場所をクリックしたら選択を解除するようにします。

TurretGeneratorスクリプトを次のように修正します。

public class TurretGenerator : MonoBehaviour
{
    // ...省略...

    void Update()
    {
        // ...省略...
        // ここから
        /*if (Input.GetMouseButtonDown(0) && canPlace) // 設置可能な場合のみ
        {
            // 砲台を生成
            GenerateTurret(gridPos);
        }*/
        if (Input.GetMouseButtonDown(0)) // マウスボタンが押されたとき
        {
            if (canPlace) // 設置可能なら
            {
                GenerateTurret(gridPos); // 砲台を生成
            }
            else // 設置不可なら
            {
                selectedTurretData = null; // 選択中の砲台データをリセット
                selectedTurretIcon.SetActive(false); // 砲台アイコンを非表示
            }
        }
        // ここまで
    }

    // ...省略...
}

動作確認

ゲームを再生して動作確認をします。

以下の機能が実装されました。

  • マウスカーソルに砲台アイコンが追随
  • 砲台アイコンがタイルにスナップ
  • 設置できないタイルではアイコンにバツ印
  • 設置できないタイルでクリックすると選択解除

さいごに

砲台アイコンをタイルにスナップさせる方法、自分で考えてみてもまったくわからなかったのですが、ChatGPT氏に訊いたら一発でした。便利な時代になりました。

でわでわ

タワーディフェンスを作る(11)

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次