衝突判定とは
当たり判定と衝突判定
当たり判定(衝突判定)とは何か?
当たり判定(衝突判定)とは、ゲーム内でオブジェクト同士が接触または交差したことを検出する機能です。
この機能は、キャラクターが敵に攻撃を当てたり、アイテムを拾ったり、壁にぶつかったりする場面で重要です。
正確な当たり判定により、ゲームのリアリティとプレイヤーの体験が向上します。
今までのゲームでの当たり判定の方法
-
矩形(AABB)判定
- 2Dゲームでよく使われる方法です。オブジェクトを囲む軸に平行なバウンディングボックス(Axis-Aligned Bounding Box)を使用して、簡単な重なりをチェックします。
- 計算が軽量で高速ですが、複雑な形状には対応しにくいです。
-
円形判定
- 矩形判定と同様に、2Dゲームで使用されることが多いです。オブジェクトを囲む円(Circle)を用いて衝突を検出します。
- 計算が比較的軽量で、回転するオブジェクトにも適用しやすいですが、複雑な形状には向いていません。
-
ピクセルパーフェクト判定
- 高精度が求められる2Dゲームで用いられる手法です。各ピクセルレベルで衝突を確認するため、正確ですが、計算量が多くなります。
-
ポリゴン判定
- 3Dゲームで一般的に使用される方法です。オブジェクトのポリゴンメッシュを利用して、複雑な形状の衝突を検出します。
- 精度が高い一方で、計算負荷も大きくなります。
-
物理エンジンによる判定
- 物理エンジン(例:Box2D、Bullet、Havok)を利用して、リアルタイムでの当たり判定や物理挙動をシミュレーションします。
- 高精度でリアルな挙動が可能ですが、設定やチューニングが複雑です。
Unityでの当たり判定
Unityでは、当たり判定を行うために主にCollider
コンポーネントとRigidbody
コンポーネントが使用されます。これらを組み合わせて、オブジェクトの物理挙動や衝突を制御します。
- Collider: オブジェクトの物理的な境界を定義します。ボックス(Box Collider)、球(Sphere Collider)、カプセル(Capsule Collider)、メッシュ(Mesh Collider)など、さまざまな形状があります。
- Rigidbody: オブジェクトに物理的な挙動を付与します。重力、力、速度などの物理特性を制御します。
これから、UnityのColliderの詳細と実際の使用方法について説明します。
UnityのColliderの仕組み
Colliderの基本機能
-
衝突判定
- Colliderは物理エンジンと連携し、オブジェクト間の衝突を検出します。
- 複数の形状が用意されており、用途に応じて適切な形状のColliderを使用します。
-
Trigger機能
- ColliderにはTriggerモードがあり、オブジェクトが接触したときに物理的な衝突は発生せず、特定のイベントをトリガーできます。
- Triggerモードを有効にするには、
Is Trigger
プロパティをチェックします。
-
接触情報の取得
- 衝突が発生したときに、接触点や接触したオブジェクトの情報を取得することができます。これにより、衝突の詳細な状況を把握できます。
主なColliderの種類とその用途
-
Box Collider
- 直方体の形状を持つColliderです。一般的な四角形のオブジェクトに使用されます。
-
Sphere Collider
- 球形のColliderです。球状のオブジェクトや、丸みを帯びたオブジェクトに適しています。
-
Capsule Collider
- カプセル状のColliderです。キャラクターや円柱形のオブジェクトに使用されます。
-
Mesh Collider
- 複雑なメッシュ形状のColliderです。正確な形状のオブジェクトに使用しますが、計算負荷が高くなるため注意が必要です。
-
Wheel Collider
- 車両のタイヤに特化したColliderです。物理的な車両挙動をシミュレートするために使用されます。
-
Terrain Collider
- 地形データに基づいたColliderです。大規模な地形に対して使用します。
Colliderを使用する際の注意点
-
パフォーマンスの考慮
- 複雑な形状のCollider(特にMesh Collider)は計算負荷が高くなるため、パフォーマンスに注意が必要です。可能な限り簡素な形状のColliderを使用し、必要に応じて複数の単純なColliderを組み合わせることを検討します。
-
TriggerとCollisionの使い分け
-
Is Trigger
を有効にしたColliderは物理的な衝突を発生させませんが、接触イベントをトリガーします。必要に応じて使い分け、適切なイベント処理を行います。
-
-
Rigidbodyとの組み合わせ
- Collider単体では物理挙動は発生しません。物理挙動を持たせたい場合は、
Rigidbody
コンポーネントと組み合わせる必要があります。Rigidbody
を持たないオブジェクト同士の衝突は静的なものとして扱われます。
- Collider単体では物理挙動は発生しません。物理挙動を持たせたい場合は、
-
スケールの影響
- Colliderのスケールは、オブジェクトのTransformスケールによって影響を受けます。意図しない当たり判定が発生しないように、スケールの設定に注意します。
-
接触イベントの処理
-
OnCollisionEnter
、OnCollisionStay
、OnCollisionExit
といったメソッドを使用して、衝突イベントを処理します。また、OnTriggerEnter
、OnTriggerStay
、OnTriggerExit
を使用して、Triggerイベントを処理します。 - これらは全てC#スクリプト上で実装して、ColiderのついたGameObjectにAdd Compornentされた状態で機能します。
-
PysicsMaterialとは
Physics Material(物理マテリアル)は、Unityにおける物理挙動を制御するための素材です。
具体的には、オブジェクトの摩擦や反発係数を設定することで、物理的な挙動をカスタマイズすることができます。
Physics Materialの主なパラメータ
-
摩擦(Friction)
- Static Friction(静的摩擦):オブジェクトが静止しているときの摩擦力を設定します。高い値に設定すると、動き始めるのが難しくなります。
- Dynamic Friction(動的摩擦):オブジェクトが動いているときの摩擦力を設定します。高い値に設定すると、動きが遅くなります。
-
反発係数(Bounciness)
- オブジェクトが衝突したときの跳ね返りの度合いを設定します。高い値に設定すると、衝突時にオブジェクトが大きく跳ね返ります。
-
摩擦結合モード(Friction Combine)
- Average:接触する二つのオブジェクトの摩擦の平均値を使用します。
- Minimum:接触する二つのオブジェクトの摩擦のうち、低い方の値を使用します。
- Multiply:接触する二つのオブジェクトの摩擦を掛け合わせた値を使用します。
- Maximum:接触する二つのオブジェクトの摩擦のうち、高い方の値を使用します。
-
反発係数結合モード(Bounce Combine)
- 摩擦結合モードと同様に、接触するオブジェクトの反発係数の計算方法を指定します。
Physics Materialの使用例
-
氷の上を滑る
- 氷のように摩擦がほとんどない表面を作りたい場合、Dynamic FrictionとStatic Frictionを低く設定します。
-
ゴムのボール
- ゴムのボールのように衝突時に大きく跳ね返るオブジェクトを作りたい場合、Bouncinessを高く設定します。
-
砂の上を歩く
- 砂のように摩擦が高い表面を作りたい場合、Dynamic FrictionとStatic Frictionを高く設定します。
Physics Materialの設定方法
-
Physics Materialの作成
- プロジェクトウィンドウで右クリックして、
Create > Physics Material
を選択します。これにより、新しいPhysics Materialが作成されます。
- プロジェクトウィンドウで右クリックして、
-
Physics Materialのプロパティ設定
- 作成したPhysics Materialを選択し、インスペクターウィンドウでStatic Friction、Dynamic Friction、Bounciness、Friction Combine、Bounce Combineの各プロパティを設定します。
-
Colliderへの適用
- オブジェクトにアタッチされているCollider(例えば、Box Collider、Sphere Colliderなど)を選択し、インスペクターウィンドウの
Material
フィールドに作成したPhysics Materialをドラッグ&ドロップします。
- オブジェクトにアタッチされているCollider(例えば、Box Collider、Sphere Colliderなど)を選択し、インスペクターウィンドウの
C#スクリプトで機能を確認する
以下に、OnCollision
系とOnTrigger
系のイベントメソッドを使用したUnityのスクリプトのサンプルコードを示します。それぞれ名前が違うように、機能もそれぞれ違います。
このスクリプトでは、オブジェクトが衝突またはトリガーに入ったときの処理を示します。
OnCollision系のイベントメソッド
OnCollision
系のイベントメソッドは、物理的な衝突が発生したときに呼び出されます。これらのメソッドは、Colliderコンポーネントがアタッチされているオブジェクトが他のColliderを持つオブジェクトと物理的に衝突したときにトリガーされます。通常、オブジェクトの動きを制御するためにRigidbodyコンポーネントも必要です。
-
OnCollisionEnter(Collision collision)
- 2つのColliderが初めて接触したときに呼び出されます。このメソッドは、接触の開始時に一度だけ呼び出されます。
- 使用例:オブジェクトが地面に落ちたときにエフェクトを表示する、得点を計算するなど。
-
OnCollisionStay(Collision collision)
- 2つのColliderが接触し続けている間、毎フレーム呼び出されます。このメソッドは、接触が続いている間ずっと呼び出されます。
- 使用例:接触している間、ダメージを与え続ける、オブジェクトを押し続けるなど。
-
OnCollisionExit(Collision collision)
- 2つのColliderの接触が終了したときに呼び出されます。このメソッドは、接触が終了したときに一度だけ呼び出されます。
- 使用例:オブジェクトが跳ね返る、接触していたオブジェクトの色を元に戻すなど。
OnTrigger系のイベントメソッド
OnTrigger
系のイベントメソッドは、Colliderが「Trigger」モードに設定されているときに呼び出されます。Triggerモードでは、物理的な衝突は発生せず、接触イベントのみがトリガーされます。通常、オブジェクトにIs Triggerプロパティが設定されたColliderを持つオブジェクトに使用されます。
-
OnTriggerEnter(Collider other)
- ColliderがTrigger領域に入ったときに呼び出されます。このメソッドは、Trigger領域への進入時に一度だけ呼び出されます。
- 使用例:プレイヤーがアイテムを取得したときに効果を発動する、トラップが発動するなど。
-
OnTriggerStay(Collider other)
- ColliderがTrigger領域内にいる間、毎フレーム呼び出されます。このメソッドは、Trigger領域内にいる間ずっと呼び出されます。
- 使用例:プレイヤーがダメージゾーンにいる間ダメージを与える、一定範囲内でスキルを発動し続けるなど。
-
OnTriggerExit(Collider other)
- ColliderがTrigger領域から出たときに呼び出されます。このメソッドは、Trigger領域からの退出時に一度だけ呼び出されます。
- 使用例:プレイヤーがエリアから出たときに効果を停止する、特定の動作を終了するなど。
OnCollision系とOnTrigger系の違いと使い方
-
物理的な衝突 vs. トリガーイベント
- OnCollision系は、物理的な衝突が発生したときに呼び出されます。オブジェクトが実際に接触して反発や摩擦などの物理挙動が発生します。
- OnTrigger系は、Colliderが「Is Trigger」モードに設定されているときに呼び出されます。物理的な衝突は発生せず、接触イベントのみが発生します。
-
Rigidbodyの必要性
- OnCollision系では、少なくとも片方のオブジェクトにRigidbodyコンポーネントが必要です。
- OnTrigger系では、Rigidbodyコンポーネントは必須ではありませんが、少なくとも一方にRigidbodyがあると、より信頼性の高い動作が保証されます。
-
使われる場面
- OnCollision系は、物理的な影響を伴うイベント(例えば、オブジェクトがぶつかって跳ね返る、押されるなど)に適しています。
- OnTrigger系は、非物理的なイベント(例えば、アイテムのピックアップ、エリアへの侵入など)に適しています。
OnCollision系の使い方とシナリオ
-
物理的な衝突を扱う
- オブジェクト同士の衝突を検出し、物理的な反応を引き起こす場合に使用します。
- 例:キャラクターが壁にぶつかって止まる、敵がプレイヤーにぶつかってダメージを与える。
void OnCollisionEnter(Collision collision)
{
Debug.Log("OnCollisionEnter with " + collision.gameObject.name);
// 衝突したオブジェクトを赤くする
collision.gameObject.GetComponent<Renderer>().material.color = Color.red;
}
-
物理的な反応をトリガー
- オブジェクトが衝突したときにエフェクトやアニメーションを発動させる。
- 例:車が障害物に衝突したときに破壊エフェクトを発動。
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Obstacle")
{
Explode();
}
}
void Explode()
{
// 破壊エフェクトを表示
}
OnTrigger系の使い方とシナリオ
-
エリア進入の検出
- プレイヤーやオブジェクトが特定のエリアに入ったことを検出してイベントを発生させる場合に使用します。
- 例:プレイヤーがアイテムを拾った、チェックポイントに到達した。
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
Debug.Log("Player entered the trigger area.");
CollectItem();
}
}
void CollectItem()
{
// アイテムを収集する処理
}
-
トラップやイベントのトリガー
- プレイヤーやオブジェクトが特定のエリアに入ったときにトラップやイベントを発動させる。
- 例:プレイヤーが特定のエリアに入るとトラップが発動する。
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
ActivateTrap();
}
}
void ActivateTrap()
{
// トラップを発動させる処理
}
どちらをどのような実装で使うべきか
-
OnCollision系を使う場合
- 物理的な接触や力の反作用が重要な場面。
- オブジェクトが衝突して現実世界のような反応をシミュレートする必要がある場合。
- 例:車の衝突、物理演算によるオブジェクトの破壊、キャラクターのジャンプや落下。
-
OnTrigger系を使う場合
- イベントの発生や状態の変化を検出する場面。
- オブジェクト同士の物理的な反応が必要ない場合。
- 例:プレイヤーがアイテムを取得、エリアに入ったことでイベントが発生、ステージクリアの条件を満たす。
適切に使い分けることで、ゲーム内のさまざまなシナリオに対応し、スムーズでリアルな挙動を実現することができます。
サンプルシーンの設定
それでは、実際にどのような挙動をするのか、どのようなタイミングで機能するのかを確認していきたいと思います。
ここでのサンプルコードは、当たった時、当たっている時、離れた時を、OnColision系とOnTrigger系で分けて機能するようにしてあります。
OnTrigger系の機能を使うときは、IsTriggerにチェックを入れるのを忘れずに。
- Unityで新しいシーンを作成します。
- 地面としてPlaneを追加し、適当なサイズにスケールします。
- 動かすオブジェクトとしてCubeを追加します。このCubeにはRigidbodyコンポーネントを追加します。
- トリガー用のオブジェクトとして、別のCubeを追加し、このCubeのIs Triggerプロパティを有効にします。
- スクリプトを作成し、動かすCubeにアタッチします。
スクリプトコード
using UnityEngine;
public class CollisionAndTriggerExample : MonoBehaviour
{
// 衝突時のイベントメソッド
private void OnCollisionEnter(Collision collision)
{
Debug.Log("OnCollisionEnter: " + collision.gameObject.name);
// 衝突したオブジェクトの色を変える
collision.gameObject.GetComponent<Renderer>().material.color = Color.red;
}
private void OnCollisionStay(Collision collision)
{
Debug.Log("OnCollisionStay: " + collision.gameObject.name);
// 衝突している間、オブジェクトの色を青に変える
collision.gameObject.GetComponent<Renderer>().material.color = Color.blue;
}
private void OnCollisionExit(Collision collision)
{
Debug.Log("OnCollisionExit: " + collision.gameObject.name);
// 衝突が終わったらオブジェクトの色を元に戻す
collision.gameObject.GetComponent<Renderer>().material.color = Color.white;
}
// トリガー時のイベントメソッド
private void OnTriggerEnter(Collider other)
{
Debug.Log("OnTriggerEnter: " + other.gameObject.name);
// トリガーに入ったオブジェクトの色を緑に変える
other.gameObject.GetComponent<Renderer>().material.color = Color.green;
}
private void OnTriggerStay(Collider other)
{
Debug.Log("OnTriggerStay: " + other.gameObject.name);
// トリガーに入っている間、オブジェクトの色を黄色に変える
other.gameObject.GetComponent<Renderer>().material.color = Color.yellow;
}
private void OnTriggerExit(Collider other)
{
Debug.Log("OnTriggerExit: " + other.gameObject.name);
// トリガーから出たらオブジェクトの色を元に戻す
other.gameObject.GetComponent<Renderer>().material.color = Color.white;
}
}
スクリプトの説明
-
OnCollisionEnter: 他のオブジェクトと衝突したときに呼び出されます。ここでは、衝突したオブジェクトの色を赤に変更します。
-
OnCollisionStay: 他のオブジェクトと接触している間、毎フレーム呼び出されます。ここでは、接触しているオブジェクトの色を青に変更します。
-
OnCollisionExit: 他のオブジェクトとの衝突が終了したときに呼び出されます。ここでは、オブジェクトの色を元に戻します。
-
OnTriggerEnter: 他のオブジェクトがトリガーに入ったときに呼び出されます。ここでは、トリガーに入ったオブジェクトの色を緑に変更します。
-
OnTriggerStay: 他のオブジェクトがトリガー内にいる間、毎フレーム呼び出されます。ここでは、トリガー内にいるオブジェクトの色を黄色に変更します。
-
OnTriggerExit: 他のオブジェクトがトリガーから出たときに呼び出されます。ここでは、オブジェクトの色を元に戻します。
動作確認
- プレイモードにして、動かすCubeを地面に落とすなどして、他のオブジェクトと衝突させます。
- トリガーに設定したCubeに動かすCubeを近づけて、トリガーイベントを確認します。
- コンソールに衝突やトリガーのイベントメッセージが表示され、オブジェクトの色が変わることを確認します。
これにより、OnCollision
系とOnTrigger
系のイベントメソッドの基本的な使い方と動作が理解できると思います。
Discussion