2Dゲームの物理でつまずくポイントは、だいたい決まっています。 キャラが着地の勢いで勝手に転ぶ。高速の弾が壁をすり抜ける。坂道や段差の角で引っかかる。——そしてこれらには全部、定番の直し方があります。
この記事では、2D物理の心臓部である Rigidbody2D と Collider2D の基本から、あるあるトラブルの対処、2Dプラットフォーマーの実装イディオムまでを解説します。
この記事でわかること
- 3Dとの違い——2D系コンポーネントは完全に別系統
Body Type(Dynamic/Kinematic/Static)の役割分担Collider2Dの使い分け——キャラにはCapsuleが定番の理由Is Triggerと衝突イベント(コイン取得・ダメージ判定)- あるあるトラブル3連発の直し方(転ぶ・すり抜ける・カクつく)
3Dと2Dの物理は「別世界」
Unityには3D用(PhysX)と2D用(Box2D)、2つの独立した物理エンジンが載っています。RigidbodyとRigidbody2D、BoxColliderとBoxCollider2Dは名前が似ているだけの別物で、互いに一切干渉しません。
「Rigidbodyを付けたのにOnCollisionEnter2Dが呼ばれない」——2D初心者の詰まりどころナンバーワンは、3D用コンポーネントの混入です。2Dゲームでは末尾に2Dが付く系統だけを使ってください。
Rigidbody2Dを付けたオブジェクトは2D物理エンジンの管理下に入り、重力で落ち、力で動き、他のオブジェクトと衝突するようになります。3D版との違いは次の2点です。
- XY平面で完結: Z軸方向の移動はありません。
- 回転は
float1個: 3DのQuaternionと違い、Z軸周りの回転角度だけを扱います。
Body Type:役割で選ぶ3タイプ
Rigidbody2Dの挙動はBody Typeで大きく変わります。「誰がこのオブジェクトを動かすのか」 で選びます。

| Body Type | 動かすのは | 用途 | 特徴 |
|---|---|---|---|
| Dynamic | 物理エンジン | プレイヤー、敵、投げた爆弾、落ちる岩 | 重力・力・衝突に完全に従う(デフォルト) |
| Kinematic | スクリプト | 動く床、上下するリフト、レール上の敵 | 重力や衝突の反発を受けず、MovePosition()等で動かす |
| Static | 誰も動かさない | 地面、壁、動かない障害物 | 完全固定。最軽量 |
tips: 動かない地形に
Rigidbody2Dを付け忘れても、Collider2Dだけで「Staticな物体」として扱われます。ただし実行中に動かす可能性があるならKinematicなRigidbody2Dを付けておくのが正しい作法です(Rigidbodyなしのコライダーを動かすと物理エンジンの再計算が走り重くなります)。
Collider2D: 衝突の形状を定義する
Collider2Dは物理的な「形」を定義します。物理エンジンにとっての実体は、見た目のSpriteではなくコライダーの形です。

BoxCollider2D: 四角形。床・壁・木箱など、最も汎用的で軽量です。CircleCollider2D: 円形。ボールや弾に。回転しても形が変わらないので回転物に強いです。CapsuleCollider2D: カプセル形。プレイヤーの当たり判定の定番です。底が丸いため、坂道やタイルの継ぎ目で角が引っかかる事故が起きにくくなります。PolygonCollider2D: Spriteの形から多角形を自動生成。精密ですが頂点が多いほど重いので、キャラの通常判定には過剰です。CompositeCollider2D: 複数のコライダーを1つに結合。タイルマップの大量のBoxCollider2Dをまとめて最適化する用途が代表です。
「キャラはCapsule、地形はBox(+Composite)、ボールはCircle」 ——まずこの組み合わせから始めるのが定石です。
Is Triggerと衝突イベント
Collider2DのIs Triggerをオンにすると、物理的な反発がなくなり、「重なった」ことだけを検知するセンサーになります。コインの取得、ダメージゾーン、ゴール判定など、「ぶつかってほしくないが検知はしたい」場面で使います。

スクリプトでは対になるイベントで受け取ります。
using UnityEngine;
public class PlayerController2D : MonoBehaviour
{
// 物理的な衝突(反発あり)を検知
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
Debug.Log("敵と衝突した!");
}
}
// トリガー(重なり)を検知
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Coin"))
{
Debug.Log("コインを取得!");
Destroy(other.gameObject);
}
}
}
イベントが呼ばれる条件やEnter/Stay/Exitの使い分けは OnTriggerとOnCollisionの記事 で詳しく解説しています。
2D物理あるあるトラブルと直し方
冒頭の3大トラブルは、すべてRigidbody2DのInspectorで解決できます。

| 症状 | 原因 | 直し方 |
|---|---|---|
| キャラが勝手に転ぶ | Dynamicは衝突で回転する | Constraints > Freeze Rotation Zをオン |
| 高速の弾が壁をすり抜ける | Discreteはフレーム間を補間しない | Collision DetectionをContinuousに |
| 動きがカクついて見える | 物理はFixedUpdate周期、描画はフレーム周期 | InterpolateをInterpolateに |
特にFreeze Rotation Zは、プレイヤーキャラを作るならほぼ必須です。「物理で動かしたいが、転がってほしくはない」のが2Dアクションのキャラだからです。
実践:2Dアクションの自機を「転ばず・すり抜けず」動かす
横スクロールアクションの主人公、メトロイドヴァニアの二段ジャンプ、物理パズルで転がすブロック——2Dで「自分で操作するキャラ」を作るときの土台は、ほとんど同じ 3点セット です。ここまでの設定を、動く自機に組み上げてみ ましょう。

- Rigidbody2D(Dynamic)+ Freeze Rotation Z: 物理で動かしつつ、衝突で転がらないよう回転を固定します。
- CapsuleCollider2D: 底が丸く、段差やタイルの継ぎ目で引っかかりにくい当たり判定です。
- 接地判定(足元レイ): ジャンプ可能かを判断するため、足元から地面へ短く判定を飛ばします。
3点をそろえたら、移動とジャンプはスクリプトで書きます。linearVelocity(旧velocity)の 横成分だけを書き換え、縦(重力・ジャンプ)は物理に任せる のが2Dアクションの定番です。
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class PlatformerMove : MonoBehaviour
{
[SerializeField] private float moveSpeed = 8f;
[SerializeField] private float jumpPower = 12f;
[SerializeField] private LayerMask groundLayer; // 接地判定の対象を「地面」だけに絞る
[SerializeField] private Transform groundCheck; // 足元に置いた空オブジェクト
private Rigidbody2D rb;
void Awake() => rb = GetComponent<Rigidbody2D>();
void Update()
{
float x = Input.GetAxisRaw("Horizontal");
// 横だけ書き換え、縦(重力・ジャンプ中の速度)は物理に任せる
rb.linearVelocity = new Vector2(x * moveSpeed, rb.linearVelocity.y);
// 接地しているときだけジャンプ(縦速度を上書き)
if (Input.GetButtonDown("Jump") && IsGrounded())
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpPower);
}
}
// 足元の小さな円が地面レイヤーに重なっていれば「接地」とみなす
private bool IsGrounded()
{
return Physics2D.OverlapCircle(groundCheck.position, 0.1f, groundLayer) != null;
}
}
ポイントは2つです。
- 横は速度で、縦は物理に任せる:
linearVelocityのxだけを入力で上書きし、yはそのまま渡します。重力もジャンプの放物線も物理エンジンが計算してくれるので、コードは「地面を蹴る瞬間だけyを上書きする」ことに集中できます。 - 接地判定はコライダーの足元から:
IsGrounded()は足元のgroundCheckからPhysics2D.OverlapCircleで地面レイヤーだけを見ます。空中で無限にジャンプさせないための必須チェックです(Physics2D.Raycastで作る方法は Raycastの記事 参照)。
なお、力や速度の操作は本来FixedUpdateで行うのが正確です(入力の取得はUpdate、物理の適用はFixedUpdateに分ける/UpdateとFixedUpdateの記事 参照)。まずは動かしてみて、カクつきが気になったら分離を検討しましょう。
tips:
velocityはUnity 6でlinearVelocityに改名されました(Unity 6 API移行ガイド 参照)。「下から飛び乗れる一方通行の床」はPlatform Effector 2Dで作れます(おまけ参照)。
おまけ:先に知っておくと良いこと
- Physics Material 2D: コライダーに割り当てる「材質」です。
Friction(摩擦)とBounciness(反発)を設定でき、ツルツルの氷床やスーパーボールが作れます。壁に張り付く問題(ジャンプ中に壁へ押し続けると落ちない)もFriction 0のマテリアルで解決できます。 - Effector2D: コライダーに特殊な力場を与えるコンポーネント群です。
Platform Effector 2Dを使うと「下から飛び乗れる床(一方通行床)」が一撃で作れます。2Dプラットフォーマーでは必修です。 - Tilemap Collider 2D: タイルマップの地形には
Tilemap Collider 2D+Composite Collider 2Dの組み合わせが定番です。タイル1枚ずつのコライダーが結合され、継ぎ目の引っかかりも軽減されます。 - 物理の更新タイミング: 力や速度の操作は本来
FixedUpdateで行うのが正確です(UpdateとFixedUpdateの記事 参照)。
まとめ
- 2Dの物理は3Dと別系統。
2D付きコンポーネントだけを使う。 - Body Typeは「誰が動かすか」で選ぶ: 物理=Dynamic、スクリプト=Kinematic、不動=Static。
- コライダーは「キャラ=Capsule、地形=Box、ボール=Circle」 から。精密すぎるPolygonは重い。
- 反発が要らない検知は
Is Trigger+OnTrigger2D系イベントで。 - 転ぶ→Freeze Rotation Z、すり抜け→Continuous、カクつき→Interpolate。3大トラブルはInspectorで解決。
物理エンジンは「それっぽい動き」を無料でくれる強力な味方です。まずはキャラにRigidbody2D+CapsuleCollider2D+Freeze Rotation Zの3点セットから始めてみてください。