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

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


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が特定のレイヤーのオブジェクトのみを検出または無視するように設定できます。
  • 遠隔での検出はできるが、接触では何もしないなどの場合にコライダー同士の演算の有無を登録します

3.1 コライダーマトリックスの設定

Physicsのコライダーマトリックスを設定することで、特定のレイヤー間での物理衝突を制御できます。これにより、不要な物理計算を減らし、パフォーマンスを向上させることができます。

  • コライダーマトリックスのアクセス:
    • メニューから EditProject Settings... を選択します。
    • 左側のリストから Physics を選択します。
    • Layer Collision Matrix が表示されます。
  • コライダーマトリックスの設定:
    • Layer Collision Matrix では、各レイヤー間の物理衝突を有効または無効にできます。
    • 以下のように設定します
  • 設定の保存:
    • 設定は自動的に保存されます。Project Settings ウィンドウを閉じて次に進みます。

注意点:

  • コライダーマトリックスは物理エンジンの衝突計算に影響を与えますが、Raycastの検出には直接影響しません。Raycastはレイヤーマスクに基づいて動作しますが、物理衝突の最適化に役立ちます。
  • OnTriggerイベントやOnCollisionイベントの発生をできなくすることができます。
    今回は実験用にコードは記載していません。

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; // レイがヒットするレイヤー
       public LayerMask obstacleLayers; // 障害物のレイヤー

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

           // 障害物を先にチェック
           if (Physics.Raycast(transform.position, direction, out RaycastHit hitObstacle, distanceToPlayer, obstacleLayers))
           {
               Debug.Log("障害物がPlayerとEnemyの間にあります。");
               // 障害物がある場合、Playerは検出されない
               return;
           }

           // Playerをチェック
           if (Physics.Raycast(transform.position, direction, out RaycastHit hitPlayer, maxDistance, hitLayers))
           {
               if (hitPlayer.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 を選択します(存在しない場合は新規作成します)。
  • タグの作成方法:
    • Tag ドロップダウン → Add Tag... を選択。
    • Tags リストに Player を追加。
    • Player オブジェクトに戻り、Tag ドロップダウンから Player を選択します。

スクリプトの設定:

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

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

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

スクリプトの理解:

  • スクリプト内で2回のRaycastを行います:
    1. ObstacleのRaycast: PlayerとEnemyの間に障害物が存在するかを確認します。
    2. PlayerのRaycast: 障害物がない場合にPlayerを検出します。

コライダーマトリックスの活用:

  • 既にコライダーマトリックスでEnemyとPlayer間の物理衝突を無効にしていますが、Raycast自体はレイヤーマスクによって制御されています。これにより、Raycastのパフォーマンスが向上し、不要な衝突計算を避けることができます。

実行結果の確認:

  • プレイモードでシーンを実行し、Enemy1 から Player に向かってRayが飛んでいることを確認します。
  • シナリオ1: Obstacleが存在しない場合、Playerが検出されます。
  • シナリオ2: Obstacleを配置してPlayerとEnemyの間に置くと、Playerが検出されなくなります。

動作確認の手順:

  • Obstacleの有無による挙動:
    • Obstacle をシーンから削除または非表示にして、Playerが正常に検出されることを確認します。
    • Obstacle をシーンに配置して、Playerが検出されないことを確認します。
  • 複数の障害物や敵の存在:
    • シーンに複数の障害物や敵を配置して、Raycastの挙動を確認します。必要に応じてレイヤーマスクやコライダーマトリックスを調整します。

6. まとめ

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

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

これらの知識を活用して、より複雑なゲームロジックやAIの実装に挑戦してみてください。特に、レイヤーとコライダーマトリックスの適切な設定は、プロジェクトのパフォーマンスと管理において非常に重要です。


実行結果サンプル

配置サンプル

レイヤーのマトリックスのテスト

PlayerにRigidbodyを追加し、Enemy1の真上に移動しておきます
実行すると、コライダーの演算が行われず、すり抜けて落下していきます

追加リソース


トラブルシューティング

  • Raycastが期待通りに動作しない:
    • レイヤーマスクが正しく設定されているか確認してください。
    • オブジェクトが正しいレイヤーに割り当てられているか確認します。
    • Obstacle の配置が適切か、Raycastの方向と距離が正しいか確認します。
  • パフォーマンスの問題:
    • 不要なレイヤー間の物理衝突をコライダーマトリックスで無効にすることで、物理計算の負荷を軽減できます。
    • Raycastの頻度や最大距離を適切に設定し、不要なRaycastを避けます。

さらなる学習

  • 複雑なRaycastの使用方法:
    • 複数のRaycastを組み合わせて広範囲をカバーする。
    • Physics.RaycastAll を使用して複数のヒット情報を取得し、優先順位に基づいて処理する。
  • レイヤーマスクの応用:
    • 複数のレイヤーを組み合わせて、より細かい制御を行う。
    • スクリプト内で動的にレイヤーマスクを変更する方法。
  • AIの実装:
    • Raycastを活用して、敵キャラクターの視覚的な範囲や攻撃範囲を設定する。
    • 障害物を考慮したパスファインディングや追跡ロジックの構築。

これらのトピックを学ぶことで、より高度なゲーム開発スキルを身につけることができます。継続的に学習し、実際にプロジェクトで試してみることをお勧めします!

Unity,当たり判定

Posted by hidepon