はじめに
FPSカメラを実装していると、カメラに映ったアイテムをピックアップしたいときに、
「目の前にあるアイテムの情報が欲しい!」と思う場面があります。
今回はRayという機能を使い視線の先にあるオブジェクトを検出。
さらに、検出したオブジェクトを取得して操作する方法をご紹介します。
Raycastとは?
イメージで言いますと、指定した場所から、指定した方向へ向けて、レーザーを飛ばして
レーザーが衝突したモノを検出する機能です。
これを利用して、実装していきます。
RaycastはColliderにしか反応しない
Raycastはすべてのオブジェクトに反応してくれるわけじゃありません。
Scene上のColliderがアタッチされているオブジェクトにのみ反応するので、注意しましょう。
スクリプトを作成
「PlayerRay.cs」というスクリプトを作ってみました。スクリプトファイル名は何でもいいです。
スクリプトの中身は以下の通りです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerRay : MonoBehaviour
{
[SerializeField] Camera fpsCam; // カメラ
[SerializeField] float distance = 0.8f; // 検出可能な距離
// Start is called before the first frame update
void Start(){ }
// Update is called once per frame
void Update()
{
// Rayはカメラの位置からとばす
var rayStartPosition = fpsCam.transform.position;
// Rayはカメラが向いてる方向にとばす
var rayDirection = fpsCam.transform.forward.normalized;
// Hitしたオブジェクト格納用
RaycastHit raycastHit;
// Rayを飛ばす(out raycastHit でHitしたオブジェクトを取得する)
var isHit = Physics.Raycast(rayStartPosition, rayDirection, out raycastHit, distance);
// Debug.DrawRay (Vector3 start(rayを開始する位置), Vector3 dir(rayの方向と長さ), Color color(ラインの色));
Debug.DrawRay(rayStartPosition, rayDirection * distance, Color.red);
// なにかを検出したら
if (isHit)
{
// LogにHitしたオブジェクト名を出力
Debug.Log("HitObject : " + raycastHit.collider.gameObject.name);
}
}
}
各行の解説をします。
どのカメラからRayをとばす?
[SerializeField] Camera fpsCam; // カメラ
実際にFPSカメラとして機能しているカメラの座標をもとにRayを利用したいので、[SerializeField]としてCameraを用意します。
どれだけの距離を調べる?
[SerializeField] float distance = 0.8f; // 検出可能な距離
Rayを飛ばす距離をここで指定します。[SerializeField]にすることで、オブジェクトにアタッチした後もinspectorからの調整を容易にします。
Rayの開始地点
ここからUpdate関数の中身についてです。
// Rayはカメラの位置からとばす
var rayStartPosition = fpsCam.transform.position;
ここでは、Rayを利用するために必要な「Rayの開始地点座標」をFPSカメラから取得しています。
Rayの発射方向
// Rayはカメラが向いてる方向にとばす
var rayDirection = fpsCam.transform.forward.normalized;
ここでは、Rayを開始点からどの方向に飛ばすかのベクトルをFPSカメラから取得しています。
方向だけわかればよいので、nomalizedを利用して正規化しています。
衝突オブジェクト用変数
// Hitしたオブジェクト格納用
RaycastHit raycastHit;
ここではRayが何かオブジェクトに衝突したとき、何に衝突したのかを格納しておく箱を用意しています。
Rayを発射して調べる
var isHit = Physics.Raycast(rayStartPosition, rayDirection, out raycastHit, distance);
Raycastを実際に利用している場所です。
各引数の意味は以下の通りです。
rayStartPosition ・・・ワールド座標でのレイの開始地点
rayDirection ・・・レイの方向
out raycastHit ・・・レイが衝突したオブジェクトの情報を取得
distance ・・・レイの距離
そして、衝突したか否かの結果を「isHit」で受け取っています。
デバッグ用に色付きレーザー発射
// Debug.DrawRay (Vector3 start(rayを開始する位置), Vector3 dir(rayの方向と長さ), Color color(ラインの色));
Debug.DrawRay(rayStartPosition, rayDirection * distance, Color.red);
Raycastは不可視です。確認することができません。
そこで、デバッグ用にRaycastと同じ場所から、同じ方向、同じ距離にむかって色付きのレーザーを発射させて、確認できるようにしています。
もちろん、デバッグ用なので本番リリースの時には、この個所は削除してください。
衝突したオブジェクトを操作
// なにかを検出したら
if (isHit)
{
// LogにHitしたオブジェクト名を出力
Debug.Log("HitObject : " + raycastHit.collider.gameObject.name);
}
「isHit」には、このフレームで、RayにオブジェクトがHitしたかどうかが格納されているので、これで判定できます。
Hitしたオブジェクトには「raycastHit.collider.gameObject」から操作しましょう。
スクリプトをアタッチ
作成したスクリプトを、FPSコントローラーにアタッチしましょう。
アタッチしたら、Inspectorの「Fps Cam」にカメラをセットしましょう。
今回は、StandardAssetsのFPSControllerを使用しているので、
「FpsCam」には、Cameraコンポーネントを持っている、「FirstPersonCharacter」をセットしてください。
結果
デバッグ用のレーザーも出ていますし
Logには、Hitしたオブジェクトの名前が出力されています。
正常に動いています。
以上です。
コメント