Unity 6の2Dで指定した地点へ移動する方法(Vector3.MoveTowards)
この記事は「Unity 6 2D移動の総合ガイド」の一部です。前の記事までは、プレイヤーがキーで操作する移動でした。ここからは、敵やNPCのように、プログラムで動くキャラクターの移動を作ります。最初は、指定した地点へ向かって移動する、いちばん基本の動きです。
この記事で分かること
Vector3.MoveTowards()で、目的地へ向かって移動する方法- 目的地をInspectorから登録する方法
- 目的地を行き過ぎない理由
1. 完成する動き
ゲームを再生すると、オブジェクトが、あらかじめ置いたTargetの位置へ向かって移動し、到着すると停止します。
2. 準備
共通の準備は総合ガイドの「共通の準備」をご覧ください。
① 移動するオブジェクトを用意する
この記事はTransformを直接動かす方法なので、Playerをそのまま使えます。ただし、前の記事で付けたRigidbody 2Dが残っていると、重力で落ちてしまうことがあります。次のどちらかにしてください。
- Rigidbody 2Dと前の記事のスクリプト(
JumpMove)を取り外す - 新しいSquareを作り、名前を
Moverにする
② 目的地を作る
Hierarchyで右クリックしてCreate Emptyを選び、名前をTargetにします。空のGameObjectは見た目がないため、シーンビューでは座標だけが分かる目印として扱います。任意の位置(例:(5, 2, 0))に置きます。
位置が分かりにくい場合は、Inspectorの名前の横のアイコンをクリックして、アイコンをつけるとシーンビューで見やすくなります。
3. スクリプトを作る
TargetMoveという名前でスクリプトを作り、移動するオブジェクトに取り付けます。
TargetMove.cs
using UnityEngine;
public class TargetMove : MonoBehaviour
{
[SerializeField] Transform target;
[SerializeField] float speed = 3f;
void Update()
{
if (target == null)
return;
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
);
}
}
スクリプトを取り付けたあと、InspectorのTarget欄に、HierarchyのTargetをドラッグして登録します。ゲームを再生すると、オブジェクトがTargetへ向かって移動します。
このスクリプトはキー入力を使わないため、Input Systemの設定は関係ありません。
4. コードの解説
① [SerializeField] Transform target;
目的地を登録するための変数です。Transform型にすると、Hierarchyのオブジェクトをドラッグで登録できます。コードで座標を直接書くのではなく、シーン上で目的地をドラッグして調整できるのが利点です。
② if (target == null) return;
目的地が登録されていないときは、何もせずに処理を終えます。登録忘れでエラーが出続けるのを防げます。
③ Vector3.MoveTowards()
Vector3.MoveTowards(
現在位置,
目的地,
移動できる最大距離
);
現在位置から目的地に向けて、「最大距離」だけ近づいた位置を返します。ここでは最大距離にspeed * Time.deltaTimeを渡しているので、毎フレーム、速さに応じた距離だけ進みます。
目的地に近づいても、基本的には指定した速さのまま進みます。そして、目的地を行き過ぎることなく、ちょうど到着できます。到着後はその場に止まります。
④ Lerpとの違い
目的地へ向かう方法には、Vector3.Lerp()もあります。違いを比べておきましょう。
| MoveTowards | Lerp | |
|---|---|---|
| 第3引数 | 移動できる最大距離 | 0〜1の割合 |
| 動き | 一定の速さで進む | 目的地に近づくほど遅くなりやすい(使い方による) |
| このシリーズでの扱い | メインで使う | 必要に応じて紹介 |
一定の速さで目的地へ向かいたいときは、MoveTowardsが分かりやすいです。
5. 注意点:Z座標をそろえる
Vector3.MoveTowards()は、XとYだけでなくZ方向も含めて移動します。そのため、TargetとMoverのZ座標が異なっていると、Z方向にも動き、カメラの外へ出てしまうことがあります。
純粋な2Dゲームでは、すべてのオブジェクトのZ座標を0にそろえるのが基本です。ここでは、TargetとMoverのPositionのZがどちらも0になっていることを確認してください。
補足:Vector2版
Z座標を気にしたくない場合は、Vector2.MoveTowards()を使う方法もあります。
Vector2 newPosition = Vector2.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
);
transform.position = new Vector3(
newPosition.x,
newPosition.y,
transform.position.z
);
Vector2で計算してから、元のZ座標をそのまま残して代入します。この書き方は、後の「追いかける」記事でも使います。
6. よくあるつまずき
| 症状 | 確認すること |
|---|---|
| 何も動かない | InspectorのTarget欄が空になっていないか。Speedが0になっていないか |
| 落ちてしまう | Rigidbody 2Dが残っていないか |
| 画面から消える | TargetとMoverのZ座標がそろっているか |
| 目的地に近づいても震える | 他の移動スクリプトが付いていないか |
7. 練習問題
speedを変更して、動きの変化を確かめてみましょう- ゲームを再生したまま、SceneビューでTargetをドラッグして動かしてみましょう
- 目的地に到着したときに、Consoleに「到着」と表示してみましょう
ヒント
- 2つ目では、Targetの位置に合わせて、毎フレーム、目的地を読み直していることに注目しましょう。
- 3つ目では、距離を調べる
Vector3.Distance()と、メッセージを表示するDebug.Log()を使います。
解答例:到着の表示(まず自分で試してから見ましょう)
void Update()
{
if (target == null)
return;
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
);
if (Vector3.Distance(
transform.position,
target.position) < 0.01f)
{
Debug.Log("到着");
}
}
到着している間は、毎フレーム「到着」と表示され続けます。一度だけ表示したい場合は、「到着済み」を表す変数を用意するとよいです。
8. まとめ
Vector3.MoveTowards()で、一定の速さで目的地へ向かえる- 目的地を行き過ぎず、ちょうど到着できる
- 2DではZ座標をそろえるか、
Vector2版を使う
次の記事では、2つの地点を往復する移動を作ります。











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