Unity 6の2Dで複数の地点を順番に巡回する方法(配列とインデックス)
この記事は「Unity 6 2D移動の総合ガイド」の一部です。前の記事では、2つの地点を往復しました。今回は、地点をいくつでも増やせる巡回の仕組みを作ります。敵の巡回や、NPCの移動に利用できます。
この記事で分かること
- 配列(
Transform[])で、複数の地点をまとめて扱う方法 - インデックスで、「今どの地点を目指しているか」を管理する方法
- 最後の地点の次に、最初に戻る方法
1. 完成する動き
4つの地点を用意し、オブジェクトが順番に巡回します。
Point0
↓
Point1
↓
Point2
↓
Point3
↓
Point0に戻る
2. 準備
共通の準備は総合ガイドの「共通の準備」をご覧ください。前の記事のPingPongMoveが付いている場合は、取り外してください。
① 4つの地点を作る
Hierarchyで空のGameObject(Create Empty)を4つ作り、次のように配置します。
| 名前 | Positionの例 |
|---|---|
| Point0 | (-4, 3, 0) |
| Point1 | (4, 3, 0) |
| Point2 | (4, -3, 0) |
| Point3 | (-4, -3, 0) |
四角形を描くように並べると、巡回の動きが分かりやすくなります。Z座標はすべて0にします。
② 移動するオブジェクトを用意する
Squareを使い、PositionをPoint0と同じ位置にしておきます。この記事もTransformを直接動かす方法なので、Rigidbody 2Dは不要です。
3. スクリプトを作る
PatrolMoveという名前でスクリプトを作り、移動するオブジェクトに取り付けます。
PatrolMove.cs
using UnityEngine;
public class PatrolMove : MonoBehaviour
{
[SerializeField] Transform[] points;
[SerializeField] float speed = 3f;
int currentIndex = 0;
void Update()
{
if (points == null || points.Length == 0)
return;
Transform target = points[currentIndex];
if (target == null)
return;
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
);
if (Vector3.Distance(
transform.position,
target.position) < 0.01f)
{
currentIndex++;
if (currentIndex >= points.Length)
{
currentIndex = 0;
}
}
}
}
Inspectorで地点を登録する
スクリプトを取り付けると、InspectorにPointsという欄が表示されます。
Pointsを開くSizeを4にする- 表示されたElement 0〜3に、Point0〜Point3を順番にドラッグして登録する
登録する順番が、巡回する順番になります。ゲームを再生すると、四角形を描くように巡回します。
4. コードの解説
① 配列:Transform[] points
配列は、同じ型のデータを並べてまとめて持つ仕組みです。前の記事ではpointAとpointBを別々の変数にしていました。この方法だと、地点を増やすたびに変数を増やす必要があります。配列にすれば、地点が何個でも、コードを変えずに対応できます。
配列の中身は、points[0]、points[1]のように番号を使って取り出します。番号は0から始まることに注意してください。4つある場合、番号は0、1、2、3です。
② インデックス:currentIndex
配列の「何番目の地点を目指しているか」を表す、番号です。この番号をインデックスと呼びます。
Transform target = points[currentIndex];
インデックスを使って、現在の目的地を取り出しています。インデックスを変えるだけで、目的地を切り替えられます。
③ 次の地点へ進む
currentIndex++;
インデックスを1増やす処理です。到着したときに実行することで、次の地点を目指すようになります。
if (currentIndex >= points.Length)
{
currentIndex = 0;
}
最後の地点に到着したあと、インデックスが配列の長さ以上になったら、0に戻します。これにより、最後の地点の次に最初の地点へ戻り、ループします。このチェックがないと、配列の範囲外を参照してエラーになります。
④ 安全のためのチェック
if (points == null || points.Length == 0)
return;
地点が1つも登録されていないときは、何もせずに処理を終えます。さらに、target == nullのチェックで、登録欄が空(None)の場合も防いでいます。
補足:余りを使った書き方
次の書き方でも、同じ動きになります。
currentIndex = (currentIndex + 1) % points.Length;
%は余りを求める演算子です。最後の番号に1を足して配列の長さと同じになると、余りが0になり、最初の地点へ戻ります。1行で書けて便利ですが、初めのうちは、本文のif文の方が読みやすいでしょう。
5. よくあるつまずき
| 症状 | 確認すること |
|---|---|
| 何も動かない | PointsのSizeが0になっていないか |
| 途中で止まる | ElementのどれかがNone(未登録)になっていないか |
| エラー「IndexOutOfRangeException」 | ゲームの再生中にSizeを減らさない。減らすときは、再生を止めてから変更する |
| 巡回の順番が想定と違う | Elementの登録順を確かめる |
| 画面外へ出てしまう | 各地点と移動するオブジェクトのZ座標がそろっているか |
6. 練習問題
- 地点を5つに増やして、コードを変えずに巡回できることを確かめてみましょう
- 巡回地点をランダムに選ぶようにしてみましょう
ヒント(2つ目)
Random.Range(0, points.Length)で、ランダムなインデックスを選べます。- 整数を使うときの
Random.Rangeは、後ろの数(第2引数)を含みません。 - 同じ地点を連続で選んでしまうと、動かなく見える点に注意しましょう。
解答例:ランダムに巡回する(まず自分で試してから見ましょう)
到着したところの処理を、次のように変えます。
if (Vector3.Distance(
transform.position,
target.position) < 0.01f)
{
if (points.Length > 1)
{
int next = currentIndex;
// 今と同じ地点にならないように、選び直す
while (next == currentIndex)
{
next = Random.Range(0, points.Length);
}
currentIndex = next;
}
}
地点が1つしかないときは、whileが終わらなくなるため、points.Length > 1のチェックを入れています。
7. まとめ
- 配列で、複数の地点をまとめて扱える
- インデックスで、目的地を切り替えられる
- インデックスが最後を超えたら、0に戻してループさせる
次の記事では、プレイヤーを追いかける敵の移動を作ります。










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