Unity 6の2Dでマウスでクリックした場所へ移動する(Mouse.currentとScreenToWorldPoint)
この記事は「Unity 6 2D移動の総合ガイド」の一部です。前の記事では、プレイヤーを追いかける敵を作りました。今回は、マウスでクリックした場所へキャラクターが移動する、シミュレーションゲームや見下ろし型RPGで使われる移動を作ります。
この記事で分かること
- Input Systemの
Mouse.currentで、マウスの状態を読み取る方法 - 画面上の座標を、ゲーム世界の座標に変換する方法(
ScreenToWorldPoint) - 「目的地を持っているか」を表す変数の使い方
1. 完成する動き
マウスの左ボタンで画面をクリックすると、オブジェクトがその場所へ向かって移動し、到着すると停止します。移動中に別の場所をクリックすると、目的地が変わります。
2. 前提と準備
共通の準備は総合ガイドの「共通の準備」をご覧ください。この記事では、特に次の点を確認してください。
- Input Systemの設定(Active Input Handling が「Input System Package (New)」または「Both」)
- Main Cameraのタグが
MainCameraになっている(初期設定のままであれば問題ありません) - Main CameraのPositionが(0, 0, -10)など、Z方向を向いた標準的な2Dシーンになっている
- 移動するオブジェクトのZ座標が0になっている
移動するオブジェクトは、Squareを使い、Positionを(0, 0, 0)にしておきます。この記事もTransformを直接動かす方法なので、Rigidbody 2Dは不要です。他の移動スクリプトが付いている場合は、取り外してください。
3. スクリプトを作る
ClickMoveという名前でスクリプトを作り、移動するオブジェクトに取り付けます。
ClickMove.cs
using UnityEngine;
using UnityEngine.InputSystem;
public class ClickMove : MonoBehaviour
{
[SerializeField] float speed = 4f;
Camera mainCamera;
Vector2 targetPosition;
bool hasTarget;
void Awake()
{
mainCamera = Camera.main;
}
void Update()
{
if (mainCamera == null ||
Mouse.current == null)
return;
if (Mouse.current.leftButton.wasPressedThisFrame)
{
Vector2 mousePosition =
Mouse.current.position.ReadValue();
Vector3 screenPosition = new Vector3(
mousePosition.x,
mousePosition.y,
-mainCamera.transform.position.z
);
Vector3 worldPosition =
mainCamera.ScreenToWorldPoint(screenPosition);
targetPosition = worldPosition;
hasTarget = true;
}
if (!hasTarget)
return;
Vector2 newPosition = Vector2.MoveTowards(
transform.position,
targetPosition,
speed * Time.deltaTime
);
transform.position = new Vector3(
newPosition.x,
newPosition.y,
transform.position.z
);
if (Vector2.Distance(
transform.position,
targetPosition) < 0.01f)
{
hasTarget = false;
}
}
}
ゲームを再生して、Gameビューをクリックしてみましょう。クリックした場所へ、オブジェクトが移動します。
4. コードの解説
① マウスを読み取る:Mouse.current
キーボードをKeyboard.currentで読み取ったのと同じように、マウスはMouse.currentで読み取ります。マウスが接続されていないときはnullになるため、先にnullチェックをしています。
| コード | 意味 |
|---|---|
Mouse.current.leftButton.wasPressedThisFrame | 左ボタンを押したフレームだけtrue |
Mouse.current.position.ReadValue() | マウスの画面上の位置(ピクセル単位) |
クリックは、押した瞬間に1回だけ反応してほしいため、isPressedではなくwasPressedThisFrameを使います。
② 画面の座標と、ゲーム世界の座標
マウスの位置は、画面上の座標(左下が(0, 0)で、ピクセル単位)です。一方、オブジェクトを動かすのはゲーム世界の座標(ユニット単位)です。この2つは別物なので、変換が必要です。
mainCamera.ScreenToWorldPoint(screenPosition)
このメソッドが、画面上の座標を、ゲーム世界の座標に変換します。
③ Zに-mainCamera.transform.position.zを指定する理由
Vector3 screenPosition = new Vector3(
mousePosition.x,
mousePosition.y,
-mainCamera.transform.position.z
);
ScreenToWorldPointには、「カメラからどれだけ先の位置か」を表すZの値も渡します。カメラが(0, 0, -10)にある場合、ゲーム世界のZ=0の平面は、カメラから10先にあります。そのため、-(-10)で、10を指定しています。
これにより、クリックした位置の、Z=0平面上の座標を取得できます。
ここでは、カメラがZ方向を向いた標準的な2Dシーンで、移動対象がZ=0平面にあることを前提としています。カメラを回転させたり、移動する平面を変えたりする場合は、別の座標計算が必要です。
④ 目的地を持っているか:hasTarget
hasTargetは、「目的地があるかどうか」を表す変数です。最初はfalseです。クリックするとtrueになり、到着するとfalseに戻ります。if (!hasTarget) return;と書くことで、目的地がないときは、移動の処理をスキップします。
⑤ 移動の処理
移動は、前の記事で使ったVector2.MoveTowards()と、Z座標をそのまま残す書き方です。到着は、Vector2.Distance()で判定しています。
5. よくあるつまずき
| 症状 | 確認すること |
|---|---|
| クリックしても動かない | Gameビューをクリックしているか。Active Input Handlingの設定 |
| NullReferenceException | Main CameraのタグがMainCameraか |
| クリックと違う場所へ動く | Main CameraのZ座標。オブジェクトのZ座標が0か |
| 画面外へ出ていく | カメラを回転させていないか |
| 勝手に動く | 他の移動スクリプトが付いたままになっていないか |
6. 練習問題
speedを変更して、動きの変化を確かめてみましょう- クリックした場所に「目印(マーカー)」を表示して、到着したら消すようにしてみましょう
ヒント(2つ目)
- 目印には、小さなSquareやCircleを用意しておき、最初は非表示(Inspectorでチェックを外す)にします。
- オブジェクトの表示・非表示は、
SetActive(true)とSetActive(false)で切り替えます。
解答例:マーカーを表示する(まず自分で試してから見ましょう)
フィールドに次を追加し、Inspectorでマーカーを登録します。
[SerializeField] Transform marker;
クリックしたところ(hasTarget = true;の行の後)に、次を追加します。
if (marker != null)
{
marker.position = new Vector3(
targetPosition.x,
targetPosition.y,
0f
);
marker.gameObject.SetActive(true);
}
到着したところ(hasTarget = false;の行の後)に、次を追加します。
if (marker != null)
{
marker.gameObject.SetActive(false);
}
7. まとめ
Mouse.currentで、マウスのボタンや位置を読み取れる- マウスの位置は画面座標なので、
ScreenToWorldPointでゲーム世界の座標へ変換する - Zには、カメラからZ=0平面までの距離を指定する
- 目的地の有無を、
hasTargetで管理する
次の記事では、力を加えて動かすAddForceを使います。











ディスカッション
コメント一覧
まだ、コメントがありません