【ゲームプログラミング】「速度」を使う時は必ず`deltaTime`を使ってください

:::note warn
`Unity`を念頭に置いた記述をしますが、どのエンジン、言語にも通ずる一般的・汎用的なお話をします
:::

## はじめに
みなさんは、ゲーム上で「 **移動** 」を扱う際、どのように実装していますか？
`Unity`なら`AddForce()`という力学的な力を加える関数で動かすことも時々しますが、普通は **座標に足し算** (引き算) **をして移動させ** ますよね？

```csharp:移動.cs
position.x += something_x;
position.y += something_y;
```

みたいな感じに。ここ問題提起。
**`something`には何を入れますか？**

ちょっとゲームプログラミングやってきた方は、**この`something`が大きいと移動が速くなる**ことに気づき、`something`が **速度に相当** するものだと気づいてor知っているでしょう。

だから
```c#:移動.cs
position.x += speed_x;
position.y += speed_y;
```
と書くと。

**これ、不安定です**

## 「速さ」を足し算しない理由
説明が二通りできます。

### プログラム上の説明（簡単な方）
ほとんどの（アクション性のある）ゲームは、[「フレーム」で構成される「ループ」にて動作している](https://yttm-work.jp/gmpg/gmpg_0016.html)ことと思います。

もし、 **足し算をそのまま一定の「速さ」にすると、毎フレームその一定値の分だけ足される** わけです。

逆に言うと、 **ゲーム上の速さがFPSに依存する** ことになります。
次の`h3`項目と重複しますが、この場合（数式に免疫のない方は見なくともいいです）
```math
\begin{align}
速度 &= 一秒あたりの移動量\\
    &= フレーム当たりの速さ \times 一秒当たりのフレーム\\
    &= フレーム当たりの速さ \times FPS
\end{align}
```
ということです。
要するに、 **重いときは移動が遅く、軽いときは移動が早く見えるようになります。** 
もちろんこっちがいい場合もあります。後述参照。

この場合だと、良からぬ点が二つあります：
* **FPSに波がある場合、ゲームのスピード感が頻繁に変わり強い違和感を生じさせる**
    極端な例ですが、1秒ごとにFPS=60とFPS=30に切り替わるようなシステムだったとして（そんなことある？）、この場合1秒ごとにゲーム全体のスピード感が2倍ないし半分になるわけです。嫌ですよね。
* **FPSを変更した場合、全てのスピードの設定を再び調整しないといけない。**
    ゲームプログラミングは**調整性が肝要**ですからね。

### 物理学上の説明（ちょっとややこしい方）

「速さ」の公式は小学校でやりましたか？
人によっては、このような図を習った方もいますね。
<img width="400" alt="kihaji" src="https://wakara.co.jp/wp-content/uploads/7fb50128f1798d440fb37db18c1b42e2-1024x1024.png">
引用：[WAKARA・マスログ「は・じ・きを覚えさせることの最大の問題点【速さ・時間・距離の公式】[youtube公開]」](https://wakara.co.jp/mathlog/20220608)

ここで一度僕が好きな代ゼミ亀田先生の30秒動画を見てください：https://www.youtube.com/watch?v=axBVaj42f0A
ご視聴ありがとうございます。

要するにこういうことです。
```math
移動した距離 = 速さ \times 時間
```

ここからがサビです。
**座標に`d`を足し算する** ということは、**`d`だけ動く** ということですよね。すなわち`d`は **「移動した距離」** に該当するわけです。
**その `d` に「速さ」を当てはめるのは、まあおかしい**わけですよね。
**だから時間を掛け算しなさい** という話になるわけです。

ゲームだから実際の物理学と違ってもいいだろ！という指摘もあるでしょう。実際そうです。
しかし、現実に揃えるメリットは明確に存在します。

こうすることで、 **「速さ」** が **「一秒あたりの移動量」に統一できます。** 

常人の皆様は「秒」を用いる時間帯系の中で生活されているかと思われますので、「フレーム当たり速さ」なんというヘンな感じなパラメーターではなく、秒あたりのパラメーターで **直観的に** 調整できるわけですね。

## `deltaTime`を使ってください
上記の問題を解決するには、「はじき」の公式にもある通り、**「速さ」に「時間」を掛け算する** といいわけですね。 **その「時間」に`deltaTime`を割り当てます。**

### `deltaTime`って？
`Unity`特有のの変数名をそのままみんな知ってるよねって面で喋っていてごめんなさい。
`deltaTime`は、**「前フレームと今フレームの時間間隔」** です。

例えばフレーム19からフレーム20に移るのに0.02秒かかったら、フレーム20の時点で`deltaTime=0.02`が入るわけです。

`Unity`の場合は`Time.deltaTime`でアクセスできます。

他の場合は、
* フレーム→フレームの時間間隔を測定するタイマーを実装するか、
* FPSの起伏があまりない場合、**FPSの逆数を掛け算** することによって似たことができます。
    FPS「一秒に処理されるフレーム数」の逆数が「1フレームにかかる秒」ですからね。

### なんで掛け算するの？
フレームとフレームの間で移動した量を足し算するわけなので、その間の **時間** は`deltaTime`ですよね？
それを掛け算すると、 フレームとフレームの間の **移動した距離** になるからです。

### 時間積分（時間で累積）をするものは全て`deltaTime`
速度→距離

以外にも、

時間当たりダメージ量→受けたダメージ

時間当たりポイント量→獲得ポイント

加速度→速度　（加速度から初めて移動量を出す場合、二回`deltaTime`の掛け算をする！！）

力積→運動量

など、「時間当たり」から、まとまった「量」を導くときは、全て`deltaTime`にしましょう。

あまりピンと来ない方は、「単位」から考えてみるアプローチもオススメです：　https://qiita.com/toRisouP/items/930100e25e666494fcd6

## 「フレーム当たり速さ」の方がいい場合もある
例えば格闘ゲームなどの公平性が重要とされるEスポーツ性のあるゲームは、こちらが好まれます。
格ゲーは「nフレーム発生の攻撃」とか言いますけど、もし環境によってタイミングがフワフワしてたら、ガチ勢プレイヤーは困りますからね。

あとは、かなりカクカクなゲームな場合もこちらがいい場合があります。
`deltaTime`が大きくなるわけなので、逆に「ワープした」という違和感を与えてしまいますので、いっそのことフレームごとの方が納得感が出ます。

## さいごに
`deltaTime`を掛け算しましょう

:::note warn
コメントで皆様から有益な示唆を受けているので、ぜひご覧ください。
:::

:::note
いいね頂けると泣いて喜びます><

この記事を読んでいる方は次の記事を読んでいるかもしれません:
* [【ゲーム物理】待て！AddForce()使う前に運動方程式の話を聞いてくれ！](https://qiita.com/konbraphat51/items/6c8ec30f488b22a854b1)
* [【ゲーム物理】離散要素法DFMで簡単物理エンジン！①　基礎編](https://qiita.com/konbraphat51/items/157e5803c514c60264d2)
:::