Unity初心者による2Dタワーディフェンス制作、第11回です。今回は砲台を設置するときにマウスカーソルに砲台アイコンを追随させる処理を実装します。
- Mac mini (M1, 2020)
- Unity 2022.3.36f1
マウスカーソルに砲台アイコンを追随させる
マウスに追随する砲台アイコンを用意
ヒエラルキーで右クリック「2D Object > Sprites > Square」を選択してオブジェクトを作成します。名前を「TurretIcon」にします。

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

TurretIconのインスペクターで「SpriteRenderer > Sprite」に砲台の台座の画像(turret_base1)をドラッグ&ドロップしてアサインします。
「SpriteRenderer > Color」でRGBAのAの値を200にします。これで画像が半透明になります。
「SpriteRenderer > Additional Settings > Sorting Layer」を「Object」にし、「Order in Layer」を0にします。

TurretHeadのインスペクターで「SpriteRenderer > Sprite」に砲台の砲身の画像(turret4)をドラッグ&ドロップしてアサインします。
「SpriteRenderer > Color」でRGBAのAの値を200にします。
「SpriteRenderer > Additional Settings > Sorting Layer」を「Object」にし、「Order in Layer」を1にします。

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

TurretGeneratorスクリプトの修正
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;
// ここまで
}
}
TurretGeneratorオブジェクトのインスペクターで「Turret Generator (Script) > Selected Turret Icon」にTurretIconオブジェクトをドラッグ&ドロップしてアサイン します。
同じく「Turret Generator (Script) > Selected Turret Head」にTurretHeadオブジェクトをドラッグ&ドロップしてアサイン します。

以上で、砲台を設置するときに半透明の砲台アイコンがマウスカーソルに追随するようになりました。いえい。
砲台アイコンをタイルにスナップさせる
マウスカーソルがマップ上を彷徨っているときに砲台アイコンがタイルにスナップしたら、砲台がどこに設置されるかわかりやすいですよね。
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);
}
}
// ここまで
}
// ...省略...
}
以上で、砲台アイコンがマップのタイルにスナップするようになりました。いえい。
砲台が設置できない場合にアイコンにバツ印を表示
砲台を設置できないタイル上でアイコンにバツ印を表示します。
TurretIconオブジェクト上で右クリック「2D Object > Sprites > Square」を選択してオブジェクトを作成します。名前を「TurretCross」にします。
インスペクターの「Sprite Renderer > Sprite」にバツ印のアイコンをドラッグ&ドロップしてアサインします。
サイズや色をいい感じに調整します。

インスペクターの「Sprite Renderer > Additional Settings > Sorting Layer」を「Object」に、「Order in Layer」を「2」に設定します。
これでバツ印が砲台アイコンの最前面に表示されます。
インスペクターの左上のチェックを外してオブジェクトを非表示にしておきます。

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)
{
// ...省略...
}
}
TurretGeneratorオブジェクトのインスペクターで「Turret Generator (Script) > Selected Turret Cross」にTurretCrossオブジェクトをドラッグ&ドロップしてアサインします。

設置できない場所をクリックしたときに選択解除
サイドバーの砲台アイコンを選択中に、砲台を設置できない場所をクリックしたら選択を解除するようにします。
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氏に訊いたら一発でした。便利な時代になりました。
でわでわ
コメント