Unityチュートリアル:Raycastで特定のオブジェクトのみを検出する方法

このチュートリアルでは、Unityを使用してシーン上に複数のオブジェクト(敵、プレイヤー、障害物)を配置し、Physics.Raycast を活用して特定のオブジェクト(プレイヤー)にのみヒットさせる方法を学びます。具体的には、Raycastが自身や他の敵オブジェクトにヒットしないようにし、障害物が存在する場合にはプレイヤーを検出しないように設定します。


1. プロジェクトのセットアップ

Unity Hubを開く:

  • 最新のUnityバージョンをインストールしていない場合は、Unityの公式サイトからダウンロードしてください。

新しいプロジェクトの作成:

  • Unity Hubで「新規プロジェクト」をクリックし、「3D」テンプレートを選択します。
  • プロジェクト名を「RaycastTutorial」とし、保存場所を指定して「作成」をクリックします。

2. オブジェクトの配置

シーンに必要なオブジェクト(Enemy1, Enemy2, Player, Obstacle)を配置します。

Enemy1とEnemy2の作成:

  • Hierarchy ウィンドウで右クリック → 3D ObjectSphere を選択します。名前を「Enemy1」に変更します。
  • 同様にもう一つのSphereを作成し、「Enemy2」に変更します。

Playerの作成:

  • Hierarchy ウィンドウで右クリック → 3D ObjectCapsule を選択します。名前を「Player」に変更します。

Obstacleの作成:

  • Hierarchy ウィンドウで右クリック → 3D ObjectCube を選択します。名前を「Obstacle」に変更します。

オブジェクトの配置:

  • Scene ビューで各オブジェクトを一直線上に配置します。例えば、X軸を基準に以下のように配置します。 オブジェクト 位置 (X, Y, Z) Enemy1 (-4, 0, 0) Enemy2 (-2, 0, 0) Obstacle (0, 0, 0) Player (2, 0, 0)
  • 各オブジェクトの Transform コンポーネントで位置を設定します。

カメラの調整:

  • Main Camera を選択し、Transform の位置を (0, 5, -10) に、回転を (30, 0, 0) に設定して全体を見渡せるようにします。

3. レイヤーの設定

Raycastが特定のレイヤーのオブジェクトのみを検出するように、各オブジェクトにレイヤーを割り当てます。

新しいレイヤーの作成:

  • Inspector ウィンドウで任意のオブジェクトを選択し、上部の Layer ドロップダウンをクリック → Add Layer... を選択します。
  • 以下のレイヤーを追加します:
    • Enemy (例:レイヤー8)
    • Player (例:レイヤー9)
    • Obstacle (例:レイヤー10)

オブジェクトにレイヤーを割り当てる:

  • 各オブジェクトを選択し、InspectorLayer ドロップダウンから対応するレイヤーを選択します。
    • Enemy1Enemy2Enemy
    • PlayerPlayer
    • ObstacleObstacle

レイヤーマスクの理解:

  • レイヤーマスクを使用すると、Raycastが特定のレイヤーのオブジェクトのみを検出または無視するように設定できます。

4. Raycastの実装

Enemy1からPlayerに向かってRayを飛ばし、Enemy2や自身にヒットしないように設定します。また、Obstacleが間にある場合はPlayerを検出しないようにします。

スクリプトの作成:

  • Project ウィンドウで右クリック → CreateC# Script を選択し、「EnemyRaycast」と命名します。
  • Enemy1 オブジェクトにこのスクリプトをドラッグ&ドロップしてアタッチします。

スクリプトの編集:

   using UnityEngine;

   public class EnemyRaycast : MonoBehaviour
   {
       public Transform player; // プレイヤーのTransformを設定
       public float maxDistance = 100f; // レイの最大距離
       public LayerMask hitLayers; // レイがヒットするレイヤー

       void Update()
       {
           // プレイヤーへの方向を計算
           Vector3 direction = player.position - transform.position;

           // レイキャストを実行
           if (Physics.Raycast(transform.position, direction, out RaycastHit hit, maxDistance, hitLayers))
           {
               if (hit.collider.gameObject.CompareTag("Player"))
               {
                   Debug.Log("Playerが検出されました!");
                   // ここにプレイヤーを検出した際の処理を追加
               }
               else
               {
                   Debug.Log("Playerは検出されていません。");
               }
           }
           else
           {
               Debug.Log("何もヒットしませんでした。");
           }

           // デバッグ用にレイを表示
           Debug.DrawRay(transform.position, direction.normalized * maxDistance, Color.red);
       }
   }

プレイヤーの設定:

  • Player オブジェクトにタグを設定します。
    • Player を選択し、InspectorTag ドロップダウンから Player を選択します(存在しない場合は新規作成)。

スクリプトの設定:

  • Enemy1 を選択し、InspectorEnemyRaycast コンポーネントで以下を設定します:
    • Player フィールドに Player オブジェクトをドラッグ&ドロップ。
    • Hit Layers フィールドで Player レイヤーのみを選択します(レイヤーマスクを設定)。
    レイヤーマスクの設定方法:
  • Hit Layers の隣にあるドロップダウンをクリックし、Player レイヤーにチェックを入れます。これにより、RaycastはPlayerレイヤーのオブジェクトのみを検出します。

5. 障害物の影響を考慮する

Obstacleが間にある場合、Playerを検出しないようにRaycastの設定を追加します。

レイヤーマスクの拡張:

  • EnemyRaycast スクリプトを修正して、Obstacleレイヤーも含めます。ただし、Playerのみを検出対象とします。
   using UnityEngine;

   public class EnemyRaycast : MonoBehaviour
   {
       public Transform player; // プレイヤーのTransformを設定
       public float maxDistance = 100f; // レイの最大距離
       public LayerMask hitLayers; // レイがヒットするレイヤー

       void Update()
       {
           // プレイヤーへの方向を計算
           Vector3 direction = player.position - transform.position;

           // レイキャストを実行
           if (Physics.Raycast(transform.position, direction, out RaycastHit hit, maxDistance, hitLayers))
           {
               if (hit.collider.gameObject.CompareTag("Player"))
               {
                   Debug.Log("Playerが検出されました!");
                   // ここにプレイヤーを検出した際の処理を追加
               }
               else
               {
                   Debug.Log("Playerは検出されていません。");
               }
           }
           else
           {
               Debug.Log("何もヒットしませんでした。");
           }

           // デバッグ用にレイを表示
           Debug.DrawRay(transform.position, direction.normalized * maxDistance, Color.red);
       }
   }

Obstacleの設定:

  • Obstacle オブジェクトの LayerObstacle に設定します。

レイヤーマスクの調整:

  • EnemyRaycast コンポーネントの Hit Layers フィールドで Player レイヤーのみを選択します。Obstacleレイヤーは選択しないことで、RaycastがObstacleにヒットした場合はPlayerに到達できなくなります。

スクリプトの改善(高度な方法):

  • 複数のレイヤーを考慮してRaycastを行い、ObstacleがPlayerとEnemyの間にあるかどうかを判断します。
   using UnityEngine;

   public class EnemyRaycast : MonoBehaviour
   {
       public Transform player;
       public float maxDistance = 100f;
       public LayerMask obstacleLayers; // 障害物のレイヤー

       void Update()
       {
           Vector3 direction = player.position - transform.position;
           float distance = Vector3.Distance(transform.position, player.position);

           // Obstacleを先にチェック
           if (Physics.Raycast(transform.position, direction, out RaycastHit hitObstacle, distance, obstacleLayers))
           {
               Debug.Log("障害物がPlayerとEnemyの間にあります。");
               return;
           }

           // Playerをチェック
           if (Physics.Raycast(transform.position, direction, out RaycastHit hitPlayer, maxDistance, LayerMask.GetMask("Player")))
           {
               if (hitPlayer.collider.gameObject.CompareTag("Player"))
               {
                   Debug.Log("Playerが検出されました!");
               }
           }
           else
           {
               Debug.Log("Playerは検出されていません。");
           }

           // デバッグ用にレイを表示
           Debug.DrawRay(transform.position, direction.normalized * maxDistance, Color.red);
       }
   }
  • スクリプトの設定:
    • Obstacle Layers フィールドに Obstacle レイヤーを選択します。
    • これにより、RaycastはまずObstacleにヒットするかを確認し、Obstacleがない場合にのみPlayerを検出します。

6. まとめ

このチュートリアルでは、以下のポイントを学びました:

  • オブジェクトの配置: シーン内に複数のオブジェクトを配置し、位置を調整する方法。
  • レイヤーの設定: オブジェクトにレイヤーを割り当て、Raycastの対象を制御する方法。
  • Raycastの実装: Physics.Raycast を使用して特定のオブジェクト(Player)にのみヒットさせる方法。
  • 障害物の考慮: 障害物が間にある場合にRaycastがPlayerを検出しないようにする方法。

Unity,当たり判定

Posted by hidepon