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 Object
→Sphere
を選択します。名前を「Enemy1」に変更します。- 同様にもう一つのSphereを作成し、「Enemy2」に変更します。
Playerの作成:
Hierarchy
ウィンドウで右クリック →3D Object
→Capsule
を選択します。名前を「Player」に変更します。
Obstacleの作成:
Hierarchy
ウィンドウで右クリック →3D Object
→Cube
を選択します。名前を「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)
オブジェクトにレイヤーを割り当てる:
- 各オブジェクトを選択し、
Inspector
のLayer
ドロップダウンから対応するレイヤーを選択します。Enemy1
とEnemy2
→Enemy
Player
→Player
Obstacle
→Obstacle
レイヤーマスクの理解:
- レイヤーマスクを使用すると、Raycastが特定のレイヤーのオブジェクトのみを検出または無視するように設定できます。
- 遠隔での検出はできるが、接触では何もしないなどの場合にコライダー同士の演算の有無を登録します
3.1 コライダーマトリックスの設定
Physicsのコライダーマトリックスを設定することで、特定のレイヤー間での物理衝突を制御できます。これにより、不要な物理計算を減らし、パフォーマンスを向上させることができます。
- コライダーマトリックスのアクセス:
- メニューから
Edit
→Project Settings...
を選択します。 - 左側のリストから
Physics
を選択します。 Layer Collision Matrix
が表示されます。
- メニューから
- コライダーマトリックスの設定:
Layer Collision Matrix
では、各レイヤー間の物理衝突を有効または無効にできます。- 以下のように設定します
- 設定の保存:
- 設定は自動的に保存されます。
Project Settings
ウィンドウを閉じて次に進みます。
- 設定は自動的に保存されます。
注意点:
- コライダーマトリックスは物理エンジンの衝突計算に影響を与えますが、Raycastの検出には直接影響しません。Raycastはレイヤーマスクに基づいて動作しますが、物理衝突の最適化に役立ちます。
- OnTriggerイベントやOnCollisionイベントの発生をできなくすることができます。
今回は実験用にコードは記載していません。
4. Raycastの実装
Enemy1からPlayerに向かってRayを飛ばし、Enemy2や自身にヒットしないように設定します。また、Obstacleが間にある場合はPlayerを検出しないようにします。
スクリプトの作成:
Project
ウィンドウで右クリック →Create
→C# 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
を選択し、Inspector
のTag
ドロップダウンからPlayer
を選択します(存在しない場合は新規作成します)。
- タグの作成方法:
Tag
ドロップダウン →Add Tag...
を選択。Tags
リストにPlayer
を追加。Player
オブジェクトに戻り、Tag
ドロップダウンからPlayer
を選択します。
スクリプトの設定:
Enemy1
を選択し、Inspector
のEnemyRaycast
コンポーネントで以下を設定します:Player
フィールドにPlayer
オブジェクトをドラッグ&ドロップ。Hit Layers
フィールドでPlayer
レイヤーのみを選択します(レイヤーマスクを設定)。Obstacle Layers
フィールドでObstacle
レイヤーのみを選択します。
Hit Layers
およびObstacle Layers
の隣にあるドロップダウンをクリックし、対応するレイヤーにチェックを入れます。これにより、Raycastは指定されたレイヤーのオブジェクトのみを検出します。
5. 障害物の影響を考慮する
Obstacleが間にある場合、Playerを検出しないようにRaycastの設定を追加します。
スクリプトの理解:
- スクリプト内で2回のRaycastを行います:
- ObstacleのRaycast: PlayerとEnemyの間に障害物が存在するかを確認します。
- 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を活用して、敵キャラクターの視覚的な範囲や攻撃範囲を設定する。
- 障害物を考慮したパスファインディングや追跡ロジックの構築。
これらのトピックを学ぶことで、より高度なゲーム開発スキルを身につけることができます。継続的に学習し、実際にプロジェクトで試してみることをお勧めします!
ディスカッション
コメント一覧
まだ、コメントがありません