FixedUpdateについて考える

ユニティちゃんに付属しているスクリプトを見ていて、疑問に思う記述が。

f:id:taka_say:20140518142300j:plain

>リジッドボディと絡めるので、FixedUpdate内で処理を行う

とのコメントがあり、メインの処理がFixedUpdate内に記述されている。

FixedUpdateについての知識がなかったため、とりあえずググる
記事末尾に出典を纏めたが、良質な情報が日本語で載っていたため助かった。

参考記事曰く、

  • Updateはフレームの進行で、FixedUpdateは物理シミュレータの進行で使用
  • InputはFixedUpdateの中に書くな
  • Rigidbodyの値を操作するときはFixedUpdateを使え

という感じでしょうか。

公式リファレンスに

FixedUpdate should be used instead of Update when dealing with Rigidbody. For example when adding a force to a rigidbody, you have to apply the force every fixed frame inside FixedUpdate instead of every frame inside Update.

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour {
    void FixedUpdate() {
        rigidbody.AddForce(Vector3.up);
    }
}

との記述があるように、RigidbodyにAddForceなんかをする場合は、FixedUpdateの中でやらなければいけないようです。

ユニティちゃん付属のサンプルコードの中で取得しているGetAxisに関しては、押した押してないみたいな正確な処理が恐らく必要無いので、FixedUpdate内でのInput取得でも別段問題は無さそうだと思ったんですが、ジャンプ判定のInputもFixedUpdate内で取得していたので、これは余りよろしくない記述なのかなあと思いました。
というかRigidbody絡んでる処理がないから、Updateに記述しても正常に動作するような気が……?
というわけでFixedUpdateからUpdateに書き直してみましたが、ほぼ問題なく動きました。
カーブ走行時にだいぶ3Dがガタガタなっていましたが、恐らく三人称視点のカメラ追随コードがイマイチなのではないかと、テキトーな理由をつけておきます。


とはいうもののやはり気になったので、Mecanimのサンプルにくっついているコードを拝見させて頂きました。
どれもFixedUpdateは使用していなかったため、やはりここで用いているのは少々不適な感じがします。
GetAxis含む各々のInputもUpdate内で取得しているようだったので、そちらが正しいお作法なのだろうと推測されます。
うーん、ユニティちゃんのスクリプト書いた人はどういう意図だったんだろう……よく分からん。


とりあえず、Inputを取りつつRigidbodyに関する処理をFixedUpdateに記述する方法は以下のようにするらしい。

Bad Practice

using UnityEngine;

public class Test:MonoBehaviour{
    void FixedUpdate(){
        if(Input.GetKeyDown(KeyCode.Space)){
           //Action
        }
    }
}

Good Practice

using UnityEngine;

public class Test:MonoBehaviour{
    bool action = false;
    void Update(){
         if(Input.GetKeyDown(KeyCode.Space)){
             action = true;
         }
    }
    void FixedUpdate(){
       if(action){
           //Action
           action = false;
        }
    }
}

しかしまあ、キーの取得云々から、3Dキャラクターのアニメーションの設定、三人称視点カメラの作り方までmecanimサンプルを見れば全部分かるんだから、たまげたもんです。


FixedUpdateに関しては今後必ず使う場面があるだろうと思うので、理解を深めておきたいところです。


5/21追記
Unity 4.0 - Mecanim Animation Tutorial - YouTube
のコメント欄を見ていたら面白いやり取りが。以下原文と意訳。

Etillion2 か月前
There is a "bug" in the BotContolScript.cs because it is checking for input in the FixedUpdate() function, which results in the buttons sometimes not working. You will have to move them to the Update() function.

BotControlScript.csにはバグがある。
なんでかってーと、FixedUpdate内でinputのチェックをすると、入力の読み込みが適切に働かないことがあるから。
Input系はUpdateの中に移さなきゃいけないよ。

FragmentalStew2 か月前
I tried changing FixedUpdate() to Update(), but it didn't seem to make a difference.

FixedUpdateからUpdateに変えてみたけど、何も変わってないっぽいよ?

Etillion2 か月前
>FragmentalStew
Everything will look the same, but when you were using FixedUpdate() the buttons for stuff like jumping (not the walking tho) would work only 50% of the time because that function is not called every frame. Using Update() will fix that.

FragmentalStew、まぁ同じに見えるんだけど、君がジャンプのような動作(歩きとかじゃなくてね)の入力をFixedUpdate内で読み込むと、たった50%の時間でしか働かないんだ。これはFixedUpdateが毎フレーム呼ばれないことに起因する。Updateを使うことでこのバグは直せる。

FragmentalStew2 か月前
Ah, ok. Thanks.

へーそうなんだ、サンキュ。

Colin Laws1 か月前
Use fixed update for everything physics based, there is no error. 

エラーなんかねえよ、全てのPhysics系処理はFixedUpdate使え。

Etillion1 か月前
It's hard to separate that code into what should go into FixedUpdate() and what Update() because it is quite tightly integrated with each other. You would need to put some work into it, so the quickest way to fix it is to just use Update() for now.

FixedUpdateとUpdateはお互い非常に堅く統合されてっから、コードをどう分割するかってのは難しい。
そういう作業をやる必要があるだろうけど、とりあえず速攻で直すにはUpdate使えば良いよってこと。

Ed Hukina1 週間前
>Etillion
You're completely right, i had this same issue a few days ago and fixed it that way.

Etillion、君は実に正しい。何日か前に同じ問題に直面したけど、俺もその方法で直したよ。


というわけで以上ガバガバ意訳ですが、InputをFixedUpdate内で取得するのはエラーの温床になるみたいなのでやめましょうってことで!


参考
ゲームは初心者にやさしく: Unity初心者が学ぶ「Inputの正しい用法」
書籍『Unity入門』 - Unity におけるフレームと Update
Unity 〜UpdateとFixedUpdateの違い〜 | Learn iPhone, iOS, Objective-c, cocos2dx, Unity and ....?
灯火: Unity : FixedUpdate と Update の違い

Unity - Scripting API: MonoBehaviour.FixedUpdate()
Common Unity Gotchas | Unity Gems