クリック(スマホではタップ)したゲームオブジェクトを判定する方法

2022年8月22日

3Dオブジェクトをクリックした時、そのオブジェクトの参照を取得する方法について説明します
これは、FPS(First Person Shooting:一人称シューティングゲーム)で、Aimで照準を合わせ、弾を発射して当たり判定をする場合などに利用できます

チュートリアルを通して、検証してみましょう

サンプルプロジェクト

プロジェクトの作成

3Dアプリケーションを選択してTargetCheckという名前で作成します。

シーンをGameSceneとして、保存します。

標準では、SampleSceneとなっていますので、変更して保存しておきます

Cubeオブジェクトを2つ作成します。

名前をCube1Cube2にします。また、Positionをそれぞれ(0, 0, 0)と(3, 0, 0)としておきます。

GameControllerスクリプトを作成します。

スクリプト名GameManegerで作成します

3Dオブジェクトをマウスで左クリックすると、そのオブジェクトの情報が取得できます

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out RaycastHit hit))
        {
            Debug.Log("光線が当たったオブジェクトの情報");
            Debug.Log("名前: " + hit.transform.name);
            Debug.Log("位置: " + hit.transform.position);
            Debug.Log("距離: " + hit.distance);
        }
    }
}

マウスの状態取得

マウスボタンの状態(ボタンが押された瞬間)を取得するInputクラスのメソッドになります。
引数が0の場合は左ボタン、1が右ボタン、2が中ボタンの状態を取得できます
もし、ボタンが押されたら、このメソッドはtrueを返すので、if文が成り立つことになります。

Input.GetMouseButtonDown(0)

常にマウスの左ボタンをクリックされたかをチェックし、クリックされると処理が実行されるようにします。

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        // 処理
    }
}

座標について

スクリーン座標は、PCでは画面、スマホではパネルに当たります
左上が(0, 0)になります
また、別に3Dオブジェクトはx, y, zのワールド座標を持っています

スクリーン座標の取得

マウスカーソルの座標(スクリーン座標)を取得するプロパティになります

Input.mousePosition

Ray(光線)のオブジェクトを取得

MainCameraタグがついているカメラオブジェクトから、3Dオブジェクトまでの延長線(Ray)をオブジェクトとして取得するメソッドになります。引数は、スクリーン座標になります。

Ray ray = Camera.main.ScreenPointToRay(スクリーン座標);

今回は、マウスでクリックしたスクリーン座標を引数にします
マウスポイントの延長線にある3Dオブジェクトまでの光線になります

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

Rayからの情報を取得

rayオブジェクトが、3Dオブジェクトに衝突(Colliderに)した場合、そのオブジェクトの情報を取得するメソッドが用意されています。このRaycast()メソッドは多くのオーバーロードを持っていますが、今回は、2つの引数を持つものを選択します。第1引数には、rayを指定し、第2引数には、衝突してオブジェクトの情報が代入される変数を指定します。

bool success = Physics.Raycast(ray, out RaycastHit hit)

out修飾子がついていますが、これとよく似た使い方として、次のようなのがあります。これは、文字列の123をint型に変換するコードですが、戻り値として、成功したかどうかをsuccess変数に、また成功したときに結果をresult変数に代入するコードになります。

bool success = int.TryParse("123",out int result)

Raycastメソッドも同様にオブジェクトがヒットすると、hit変数にそのオブジェクトの情報が代入されます。また、取得に成功したかどうかは、success変数に代入されます。

hit変数からは、様々な情報を得ることができますが、今回は次のような情報を取得します。

Debug.Log("名前: " + hit.transform.name);
Debug.Log("位置: " + hit.transform.position);
Debug.Log("距離: " + hit.distance);

スクリプトのアタッチ

Unityエディタで、空のオブジェクトを作成し、このスクリプトをアタッチして実行してみましょう。
それぞれのCubeオブジェクトのクリックで、情報が取得できると思います。

クリックしたオブジェクトの色を変えてみる

ヒットしたオブジェクトにアタッチされているMeshRendererコンポーネント(描画するコンポーネント)のカラー情報を変更してみましょう
Cubeをクリックするとそのオブジェクトの色が変更されるはずです

hit.transform.GetComponent<MeshRenderer>().material.color = Color.green;

// 次でもいいです。transform.gameObjectでオブジェクト取得できます
// hit.transform.gameObject.GetComponent<MeshRenderer>().material.color = Color.green;

全コード

最終的に全体コードは次のようになります。

using UnityEngine;

public class GameManeger : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(ray, out RaycastHit hit))
            {
                Debug.Log("光線が当たったオブジェクトの情報");
                Debug.Log("名前: " + hit.transform.name);
                Debug.Log("位置: " + hit.transform.position);
                Debug.Log("距離: " + hit.distance);
                hit.transform.GetComponent<MeshRenderer>().material.color = Color.green;
            }
        }
    }
}

参考

カメラからのRay

Raycast構造体から得られるさまざまな情報

articulationBodyヒットしたコライダの ArticulationBody。コライダがアーティキュレーション ボディに接続されていない場合は、NULLになります。
barycentricCoordinateヒットした三角形の重心座標
colliderヒットしたコライダー
colliderInstanceIDヒットしたColliderのインスタンスID
distanceレイの原点から衝突点までの距離
lightmapCoord衝突点の UV ライトマップ座標
normalレイがヒットしたサーフェスの法線
pointレイがコライダーにヒットした位置 (ワールド空間)。
rigidbodyヒットしたコライダーの Rigidbody。コライダーに Rigidbody がアタッチされていない場合は null になります。
textureCoordコリジョン位置の uv テクスチャ座標
textureCoord2衝突したセカンダリ UV テクスチャの座標
transform衝突したコライダーまたは Rigidbody の Transform
triangleIndex衝突したメッシュの三角形におけるインデックス

関連

Unity

Posted by hidepon