【Unity 6】Time.deltaTimeとは?「なぜ掛けるの?」が誰でもわかる超入門

広告

Unityでキャラクターを動かすプログラムを書くと、こんなコードをよく見かけます。

transform.position +=
    Vector3.right * speed * Time.deltaTime;

この最後にある Time.deltaTime。「とりあえず付けておけばいい」と覚えていませんか?

実は、これには大切な意味があります。しかも、仕組みはそれほど難しくありません。「1秒間にどれだけ動かしたいか」を考えるだけで、理解できるようになります。

この記事では、難しい説明をできるだけ使わず、身近な例と図解で Time.deltaTime を理解していきましょう。

  • 対象:Unity初心者・C#を学び始めた人
  • 難易度:★☆☆☆☆
  • 使用環境:Unity 6 / C#
UnityのTime.deltaTimeの定義、FPSごとの値、使う場合と使わない場合の違い、移動・回転・タイマーの使い方をまとめた図
Time.deltaTimeは、前の画面更新から今回までの経過時間(秒)です。この値を掛けることで、フレームレートが違っても同じ速さで動かせます。

1. まず結論!Time.deltaTimeとは?

Time.deltaTime は、簡単に言うと、前の画面更新から、今回の画面更新までに経過した時間(秒)です。

例えば、Unityが1秒間に60回画面を更新しているとしましょう。この場合、1回の更新にかかる時間は、およそ次のようになります。

1秒 ÷ 60回 = 約0.0167秒

つまり、Time.deltaTime の値は、およそ 0.0167 になります。

ただし、これは60 FPSで安定して動作している場合の話です。実際には、画面更新の間隔に応じて値が変化します。

画面の更新回数1回あたりの時間
30 FPS約0.0333秒
60 FPS約0.0167秒
120 FPS約0.0083秒

FPSとは、1秒間に画面を何回更新するかを表す数値です。ここでは、画面更新の回数が多いほど、1回あたりの時間は短くなると理解できれば十分です。

2. そもそも、なぜTime.deltaTimeが必要なの?

例えば、画面の右方向に進むキャラクターを作るとしましょう。次のプログラムを見てください。

using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    void Update()
    {
        transform.position += Vector3.right * 0.1f;
    }
}

このプログラムには、Time.deltaTime がありません。何が問題なのでしょうか?

Updateは1秒に1回ではない

Update() は、基本的に画面が更新されるたびに1回実行されます。つまり、60 FPSなら、およそ1秒間に60回実行されます。先ほどのコードは、

transform.position += Vector3.right * 0.1f;

なので、1回実行するたびに右へ0.1移動します。では、1秒間にどれだけ動くでしょうか?

60 FPSの場合

0.1 × 60回 = 6

1秒間で6移動します。

30 FPSの場合

0.1 × 30回 = 3

1秒間で3しか移動しません。

120 FPSの場合

0.1 × 120回 = 12

なんと、1秒間で12も移動します!

同じゲームなのに、パソコンの性能や描画負荷によって移動速度が変わってしまうのです。これでは困りますね。

3. Time.deltaTimeを掛けると何が変わる?

そこで登場するのが Time.deltaTime です。先ほどのプログラムを、次のように変更します。

using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    public float speed = 5f;

    void Update()
    {
        transform.position +=
            Vector3.right * speed * Time.deltaTime;
    }
}

ここでの speed = 5f は、1秒間に5 Unity単位進むという意味になります。実際に計算してみましょう。

60 FPSの場合

1回あたりの移動距離は、

5 × 0.0167 = 約0.0833

これを1秒間に60回繰り返すので、

約0.0833 × 60 = 約5

30 FPSの場合

5 × 0.0333 = 約0.1667

1秒間に30回繰り返すので、

約0.1667 × 30 = 約5

120 FPSの場合

5 × 0.0083 = 約0.0417

1秒間に120回繰り返すので、

約0.0417 × 120 = 約5

結果を整理してみます。

FPS1回の移動距離1秒間の移動距離
30約0.1667約5
60約0.0833約5
120約0.0417約5

※ 表示上の数値は四捨五入しています。

つまり、画面更新が速くても遅くても、1秒間に進む距離がほぼ同じになる!これが Time.deltaTime を使う最大の理由です。

UnityのTime.deltaTimeを使った場合と使わない場合の移動距離を30・60・120FPSで比較した図
Time.deltaTimeを使うことで、フレームレートが異なっても1秒間の移動距離をほぼ一定にできます。

4. もっと簡単に!自転車で考えてみよう

ここまでで、まだ難しく感じる人もいるかもしれません。そんなときは、自転車を想像してください。あなたは自転車で、1秒間に5m進むとします。では、0.1秒間では何m進むでしょうか?

5m × 0.1秒 = 0.5m

0.5秒間なら?

5m × 0.5秒 = 2.5m

2秒間なら?

5m × 2秒 = 10m

このように、移動距離は、速さ × 経過時間 = 移動距離で計算できます。Unityでも、まったく同じ考え方を使います。

speed * Time.deltaTime

これは、1秒あたりの移動量 × 今回経過した時間という意味です。難しそうに見える Time.deltaTime ですが、単なる「経過時間」なのです。

5. 実際にUnityで動かしてみよう

ここからは、実際にUnityで確認してみましょう。

① Cubeを作る

UnityのHierarchyで、右クリック → 3D Object → Cube を選択します。

② スクリプトを作る

Projectウィンドウで、C#スクリプトを作成します。名前は、DeltaTimeSample にしましょう。

③ プログラムを書く

using UnityEngine;

public class DeltaTimeSample : MonoBehaviour
{
    [SerializeField]
    private float speed = 3f;

    void Update()
    {
        transform.position +=
            Vector3.right * speed * Time.deltaTime;
    }
}

④ Cubeに取り付ける

作成したスクリプトをCubeにアタッチします。

⑤ ゲームを実行する

Playボタンを押してみてください。Cubeが右方向に移動します。speed を変更すると、移動する速さも変わります。例えば、

  • speed = 1 → 1秒間に1進む
  • speed = 3 → 1秒間に3進む
  • speed = 10 → 1秒間に10進む

という動きになります。

※ この例はTransformを直接動かす基本的な方法です。Rigidbodyによる物理挙動を扱う移動とは区別してください。

6. 1行のプログラムを分解してみよう

次のコードを見てください。

transform.position += Vector3.right * speed * Time.deltaTime;

長く見えますが、分けて考えると簡単です。

① Vector3.right

Vector3.right は右方向を表します。具体的には、new Vector3(1, 0, 0) と同じ方向です。

② speed

speed は、1秒間にどれだけ進むかを表します。例えば、speed = 3f; なら、1秒間に3 Unity単位進む速さです。

③ Time.deltaTime

Time.deltaTime は、今回の画面更新までに経過した時間です。

④ 掛け算する

Vector3.right * speed * Time.deltaTime

右方向に、今回進むべき距離を計算しています。

⑤ +=

transform.position += ...

現在位置に、今回の移動量を足します。例えば、現在のX座標が10で、今回の移動量が0.05なら、

10 + 0.05 = 10.05

になります。これを毎回繰り返して、キャラクターを少しずつ動かしているわけです。

7. Time.deltaTimeは移動以外にも使える

Time.deltaTime は、キャラクターを動かすためだけのものではありません。時間に合わせて変化させたい処理にも使えます。

例① 物体を回転させる

using UnityEngine;

public class RotateSample : MonoBehaviour
{
    [SerializeField]
    private float rotationSpeed = 90f;

    void Update()
    {
        transform.Rotate(
            0f,
            0f,
            rotationSpeed * Time.deltaTime
        );
    }
}

rotationSpeed = 90f なので、1秒間に90度回転します。2Dゲームで、ルーレットや針を回転させるときにも使える考え方です。

例② 3秒後にメッセージを表示する

using UnityEngine;

public class TimerSample : MonoBehaviour
{
    private float timer = 0f;

    void Update()
    {
        timer += Time.deltaTime;

        if (timer >= 3f)
        {
            Debug.Log("3秒経過しました!");
            enabled = false;
        }
    }
}

注目するのは、

timer += Time.deltaTime;

です。Update() が実行されるたびに、経過時間を加算しています。例えば、

0.0167秒
0.0334秒
0.0501秒
0.0668秒
...

というように、時間が積み重なっていきます。そして、約3秒経過するとメッセージを表示します。ここで重要なのは、Update() の実行回数ではなく、経過した時間を数えているということです。

※ 実際の判定はフレーム単位なので、3秒ちょうどではなく、3秒を超えた最初の更新で実行されます。

例③ 1秒ごとに処理する

using UnityEngine;

public class IntervalSample : MonoBehaviour
{
    private float timer = 0f;

    void Update()
    {
        timer += Time.deltaTime;

        if (timer >= 1f)
        {
            Debug.Log("約1秒経過!");
            timer -= 1f;
        }
    }
}

この場合、

timer -= 1f;

としている点がポイントです。単純に、

timer = 0f;

としても動きますが、1秒を少し超えた分の時間が失われます。timer -= 1f とすることで、余った時間を次の計測に引き継げます。

ただし、極端に処理が重くなって1フレームで2秒以上経過するような場合は、このコードだけではすべての1秒区間を処理できません。通常の初学者向けタイマーとしては、この理解で十分です。

8. よくある間違い

間違い① Updateなら必ずdeltaTimeを掛ける?

いいえ。Update() 内のすべての計算に Time.deltaTime が必要なわけではありません。例えば、ボタンが押されたときに得点を10点増やす場合です。

score += 10;

この場合、Time.deltaTime は不要です。押した回数に応じて得点を増やしたいので、経過時間を掛ける必要がないからです。一方で、

score += 10f * Time.deltaTime;

とすると、1秒間に10点の割合で得点が増える処理になります。このように、「1秒あたり」という意味の数値を使っているかどうかが判断のポイントです。

間違い② deltaTimeを2回掛けてしまう

例えば、次のコードです。

float move = speed * Time.deltaTime;

transform.position +=
    Vector3.right * move * Time.deltaTime;

これは間違いです。move を計算した時点で、すでに Time.deltaTime を掛けています。もう一度掛けると、移動量が必要以上に小さくなります。正しくは、

float move = speed * Time.deltaTime;

transform.position += Vector3.right * move;

です。

間違い③ FixedUpdateでも同じように使う?

FixedUpdate() は、物理演算などで使う、固定時間間隔の更新処理です。Update() とは実行されるタイミングが異なります。Unity 6では、FixedUpdate() 内で Time.deltaTime を参照すると、Time.fixedDeltaTime に相当する値が返されます(Time.deltaTime – Unity公式ドキュメント)。

ただし、ここで覚えておいてほしいことがあります。Rigidbodyを使うときに、すべての処理へdeltaTimeを掛けるわけではありません。例えば、

rb.linearVelocity = new Vector2(5f, 0f);

のように速度を直接指定する場合、その速度はすでに「1秒あたり」の値なので、Time.deltaTime を掛けません。一方、毎秒一定量ずつ速度を変えたい場合などは、時間を使った計算が必要になります。Update、FixedUpdate、Rigidbodyの使い分けは、別の記事として学ぶと理解しやすいでしょう。

9. 実はdeltaTimeにも注意点がある

ここまで読むと、「Time.deltaTime を使えば、すべての動きが完全に同じになる」と思うかもしれません。しかし、厳密にはそうではありません。

例えば、速度を時間とともに変化させたり、衝突判定を行ったりするゲームでは、更新の刻み方によって結果が異なることがあります。

また、Unityには、極端に長いフレーム時間を制限する Time.maximumDeltaTime という仕組みがあります。そのため、Time.deltaTime は、必ずしも現実世界で経過した時間をそのまま表すとは限りません(時間の変動の処理 – Unity公式ドキュメント)。

初心者の段階では、まず次の理解で問題ありません。

Time.deltaTime は、フレームレートに左右されにくい時間ベースの処理を作るための基本的な仕組みです。

10. 理解できたか確認しよう!

最後に、簡単な問題を3つ出します。

問題1

speed = 10f;

Time.deltaTime が0.02だった場合、1回の更新で進む距離はいくつでしょうか?

問題2

次のコードでは、FPSによって1秒間の移動距離が変わるでしょうか?

void Update()
{
    transform.position += Vector3.up * 0.1f;
}

問題3

次のコードの speed = 5f は、どんな意味でしょうか?

void Update()
{
    transform.position +=
        Vector3.right * speed * Time.deltaTime;
}

答え

問題1:0.2

10 × 0.02 = 0.2

問題2:変わります。Time.deltaTime を掛けていないため、Update() が多く実行されるほど、1秒間の移動距離が増えます。

問題3:1秒間に5 Unity単位進む速さです。Time.deltaTime によって、今回の更新で必要な移動距離が計算されます。

まとめ:Time.deltaTimeは「時間を考えて動かす」ためのもの

今回覚えてほしいのは、次の3点です。

  1. Update() は、1秒間に何度も実行される。
  2. Time.deltaTime は、前回の画面更新からの経過時間(秒)を表す。
  3. 1秒あたりの速さに Time.deltaTime を掛けると、今回進むべき距離が求められる。

特に大切なのは、次の式です。

移動距離 = 速さ × 時間

Unityのプログラムでは、

float move = speed * Time.deltaTime;

と書きます。Time.deltaTime は、難しい特殊な計算をする命令ではありません。「今回は何秒分、動かせばいいの?」を教えてくれる値なのです。この意味がわかれば、キャラクターの移動、回転、タイマーなど、さまざまなプログラムを自分で考えて作れるようになります。

2Dでの移動をさらに学びたい方は、Unity 6の2Dでオブジェクトを自動的に右へ移動させる方法もあわせてご覧ください。

参考:Unity公式ドキュメント

訪問数 4 回, 今日の訪問数 4回

広告