【Unity】ゲームの自然なジャンプの考え方と作り方

【Unity】ゲームの自然なジャンプの考え方と作り方

目次

シンプルなジャンプ

一番シンプルにジャンプを実装しようとすると、以下のように、RigidbodyをPlayerにアタッチして、以下のコードを記述したスクリプトをPlayerにアタッチします

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;

public class Jump : MonoBehaviour
{
[Range(1, 10)] [SerializeField] private float jumpVelocity;

private Rigidbody2D _rb;

private void Start()
{
_rb = GetComponent<Rigidbody2D>();
}

private void Update()
{
if (Input.GetButtonDown("Jump"))
{
_rb.velocity = Vector2.up * jumpVelocity;
}
}
}

実行結果は以下のような結果になると思います。
(Velocity = 速度)

確かにジャンプはしています。
しかし、私は以下のことが気になりました。

  • ふわっと感がある
    • まるで宇宙でジャンプしているような感じ

ここでは、キャラクターが地面についたかどうかの判定は行っていないのでジャンプボタンを連打すると、無限にジャンプできてしまいますが、それはいったん置いておきます。

シンプルジャンプの「ふわっと感」の正体

この現象の正体は、「物理現象」です。
私たちがプレイヤーキャラクターにつけた「Rigidbody2D」は物理演算をするによって重力をシミュレートしているため、ある程度実際の物理現象と同じ挙動をするようになります。

この物理現象は、一般的に「等加速度運動」と呼ばれています。

等加速運動とは何か

等加とついている通り、「等しく」「加えられる」「速さ」の運動です。

等しく何が加えられるのかというと、この場合は「重力」になります。

Unity内はシミュレーションの世界なので、厳密に等加速度運動を再現できるので、以下の2つの式がそのまま使えることになります。
(現実空間では、風などの外的要因が加わるためこの通りの計算結果になることはほぼない)

  1. 速度() :
    • : 初速度()
    • : 加速度()
    • : 時間(秒)
  2. 移動距離() :
    • : 出発地点
    • : 初速度による高さの増加(ジャンプならけりだす力を考慮する)
    • : 移動量

移動距離は、物体が「等加直線運動」をしている場合の、ある時刻(t)におけるその時の位置を求める式になります。

初速度は最初に与えられた力、加速度はその後に継続的に与えられる力

初速度5m/sの場合、毎秒5m進み続ける、そこに加速度による移動量を足すことで、しょそくど外的にかかる速度を


「等加速度運動」を実際に試してみる

式だけ見てもわかりにくいので、この式をUnity内で動かしてみます。

まずは「速度」の式からです

速度は、どれくらいの速さで移動しているかを表す言葉です。
単位は(メートル毎秒)になります。

  • 速度() :
    • : 初速度()
    • : 加速度()
    • : 時間(秒)

上記の式をC#で記述すると以下のようになります。

1
2
3
4
5
6
7
8
private float _timeElapsed = 0; // 経過時間

private void FixedUpdate() {
_timeElapsed += Time.deltaTime;
float speed = 0 + 3 * _timeElapsed ;

Debug.Log($"{_timeElapsed}秒 : {speed}m/s");
}

上記の式は、初速度が0なので、「崖から下に落ちた」ような状況だと思ってください。
そこに、加速度を毎秒3m加えます。

FixedUpdateで「毎フレーム」更新する処理なので、Time.deltaTimetimeElapsed足し続けることで時間経過によって速度がどうなるのかを見ることができます。

この式では、「timeElapsed秒」経過した場合の速度を求めているということになります。

実行結果を抜き出してみると以下のような出力が出ていると思います。
0.02秒に0.06m/sずつ速度が上がっているのがわかると思います。

1
2
3
4
5
6
7
8
9
0.02秒 : 0.06m/s
0.04秒 : 0.12m/s
0.06秒 : 0.18m/s
0.08秒 : 0.24m/s
...
0.9399996秒 : 2.819999m/s
0.9599996秒 : 2.879999m/s
0.9799996秒 : 2.939999m/s
0.9999996秒 : 2.999999m/s

では次に移動距離についてみていきます
ここで移動距離といっているのは、3秒後にどれだけ移動しているかという考え方になるので、0を基準とした総移動距離を求めることになります。

まずは、速度が一定「等速直線運動」の場合を考えましょう、
例えば、速度がずっと 2 m/s なら、毎秒 2m ずつ移動する

  • 1秒後:2m
  • 2秒後:4m
  • 3秒後:8m

移動距離(d)は「速度× 時間」で求まります。

  • : 速度
  • : 時間

この式は図形として以下のように考えることもできます。
この幾何的な考え方が、大切になります。

これは、v(速度)とt(時間)で構成された、グラフになります。
このグラフの速度が2m/sの時の直線と、各時間の直線が作り出す四角形の面積がそのまま移動距離と考えることができます。

なので、速度が2m/sの時に、2秒進んだ場合2 * 2で4m進むことになりますが、これを四角形の面積の求め方「縦 * 横」として見ると、同じようにグラフが作り出す四角形も答えが一致します。


ここまでの考え方で、「等速直線運動」の式はわかりましたが、今回のメインは、「等加速度運動」になります。

等加速度運動の場合は、速度*時間で距離を求めることはできません。

これは、等加速度運動の場合のグラフを考えてみるとわかりやすいです。
まず、当加速運動の「速度」を求める必要があるので、以下の式をグラフにプロットしてみます。

今回は、は0として扱うので、をプロットします。
(加速度)はとします。

このグラフに、経過時間の縦棒グラフを追記すると以下のような三角形の図形の面積を求めれば移動距離を求めることができることがわかります。

まず三角形の面積は、

で求められます。
それぞれに該当する情報は以下の通りです。

  • 底辺 : 時間(t)
  • 高さ : 等加速度運動の速度を求める方程式の

これらを数式に当てはめると、

速度の計算式を展開して整理します。

式展開

同一項目をまとめて、を掛け算にする

最後に短くまとめる


これで、すべてのコードが完成したので、

移動距離や速度を使った実用例

以下の条件で「ジャンプ」をした場合の処理を考える

  • 初速度 : 5 m/s
  • 高さ : 0 m
  • 重力 : 下方向に9.81 m/s = -9.81 m/s

1秒後のプレイヤーの高さ

0やになる部分を消して式を整理

計算

よって、1秒後の高さは0.095mとなる

最高点に到達する時間

最高点に到達する時間は、速度を求める公式から計算できます。

今回の場合、初速度()と加速度()が分かっているて、本来求める速度が0になるときが最高到達点に到着したときになります。
よって残りのt(時間)を求めればいいことになります

公式

この式にわかっている情報を代入します、掛け算を合わせます

まず右辺で孤立している5を消すために、両辺から5を引きます

次に、両辺に-1をかけて符号を整えます

最後にtを求めます

よって、0.5107秒後に最高到達点に到達するとわかります。

最高到達点の高さ

前の計算で最高到達点に到達するまでの時間が分かったので、それの時間を使って今度は最高到達点の高さを求めてみます。

この計算は、移動距離を求める式に分かっている情報を入れるだけで求められます。

上の式に分かっている情報を入れていきます

  • : 0
  • : 5
  • : 0.5107
  • : -9.81

これは純粋に計算するだけなので途中式をある程度省きます

よって、最高到達点の高さは、1.28mということがわかります。


さてこれまで長々と物理の話をしてきましたが、この物理法則をジャンプで使用してしまうと、以下のようなぐらふになります。

これは、物理的には正しいのですが、ゲームとしてのジャンプとしては違和感があります。
それは単に気持ちよさの問題になるのですが、実際のマリオのジャンプを見てみると物理法則に反しているのがわかります。

ジャンプは28フレームをかけて行われていて、最高到達点は18フレーム目です。
2Dゲームの巨匠がこのジャンプなので、近いジャンプを行うようにしたいです。

この現象はつまり、最高到達点に達したとは、飛び上がり時の重力よりもより大きな重力をかければいいということがわかります。

ジャンプ下り時の重力の倍率はジャンプ上り時の重力よりも何倍()必要なのかは以下の計算式で求められます。

よって、最高到達点以降の1.8倍にすればいいということがわかりました。

これをUnityの先程のジャンプに取り入れると、以下のようなコードになります。

1

ボタンの押す長さによってジャンプの高さを変える

この処理は、言い方を変えれば、「ボタンを押している間は重力が弱くなる」ということです。
ボタンを押し続けていれば、無限にジャンプするわけではなく、上限値はあるので、このような解釈で処理が成立します。

これを前の節で作成したコードに組み込むと以下のようになります。

1

参考

Author

Daiki Iijima

Posted on

2025-03-10

Updated on

2025-03-11

Licensed under