はかせのラボ

私の頭の中を書いていく雑記ブログです

Unity UnityのUpdate達

あいさつ

どうも、はかせです。
今日は熱っぽかったり頭痛や咳が出たりと
とにかく体調が悪かったので開発は休みました。
頭も大して動いていないような気がします。

ただなにも書かないのもあれだと思うので割とハマりやすいと思われる
UnityのUpdate関数達の紹介をしていきたいと思います。
(忘れそうになってたから備忘録がてらというのもある)

Update

毎フレーム呼び出される関数です。
Unityで作ってる人なら多分みんなお世話になっている関数だと思います。

ここには入力や現在の状態の更新などを行うコードを書くとよいと思います。
また他のオブジェクトに対するメッセージングなんかもそれ用のメソッドを用意してここで呼んでやるとうまくいきやすいと思います。
(状態確認を行いやすいのでNullReferenceとかが起きにくい)

ただこの関数はなにもしなければVsyncがオンになっているのと同じタイミングで呼ばれます。
つまり画面更新と同じタイミングですね。
(Vsyncとかについてはこれとかこれをどうぞ)

Updateメソッドが呼ばれる順番は不定です。
なので順番が大事なものはUpdateに書かない方がいいです。
(設定から優先順位をつけることは出来ますがあまり現実的な解決法ではないと思います)

あとUpdateに限った話ではないですがUnityの関数には呼び出しオーバヘッドがかかります。
1つ1つは大してですが数が増えたとき割と馬鹿になりません。
なので必要がなければそもそも書かないか
UpdateManagerみたいな呼び出し代行を作ると多少改善されます。

LateUpdate

Update関数が呼び出し終わった後に呼ばれます。
Updateに比べて知名度が圧倒的に低い気がしますが、
結構大事な関数だと思っています。

明確にUpdate処理の後に行いたい処理、
例えばカメラがプレイヤーを追従する
とかの処理はここに書くとよいと思います。

よくこういった処理は後述するFixedUpdateに書くべきという話がありますが、
こちらの方が確実です。
(Updateの後に呼ばれることが保証されているため)

FixedUpdate

一定時間間隔で呼ばれます。
この時間間隔は設定で変更可能です。
(初期値は0.02秒)

この関数には主に物理挙動を使うようなコードを書くと良いと思います。
UpdateやLateUpdateは単位時間あたりに呼ばれる回数が不定です。
なので処理状況や環境によって動きが早くなったり遅くなったり
瞬間移動したりします。
(多分Unity始めた人がハマることが多いと思われる)

対してFixedUpdateは呼ばれる間隔が決まっているので
常に一定の間隔で動いてくれます。

あとがき

今回はUnityのUpdateについてでした。
私もUpdateだけあればいいじゃんとUnityを始めた当初は思っていました。
ただ色々な環境で開発したりして他のUpdateの必要性を体感しました。
(最初に作ったブロック崩しが倍速になったのはいい思い出w)

色々書きましたが基本的には
・入力や自身のステータスの更新とかはUpdate
・更新された情報を同フレーム内で扱いたければLateUpdate
・物理挙動のような連続的な移動などはFixedUpdate

みたいな感じで使い分けると問題は起きにくいと思います。

それでは今回はこの辺でノシ

C++ 今日のリファクタリング ~マジックナンバー~

あいさつ

どうも、はかせです。
今回は久しぶりのリファクタリングです。

やったこと

マジックナンバーの掃除と冗長な書き方をしていたところの書き直しです。

えっ?これだけかって?
はい。これだけです。

いや私もこれだけだなんて思いたくないですよ?
ただ書き直してたらまぁマジックナンバーや冗長な書き方が出るわ出るわでorz

そんな感じで機能的にも見た目的にも一切進展がありません。
いつも通りですねw
ただそれだけだとあれなんで、
マジックナンバーについて書いてみたいと思います。

マジックナンバー

直訳すると魔法の数字です。
一般的にマジックナンバーは悪だとされています。

コードの中に意味を持っている数字がそのままある状態ですね。
コードにするとこんな感じですかね

mScore += 10;

スコアの変数に10点足されているみたいですね。

マジックナンバーが悪だといわれる理由は
・意味が確定しない
・変更もれがおきやすい

ことです。

10という数字はどういう意味の10なのかコード上からは読み取れません。
それが10点なのか10回なのかはたまた別の意味があるのか。
(スコアという変数に足しているからおそらく10点だろうというあたりは付けられますけどね)

仮に10点だったとしてもそれがのちに20点に変更された場合
この10点足しているコードを
手作業で全て探して変更しなければなりません。
おまけにVisualStudioとかIDEのコード補完の恩恵を受けることもできません。
これでミスや漏れを無くせというほうが無理な話です。

なので上のコードは

AddScore = 10;
mScore += AddScore;

こんな感じに書き直したらいいと思います。
こうすれば10という数字は
加算される点数を表していることがわかりますし、
加算される点数が変更されるときはAddScoreに入れる数字を変えるだけで済みます。
どれだけ色々なところで使っていても全てAddScoreでやっていれば漏れはありません。

マジックナンバーの掃除はこんな感じでやりました。
ただし
・調整中でなおかつそこでしか使っていない
・変数化して持つと膨大な数の変数定義が必要

な場合には後回しにしたり
コメントで済ましたりすることが多いです・・orz

特に今やっているようなオブジェクトの位置とかだと
それを変数化してプログラムで持つと大量の変数が必要になってしまうため
ちょっとな・・てなります。
こういう時は外部データに書き出して読み込んで適用させるっていうやり方が一番だと思います。

冗長な書き方

うまい言い方がわからないのでこういう言い方をしました。
ようはこういうコードのことです。

void Hoge()
{
    if(somethingFlg)
    {
        //何かの処理が長々続いている






    }
}

最初にif文で判定して真の場合のみ処理をしていますね。
このコードの何が冗長かというと
・ネストが1つ増えている
・偽の場合どうするか最後までみないとわからない

という点です。

ネストは深いとコードが追いづらくなるのはプログラム書いてる人なら
おそらく体感的にわかっていることだと思います。
偽の場合どうするかは、
書いてる本人は何もしないと最初から分かっているので
ストレスないでしょうけど
読む人からすれば偽だったらどうするのかとモヤモヤする可能性があります。

どちらにしても読み手にやさしくないコードということです。
これを手っ取り早く解決するのがEarlyReturnと呼ばれる書き方です。

void Hoge()
{
    if(!somothingFlg) return;
    //何かの処理が長々続いてる
}

これならばネストは少なくなりますし
偽の場合は処理をしないっていうことが最初に分かるので
モヤモヤも減ります。

あとがき

今回はコードの書き方テクニック的な何かでした。
マジックナンバーも冗長な書き方も急いで開発していたり、
仕様変更が重なると徐々に増えていくんですよね。

なんで気づいたタイミングで適時やっていくといいと思います。
後回しにしていると今回の私みたく1日のほとんどをその作業でとられてしますので。(戒め)

それでは今回はこの辺でノシ