UnityでRaycastとIsTriggerを組み合わせてアニメーションを再生する方法

Unity

はじめに

Unityでは、RaycastとIsTriggerを組み合わせることで、プレイヤーの位置と視線の両方を条件にして、オブジェクトのアニメーションを再生できます。

今回は、プレイヤーが扉の近くにいる状態で、扉に視線を向けてクリックすると、開くアニメーションが再生される仕組みを作成します。

Raycastで扉を検知し、IsTriggerでプレイヤーが操作可能な範囲内にいるかを判定します。


扉とアニメーションを準備する

今回は、これまでの記事で作成した扉とアニメーションを使用します。

扉の作成やColliderの設定、アニメーションの準備については、以下の記事を参考にしてください。

  • IsTriggerを使ってアニメーションを再生する方法
UnityでIs Triggerに入ったときにアニメーションを再生する方法
UnityでIs Triggerに入ったときにアニメーションを再生する方法を解説。Playerタグの設定からAnimatorのステートや遷移条件、スクリプトの実装まで紹介します。
  • Raycastを使ってアニメーションを再生する方法
UnityでRaycastを使ってアニメーションを再生する方法
UnityのRaycastを使って、カメラの正面にあるドアを判定し、マウスの左クリックで開くアニメーションを再生する方法を紹介します。Raycastによる判定方法やスクリプトの実装を解説します。

今回は、扉にColliderとAnimatorが設定され、AnimatorにOpenDoorというTriggerパラメーターが追加されている状態から進めます。

また、プレイヤーの接近を検知するためのTriggerエリアも準備しておきます。


RaycastとIsTriggerを組み合わせる

今回は、それぞれの機能を次のように使用します。

  • IsTrigger:プレイヤーが扉の近くにいるかを判定する
  • Raycast:プレイヤーが扉を見ているかを判定する

この2つの条件を満たした状態でクリックすると、扉のアニメーションが再生されるようにします。

IsTriggerでプレイヤーが範囲内にいることを確認してから、Raycastによる判定を行うのがポイントです。


スクリプトを作成する

今回は、次の3つのスクリプトを作成します。

スクリプト役割
PlayerRaycast.csRaycastで扉を見ているか判定
DoorTrigger.csIsTriggerでプレイヤーの接近を検知
DoorInteraction.cs2つの判定結果を組み合わせてアニメーションを再生

PlayerRaycast.csを作成する

まず、プレイヤーのカメラからRaycastを飛ばすためのスクリプトを作成します。

PlayerRaycast.csという名前で作成し、Playerにアタッチします。

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerRaycast : MonoBehaviour
{
    public Camera playerCamera;
    public DoorInteraction doorInteraction;
    public float rayDistance = 3f;

    void Update()
    {
        if (doorInteraction == null)
            return;

        doorInteraction.isLookingAtDoor = false;

        if (playerCamera == null || Mouse.current == null)
            return;

        if (!Mouse.current.leftButton.wasPressedThisFrame)
            return;

        Ray ray = new Ray(
            playerCamera.transform.position,
            playerCamera.transform.forward
        );

        if (Physics.Raycast(
            ray,
            out RaycastHit hit,
            rayDistance,
            Physics.DefaultRaycastLayers,
            QueryTriggerInteraction.Ignore))
        {
            Animator hitAnimator =
                hit.collider.GetComponentInParent<Animator>();

            if (hitAnimator == doorInteraction.doorAnimator)
            {
                doorInteraction.isLookingAtDoor = true;
            }
        }

        doorInteraction.CheckInteraction();
    }
}

このスクリプトでは、マウスの左クリックを押したときに、プレイヤーのカメラからRaycastを飛ばします。

まず、次の部分で左クリックされたかどうかを確認します。

if (!Mouse.current.leftButton.wasPressedThisFrame)
    return;

wasPressedThisFrameは、そのフレームでボタンが押されたかどうかを判定するプロパティです。

左クリックされていない場合は、ここで処理を終了します。

次に、Rayの発射位置と方向を指定します。

Ray ray = new Ray(
    playerCamera.transform.position,
    playerCamera.transform.forward
);

playerCamera.transform.positionでカメラの位置を取得し、playerCamera.transform.forwardでカメラの正面方向を指定しています。

続いて、Physics.RaycastでRayがColliderに当たったかどうかを判定します。

if (Physics.Raycast(
    ray,
    out RaycastHit hit,
    rayDistance,
    Physics.DefaultRaycastLayers,
    QueryTriggerInteraction.Ignore))

RaycastがColliderに当たると、条件が成立します。

rayDistanceはRaycastで判定する距離です。今回は3に設定しています。

また、QueryTriggerInteraction.Ignoreを指定することで、IsTriggerを有効にしたColliderをRaycastの検知対象から除外しています。

続いて、Raycastが当たったオブジェクトからAnimatorを取得します。

Animator hitAnimator =
    hit.collider.GetComponentInParent<Animator>();

GetComponentInParentを使用することで、Colliderが付いているオブジェクトだけでなく、その親オブジェクトに設定されているAnimatorも取得できます。

取得したAnimatorが操作対象の扉のAnimatorと一致した場合、isLookingAtDoorをtrueにします。

if (hitAnimator == doorInteraction.doorAnimator)
{
    doorInteraction.isLookingAtDoor = true;
}

最後に、次の処理でDoorInteraction.csのメソッドを呼び出します。

doorInteraction.CheckInteraction();

これにより、Raycastの判定結果をIsTriggerの判定結果と組み合わせて、扉を操作できるかどうかを確認します。

このように、左クリックしたときだけRaycastを実行し、扉に当たった場合に操作対象として判定します。


DoorTrigger.csを作成する

次に、プレイヤーが扉の操作範囲内にいるかどうかを判定するスクリプトを作成します。

DoorTrigger.csという名前で作成し、Triggerエリアにアタッチします。

using UnityEngine;

public class DoorTrigger : MonoBehaviour
{
    public DoorInteraction doorInteraction;

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            doorInteraction.isPlayerInRange = true;
        }
    }

    void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            doorInteraction.isPlayerInRange = false;
        }
    }
}

OnTriggerEnterは、別のColliderがTriggerの範囲に入ったときに呼び出されるメソッドです。

CompareTag("Player")でプレイヤーかどうかを判定し、プレイヤーであればisPlayerInRangeをtrueにします。

反対に、Triggerエリアから出るとOnTriggerExitが呼び出され、isPlayerInRangeがfalseになります。

これにより、プレイヤーが扉の操作範囲内にいるかどうかを判定できます。


DoorInteraction.csを作成する

最後に、RaycastとIsTriggerの判定結果を組み合わせ、扉のアニメーションを制御するスクリプトを作成します。

DoorInteraction.csという名前で作成し、扉にアタッチします。

using UnityEngine;

public class DoorInteraction : MonoBehaviour
{
    public Animator doorAnimator;

    public bool isPlayerInRange;
    public bool isLookingAtDoor;

    public void CheckInteraction()
    {
        if (!isPlayerInRange || !isLookingAtDoor)
            return;

        if (doorAnimator == null)
            return;

        doorAnimator.SetTrigger("OpenDoor");
    }
}

まず、次の部分で2つの判定結果を確認します。

if (!isPlayerInRange || !isLookingAtDoor)
    return;

isPlayerInRangeはIsTriggerによる判定、isLookingAtDoorはRaycastによる判定です。

どちらか一方でもfalseの場合は、ここで処理を終了します。

両方がtrueの場合は、次の処理に進みます。

doorAnimator.SetTrigger("OpenDoor");

SetTriggerでAnimatorのOpenDoorパラメーターを呼び出し、扉の開くアニメーションを再生します。

この処理は、Player側のPlayerRaycast.csから左クリックされたタイミングで呼び出されます。

これにより、プレイヤーが扉の操作範囲内にいて、扉に視線を向けた状態で左クリックした場合だけ、アニメーションを再生できます。


スクリプトを設定する

PlayerRaycast.csの設定

作成したPlayerRaycast.csをPlayerにアタッチします。

Inspectorで、次の項目を設定します。

  • Player Camera:プレイヤーのカメラを設定
  • Door Interaction:扉にアタッチしたDoorInteraction.csを設定
  • Ray Distance:Raycastで判定する距離を設定(今回は3)

DoorTrigger.csの設定

作成したDoorTrigger.csをTriggerエリアにアタッチします。

Inspectorで、次の項目を設定します。

  • Door Interaction:扉にアタッチしたDoorInteraction.csを設定

DoorInteraction.csの設定

作成したDoorInteraction.csをDoorにアタッチします。

Inspectorで、次の項目を設定します。

  • Door Animator:扉のAnimatorを設定

また、次の項目も確認してください。

  • プレイヤーのTagがPlayerになっていること
  • TriggerエリアのBox ColliderでIs Triggerが有効になっていること
  • プレイヤーとTriggerエリアのどちらかにRigidbodyが設定されていること
  • 扉にRaycastが当たるColliderが設定されていること

プレイヤーのColliderが子オブジェクトに付いている場合は、そのColliderが付いているGameObjectにもPlayerタグを設定してください。


動作を確認する

設定ができたら、実際に動作を確認します。

  1. プレイヤーが扉のTriggerエリアに入る。
  2. 扉に視線を向ける。
  3. マウスの左クリックを押す。
  4. 扉の開くアニメーションが再生される。

プレイヤーがTriggerエリアの外にいる場合や、扉から視線を外している場合は、クリックしてもアニメーションは再生されません。

なお、動画ではTriggerエリアに入ったことと、左クリックしたタイミングが分かるように、スクリプトにDebug.Log()を追加しています。

Debug.Log()でメッセージをConsoleに表示することで、それぞれの処理が実行されたタイミングを確認できます。


まとめ

今回は、RaycastとIsTriggerを組み合わせて、扉のアニメーションを再生する方法を紹介しました。

IsTriggerでプレイヤーの接近を検知し、Raycastで扉に視線を向けているかを判定することで、2つの条件を満たした場合だけ操作できる仕組みを作成できます。

それぞれの判定を別のスクリプトに分けることで、役割を整理しながら管理できます。