【Unity】マリオみたいなジャンプを再現する方法
Unityで「マリオのようなジャンプ」を再現する方法について解説します。
マリオシリーズのジャンプは、普通のジャンプと比べて非常に気持ちよく設計されています。
その秘密は、ジャンプ中・落下中で重力を動的に変化させている点にあります。
なぜ普通のジャンプではマリオっぽくならないのか?
Unityのデフォルト設定では、重力加速度が -9.8 m/s² に設定されています。
これは現実世界に基づく値ですが、これをそのまま使うとジャンプが重たく、もっさりした挙動になってしまいます。
初代『スーパーマリオブラザーズ』について、
Tom Murphy VII氏による調査では、
重力加速度が現実の–9.8m/s²よりもかなり大きく、約–90m/s²程度であるという分析結果が報告されています。
さらにマリオシリーズでは、ジャンプの各状態に応じて重力の強さ(Gravity Scale)を切り替えることで、非常に直感的な操作感を実現しています。
具体的には、
- 上昇中:Gravity Scaleを小さくして、ゆっくり上がるようにする
- ジャンプボタンを離した直後:Gravity Scaleを一気に大きくして、急加速して落ち始める
- 下降中:さらにGravity Scaleを大きくして、すばやくストンと着地する
この切り替えにより、
- ジャンプボタンを短く押せば小ジャンプ
- 長く押し続ければ高いジャンプ
- 頂点からは素早く落下
という「気持ちいいジャンプ操作」が可能になっています。
比較動画

| 左:本記事の方法で作ったジャンプ | 右:常に同じ重力で作ったジャンプ |
※左のジャンプは、上昇・ボタン離し・下降で重力を切り替えています。
※右のジャンプは、常に一定の重力で制御しているため、もっさりとした動きになっています。
実装の基本方針
マリオジャンプを再現するために、以下のポイントを押さえます。
- ジャンプ時にしっかりとした初速(上向き速度)を与える
- 上昇中はGravity Scaleを弱めて、滞空感を出す
- ジャンプボタンを離した直後はGravity Scaleを強めて、急降下を開始する
- 下降中はさらにGravity Scaleを強めて、素早く着地させる
今回はさらに、n段ジャンプ(ダブルジャンプ、トリプルジャンプなど)にも対応しています。
コードサンプル
ここでは、上記の方針に沿って実装した、実際のUnity用C#スクリプトを紹介します。
このスクリプトをキャラクターにアタッチするだけで、マリオのようなジャンプ挙動を再現できます。
using System; using UnityEngine; [RequireComponent(typeof(Rigidbody2D))] public class MarioLikeJump : MonoBehaviour { [SerializeField] private Rigidbody2D _rigidbody; [SerializeField] private float _takeOffVelocity = 17f; [SerializeField] private float _riseGravityScale = 3.5f; [SerializeField] private float _cutGravityScale = 7f; [SerializeField] private float _fallGravityScale = 6f; [SerializeField] private int _maxJumpCount = 2; private bool _jumpRequest; private bool _jumpHeld; private int _jumpCount; private float _defaultGravityScale; #if UNITY_EDITOR private void Reset() { _rigidbody = GetComponent<Rigidbody2D>(); } #endif private void Awake() { _defaultGravityScale = _rigidbody.gravityScale; } private void Update() { if (Input.GetButtonDown("Jump")) _jumpRequest = _jumpHeld = true; if (Input.GetButtonUp("Jump")) _jumpHeld = false; } private void FixedUpdate() { var grounded = Mathf.Abs(_rigidbody.velocity.y) < 0.01f; if (grounded) { _jumpCount = 0; } if (_jumpRequest) { if (_jumpCount < _maxJumpCount) { _rigidbody.velocity = new Vector2(_rigidbody.velocity.x, _takeOffVelocity); _jumpCount++; } _jumpRequest = false; } if (_rigidbody.velocity.y > 0) // 上昇中 { _rigidbody.gravityScale = _defaultGravityScale * (_jumpHeld ? _riseGravityScale : _cutGravityScale); } else // 下降中 { _rigidbody.gravityScale = _defaultGravityScale * _fallGravityScale; } } }