Menu
CoddyTech

巡回して追いかける

CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 52/63。

巡回中のガードは、プレイヤーを見つけるまでルートを歩き、追跡し、プレイヤーがいなくなるとルートに戻ります。どちらの動作も、ある地点に向かう同じ操舵を使うため、1つのメソッドで両方の移動を行えます。この歩哨は2つの持ち場の間を往復し、chaseRange内にいるプレイヤーを追跡します。

[SerializeField] private Transform pointA;
[SerializeField] private Transform pointB;
[SerializeField] private Transform player;
[SerializeField] private float speed = 2f;
[SerializeField] private float chaseRange = 5f;
private Rigidbody rb;
private Transform goal;

void Start()
{
    rb = GetComponent<Rigidbody>();
    goal = pointA;
}

void FixedUpdate()
{
    if (Flat(player.position - rb.position).magnitude < chaseRange)
    {
        WalkTo(player.position);
        return;
    }
    if (Flat(goal.position - rb.position).magnitude < 0.2f)
    {
        goal = goal == pointA ? pointB : pointA;
    }
    WalkTo(goal.position);
}

void WalkTo(Vector3 target)
{
    Vector3 dir = Flat(target - rb.position).normalized;
    rb.linearVelocity = new Vector3(dir.x * speed, rb.linearVelocity.y, dir.z * speed);
}

Vector3 Flat(Vector3 v)
{
    return new Vector3(v.x, 0f, v.z);
}

追跡の判定を最初に行い、その中のreturnで巡回コードをスキップするため、プレイヤーが近くにいるときは追跡が優先されます。goalはフィールドなので、歩哨は追跡中もその値を保持します。プレイヤーがいなくなると、向かっていた持ち場まで歩き続けます。

到着判定では、地面に沿った距離を測定します。持ち場は床の目印で、歩哨の中心はそこから1 unit上にあるため、高さを含めた距離は1未満にならず、歩哨は方向転換しません。この判定では、ちょうど0ではなく0.2未満を調べます。毎秒2 unitsの速度では、歩哨は1ステップごとに0.04 units移動するため、持ち場にぴったり到着することはほとんどありません。

challenge icon

チャレンジ

中級

警備ロボットが倉庫を巡回しています。Robotスクリプトを書きましょう。Inspectorから、waypoints(順番に並んだ4つの黄色いマーカーW0〜W3)、player、speed(4)、chaseRange(4)が設定されます。Playerスクリプトは準備できています。

  • nextという名前のintフィールドは、ロボットが向かっているウェイポイントのインデックスです。初期値は0です。
  • 巡回:waypoints[next]まで歩きます。地面に沿った距離で、そのウェイポイントまでの距離が0.2未満になったら、nextを次のウェイポイントに進め、最後のウェイポイントの次は0に戻します。
  • 追跡:地面に沿った距離でプレイヤーがchaseRange未満の間は、代わりにプレイヤーのところまで歩きます。
  • プレイヤーが離れたら、向かっていたウェイポイントであるwaypoints[next]まで進み続けます。
  • Rigidbodyの速度を地面に沿ってspeedに設定して移動し、y方向の速度は維持します。

Playを押して、巡回の一周を観察し、ロボットの進路を横切ってから、Checkを押します。

自分で試してみよう

using UnityEngine;

public class Robot : MonoBehaviour
{
    [SerializeField] private Transform[] waypoints;
    [SerializeField] private Transform player;
    [SerializeField] private float speed = 4f;
    [SerializeField] private float chaseRange = 4f;
    private Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        // プレイヤーが近くにいるときは追いかけ、そうでなければ巡回ルートを歩く
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

物理演算とゲームプレイのすべてのレッスン