deltaTimeとは?requestAnimationFrameで正確なアニメーションを作る方法

deltaTimeのアイキャッチ画像

JavaScriptでアニメーションを作っていると、こんな現象に出会います。

  • PCでは速いのにスマホでは遅い
  • カクついた瞬間に動きが変になる
  • 端末ごとに「速度」が違って見える

原因はほぼ同じです。

フレーム数に依存して動かしていること。

それを解決するのが deltaTime(デルタタイム) です。

この記事では、

  • deltaTimeとは何か
  • なぜ必要なのか
  • requestAnimationFrameでの正しい使い方
  • 実戦での注意点

を、初心者向けに整理します。

1. フレーム依存で動かすと何が起きる?

よくあるコードです。

const box = document.getElementById("box");
let x = 0;

function animate() {
  x += 5;
  box.style.transform = `translateX(${x}px)`;
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

これは
「1フレームごとに5px進む」
という意味です。

つまり、

  • 60fps → 1秒で 300px
  • 30fps → 1秒で 150px

fpsが違えば速度も変わります。

これがズレの正体です。

requestAnimationFrame自体の仕組みが曖昧な場合は、
👉 #01 requestAnimationFrameの使い方 を先に読むと理解がスムーズです。

2. deltaTimeとは?

deltaTimeとは、

前回のフレームから今回のフレームまでに経過した時間

のことです。

フレーム数ではなく
時間で動きを制御するための値です。

3. requestAnimationFrameが渡してくれる time

function animate(time) {
  console.log(time);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

この time は、

  • ページ読み込み開始からの経過時間(ミリ秒)
  • 毎フレーム増えていく数値

です。

この値の差分を取ることでdeltaTimeが作れます。

4. deltaTimeの計算方法

let lastTime = 0;

function animate(currentTime) {
  const deltaTime = currentTime - lastTime;
  lastTime = currentTime;

  console.log(deltaTime);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

60fpsなら約16ms前後になります。

5. 正しい動かし方 = 距離 = 速度 × 時間

フレーム依存 ❌

x += 5;

時間ベース ✅

x += speed * deltaTime;

これでfpsが変わっても
1秒あたりの移動量は一定になります。

6. 実装例(ms版)

const box = document.getElementById("box");
let x = 0;

let lastTime = 0;
const speed = 0.2; // px/ms

function animate(currentTime) {
  const deltaTime = currentTime - lastTime;
  lastTime = currentTime;

  x += speed * deltaTime;
  box.style.transform = `translateX(${x}px)`;

  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

1msあたり0.2px進む
=1秒で200px進む、という意味です。

7. 実装例(秒版)

const box = document.getElementById("box");
let x = 0;

let lastTime = 0;
const speed = 200; // px/s

function animate(currentTime) {
  const deltaTime = (currentTime - lastTime) / 1000;
  lastTime = currentTime;

  x += speed * deltaTime;
  box.style.transform = `translateX(${x}px)`;

  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

重要なのは、

  • speedがpx/sならdeltaTimeは秒
  • speedがpx/msならdeltaTimeはms

単位を必ず揃えること。

8. よくあるミス

lastTimeを更新し忘れる

deltaTimeが巨大になり壊れます。

単位がズレている

速度と時間の単位が一致していない。

初回だけ大きな値になる

安全な書き方はこちら。

let lastTime = null;

function animate(currentTime) {
  if (lastTime === null) lastTime = currentTime;

  const deltaTime = currentTime - lastTime;
  lastTime = currentTime;

  requestAnimationFrame(animate);
}

9. 実戦で重要:ワープ防止

タブ復帰時などに
deltaTimeが極端に大きくなることがあります。

そのまま使うと一瞬でワープします。

対策は「上限を設ける」こと。

const MAX_DELTA = 50;

let deltaTime = currentTime - lastTime;
if (deltaTime > MAX_DELTA) deltaTime = MAX_DELTA;

これだけで安定性が一気に上がります。

10.まとめ

  • フレーム依存では速度が変わる
  • deltaTimeはフレーム間の経過時間
  • 距離 = 速度 × 時間
  • 単位を揃えるのが最重要
  • 実戦ではワープ防止が効く

11.実験:フレーム依存 vs deltaTime(同じ速度で動くか目で見る)

以下のデモでは2つの更新方法を比較できます。

A:フレーム依存(px / frame)

x += constant;

B:deltaTime(px / second)

x += speed * dt;

通常状態では2つはほぼ同じ速度に見えます。

しかし Heavy Load をONにするとフレームレートが下がり、

  • A:フレーム依存 → 遅くなる
  • B:deltaTime → 速度を維持

という違いが確認できます。

これはゲームループやアニメーションで deltaTime が使われる理由の一つです。

観察ポイント

Heavy Load をONにすると FPS が低下します。

その状態で比較すると、

  • フレーム依存(A)はフレーム数が減るため 進み方が遅くなる
  • deltaTime(B)は経過時間を基準に計算するため 速度が維持される

この違いが deltaTime の重要なポイントです。


次に読むなら

▶ 止める設計を知りたい → #05 cancelAnimationFrameの正しい使い方
▶ 減速や自然な動きを作りたい → #03 easingとは?アニメーションの減速・加速を作る方法

🔎 このラボの全体像はこちら
UI Architecture Roadmap

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA