キャラクターを動かすスクリプトを書いていたら、なぜか動きがカクついたり、パソコンによって速度が変わってしまったり…そんな経験はありませんか?
その原因、実はUpdateとFixedUpdateの使い分けにあるかもしれません。似たような名前だからと同じ感覚で書いてしまうと、思わぬ不具合につながることがあるんです。
この記事では、UpdateとFixedUpdateがそもそもどう違うのか、そして移動処理や物理演算、入力判定をそれぞれどちらに書けばいいのかを、具体的な場面ごとに整理していきます。
UpdateとFixedUpdateの違いは?
結論から言ってしまうと、物理演算に関わる処理はFixedUpdate、それ以外の入力やゲームロジックはUpdateに書くのが基本の考え方です。まずはこの2つが、それぞれどんなタイミングで動いているのかを見ていきましょう。
Updateは、毎フレーム1回呼び出されるメソッドです。ここで言う「フレーム」は画面の描画タイミングのことなので、パソコンの性能や処理の重さによって、呼ばれる間隔がそのつど変わります。快適な環境なら短い間隔で何度も呼ばれますし、負荷が高い場面では間隔が空いてしまう、というイメージですね。
一方のFixedUpdateは、あらかじめ決められた一定の時間間隔で呼び出されます。初期設定では0.02秒(1秒間に50回)というペースです。こちらは画面の描画速度に関係なく、常に同じリズムで実行され続けます。
ただし「同じリズムで動く」といっても、描画フレームとの周期がぴったり噛み合うわけではありません。1フレームの間にFixedUpdateが1回も呼ばれないこともあれば、逆に2回続けて呼ばれることもあります。この周期のズレが、後ほど紹介するカクつきの原因のひとつになってきます。
なぜこの2つが分かれているかというと、Unityの物理演算エンジン(PhysX)の更新タイミングが、FixedUpdateの間隔に合わせて動いているからです。物理的な力の計算はUpdateのような不安定なタイミングではなく、一定間隔で行う必要がある、というわけですね。
ちなみに、時間の進み方を表すTime.deltaTimeについてもう少し詳しく知りたい方は、こちらの記事もあわせて参考にしてみてください。

ここまでで「そもそも何が違うのか」はイメージできたと思います。次は、実際に自分のプロジェクトでどちらに処理を書けばいいのか、具体的な場面で見ていきましょう。
移動処理はUpdateとFixedUpdate、どっちに書く?
ここが一番迷うポイントかもしれません。結論としては、Rigidbodyを使って動かしているならFixedUpdate、CharacterControllerやtransformで直接動かしているならUpdateという分け方になります。
この違いを分けているのは「Unityの物理エンジンを通しているかどうか」です。次のチェックリストで、自分の実装がどちらに当てはまるか確認してみてください。
✅ rb.AddForceやrb.MovePositionでRigidbodyを動かしている → FixedUpdate
✅ CharacterController.Moveで移動させている → Update
✅ transform.Translateやtransform.positionを直接書き換えている → Update
Rigidbodyを使っているのにUpdateに書いてしまうと、フレームレートが変動するたびに力の加わるタイミングもズレてしまい、環境によって動きが変わる原因になります。逆にCharacterControllerやtransformの移動は物理エンジンを介していないので、Updateで書いても特に問題はありません。
入力はUpdateで取得し、FixedUpdateで適用する
Rigidbodyでの移動を実装するとき、実は入力の取得とRigidbodyへの反映を、同じメソッドの中で完結させない方が安定します。おすすめの流れはこちらです。
- Updateの中で、キー入力の方向をそのつど変数に保存する
- FixedUpdateの中で、保存しておいた変数を使ってRigidbodyに力や速度を適用する
コードにすると、こんなイメージになります。
Vector3 inputDir;
void Update()
{
inputDir = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
}
void FixedUpdate()
{
rb.MovePosition(rb.position + inputDir * speed * Time.fixedDeltaTime);
}
こうしておくと、入力の取得はフレームごとにきちんと拾いつつ、実際にキャラクターを動かす計算は物理エンジンのタイミングに合わせて安定して行われます。

入力もRigidbodyの操作も同じ場所にまとめて書きたくなりますが、役割を分けておいた方が、後から動きが不安定になったときの原因も追いやすくなりますよ。
Rigidbody(物理演算)をFixedUpdateに書くべき理由
前のセクションで「Rigidbodyを使うならFixedUpdate」とお伝えしましたが、ここではもう少し踏み込んで、なぜそう言えるのかを見ていきます。
AddForceやMovePositionといったRigidbody向けのAPIには、Time.deltaTimeを掛け算する必要がありません。これはFixedUpdate自体が、すでに一定間隔で呼ばれることを前提に設計されているためです。もしFixedUpdateの中で自分で時間計算をしたい場面があれば、その時はTime.deltaTimeを使って構いません。FixedUpdate内では、これがFixedUpdateの実行間隔であるTime.fixedDeltaTimeと同じ値を返す仕組みになっています。
もしRigidbodyへの力の適用をUpdateの中に書いてしまうと、フレームレートが上がるほど力が加わる回数も増えてしまいます。同じスクリプトでも、処理が軽いパソコンと重いパソコンとでキャラクターの飛び方や進む距離が変わってしまう、ということが起こり得るので注意が必要です。
たとえば「ボタンを押した瞬間にキャラクターをジャンプさせたい」という処理をUpdateの中でAddForceしてしまうと、環境によってジャンプ力が微妙に変わってしまう…というのは、実装の中でも気づきにくい失敗パターンのひとつです。見た目には同じコードなのに、テストした端末と本番の端末で挙動が違う、なんてことにもつながりかねません。
Rigidbodyの基本的な扱い方からもう一度確認しておきたい方は、こちらの記事も参考にしてみてください。

物理演算をFixedUpdateにまとめておけば、パソコンやスマホの性能差に振り回されることなく、狙い通りの動きを再現しやすくなります。
入力判定をFixedUpdateに書くと起きる問題
移動の仕組みが分かってくると、「じゃあ入力もまとめてFixedUpdateに書いてしまえばいいのでは?」と思う方もいるかもしれません。ですが、これは思わぬ取りこぼしにつながるので気をつけたいポイントです。
Input.GetKeyDownのような「押した瞬間」を検知する処理をFixedUpdateに書くと、ジャンプボタンを押したのに反応しない、といった現象が起こることがあります。これは、FixedUpdateが1フレームの間に一度も呼ばれないタイミングが存在するためです。押した瞬間がちょうどそのタイミングと重なると、入力そのものを取りこぼしてしまいます。
この問題を避けるための考え方はシンプルで、「押した瞬間を知りたいのか」「継続的に力や速度を加えたいのか」で置き場所を分けることです。
✅ ジャンプ・ダッシュ・攻撃など、ボタンを押した瞬間を検知したい処理 → Update
✅ 押しっぱなしの間、継続的にRigidbodyへ力を加え続ける処理 → FixedUpdate
たとえばジャンプなら、「押した瞬間」はUpdateで検知しておき、実際にジャンプ力を加える処理はその情報を使ってFixedUpdate側で行う、という形にすると取りこぼしの心配がなくなります。前のセクションで紹介した「入力はUpdate、反映はFixedUpdate」という流れが、ここでもそのまま活きてきますね。
ゲームによっては、複数のキー入力を組み合わせたり、長押しやダブルタップのような細かい入力判定が必要になる場面も出てきます。そうした入力まわりを一から自前で管理するのが大変になってきたら、入力管理を専門に扱うアセットを使うという方法もあります。
Rewired
✅アセットストアでチェックする
移動のカクつき・速度のばらつきを直す方法
UpdateとFixedUpdateを正しく使い分けていても、動きが微妙にカクついて見えることがあります。これは実装が間違っているというより、2つのメソッドの周期がずれることで起きる、いわゆるJudder(ジャダー)現象と呼ばれるものです。
原因は、描画を担当するUpdateと、物理演算を担当するFixedUpdateの実行タイミングが完全には一致しないことにあります。画面に映る瞬間、Rigidbodyの位置がまだ更新される前の古い情報のまま描画されてしまい、それが人の目にはカクつきとして映るんです。
この現象への対処法は、大きく分けて2つあります。
| 対処法 | 内容 | 向いている場面 |
|---|---|---|
| Interpolateを有効にする | Rigidbodyの見た目の位置だけを補間して滑らかに見せる | プレイヤーが操作するキャラクターなど、動きの滑らかさを優先したい場合 |
| Fixed Timestepを小さくする | FixedUpdateの実行間隔を短くして、周期のズレ自体を減らす | VRなど高い精度が求められる場面、処理負荷に余裕がある場合 |
1つ目は、RigidbodyコンポーネントにあるInterpolateの設定を有効にする方法です。これは物理演算そのものを変えるのではなく、見た目の位置を滑らかに補間してくれる機能です。
ただしInterpolateは、物理エンジンを介さずに見た目の位置を補間する仕組みなので、他のオブジェクトとの当たり判定にわずかなズレが生じることがあります。すべてのオブジェクトに設定するのではなく、プレイヤーが操作するキャラクターなど、見た目の滑らかさが特に重要なものに絞って使うのがおすすめです。
2つ目は、Edit > Project Settings > Timeの中にあるFixed Timestepの数値を小さくする方法です。FixedUpdateが呼ばれる頻度そのものが上がるので、描画とのズレが起きにくくなります。ただしその分、物理演算の計算回数も増えるため、端末への処理負荷は上がります。動作がやや重くなっていないか、実機での確認は必要になってきます。
処理負荷が気になる場合は、そもそもUpdateの呼び出し回数自体を見直すという方向性もあります。こちらの記事でパフォーマンス改善の考え方を詳しく解説しているので、あわせて確認してみてください。
また、キャラクターの動き自体をより滑らかに見せる演出を加えたい場合は、補間アニメーションを手軽に扱えるアセットを使うという選択肢もあります。
DOTween
✅アセットストアでチェックする
カメラ追従はLateUpdateに書く理由
キャラクターの移動とあわせてよく出てくるのが、カメラを追従させる処理です。ここで意外と見落とされがちなのが、カメラの追従はUpdateでもFixedUpdateでもなく、LateUpdateに書くべきという点です。
LateUpdateは、そのフレーム内のすべてのUpdate(必要に応じてFixedUpdateも含む)の処理が終わったあとに、同じフレームの中で呼び出されるメソッドです。つまり、キャラクターやその他のオブジェクトの位置がすべて確定してから実行される、という位置づけになります。
もしカメラの追従処理をUpdateに書いてしまうと、実行される順番によっては、キャラクターがまだ移動しきっていない古い位置を基準にカメラが動いてしまうことがあります。その結果、キャラクターとカメラの間にわずかなズレやガタつきが生まれてしまうんです。
そのズレを防ぐために、「全員の位置が決まったあとに、最後にカメラだけを動かす」という役割をLateUpdateに任せている、とイメージすると分かりやすいかもしれません。

移動処理はFixedUpdateやUpdate、カメラの追従はLateUpdateというように、それぞれのメソッドに役割をひとつずつ持たせておくと、あとから見返したときにも処理の流れを追いやすいスクリプトになりますよ。
Unity6でvelocityがlinearVelocityに変わった点に注意
ここまで紹介してきた使い分けの考え方とは別に、もうひとつ知っておきたいのが、Unity6以降でのRigidbody周りの表記変更です。
Unity6では、RigidbodyおよびRigidbody2Dが持っていたvelocityというプロパティが非推奨(Obsolete)となり、代わりにlinearVelocityを使うように変更されました。これは公式のスクリプトリファレンスにも明記されている変更です。
// Unity6以降の書き方
rb.linearVelocity = new Vector3(moveX, rb.linearVelocity.y, moveZ);
使用しているUnityのバージョンによっては、velocityのままでも警告だけでエラーにならず動作するケースもあります。ただ今後のことを考えると、Unity6以降のプロジェクトではlinearVelocityに書き換えておくのが安心です。
また、これは断定できる情報ではありませんが、Unity6へアップデートした際に、先ほど紹介したFixed Timestepの設定値が初期値に戻ってしまうケースがあると一部で報告されています。

カクつきの対策として数値を変更していたはずなのに、いつの間にか戻っている…という場合は、念のためEdit > Project Settings > Timeの項目を確認してみるとよさそうです。
よくある質問
-
QFixedUpdateが1フレームで2回以上呼ばれることがあるのは不具合ですか?
-
A不具合ではなく、仕様として起こり得る動きです。FixedUpdateは一定間隔で呼ばれますが、その間隔と描画フレームの周期は完全には一致しないため、1フレームの中でFixedUpdateが呼ばれない回や、逆に2回続けて呼ばれる回が生じます。物理演算の計算自体は正しく行われているので、この回数のばらつき自体を気にして調整する必要は基本的にありません。
-
QAwake・Startのあと、UpdateとFixedUpdateはどちらが先に実行されますか?
-
A最初のフレームでは、通常FixedUpdateが先に一度実行されたあとにUpdateが実行される、という順序になります。ただしこれは毎フレーム固定の順番として厳密に意識するというより、初期化処理をAwakeやStartに書いておけば、UpdateとFixedUpdateのどちらが先でも困らない設計にしておくほうが実用的です。
-
Qスマホなど低スペック端末でも、FixedUpdateの間隔は変わりませんか?
-
AFixed Timestepの設定値自体は端末の性能によって変わることはなく、指定した間隔で呼び出されようとします。ただし処理が重すぎて1フレームの時間内に計算が終わらない場合、FixedUpdateの呼び出しが追いつかず、結果的に物理演算の更新頻度が実質的に落ちてしまうことはあります。低スペック端末向けには、Fixed Timestepの値を極端に小さくしすぎない、というバランス感覚も必要になってきます。










※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。
※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。