表題通り。
「Unity Update 1秒間」とかで調べると色々とやり方がでてくるのですが、
なぜか処理がガクガクしたり処理落ちっぽい挙動をするようになった。
備忘録として対応方法を残しておきます。
初期実装
こちらの記事を参考に実装しました
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fcdn.qiita.com%2Fassets%2Fpublic%2Farticle-ogp-background-412672c5f0600ab9a64263b751f1bc81.png?ixlib=rb-4.0.0&w=1200&mark64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTk3MiZoPTM3OCZ0eHQ9VW5pdHklRTMlODElQTclRTMlODElQTAlRTMlODElODQlRTMlODElOUYlRTMlODElODQlRTIlOTclQUYlRTclQTclOTIlRTMlODElOTQlRTMlODElQTglRTMlODElQUIlRTUlODclQTYlRTclOTAlODYlRTMlODIlOTIlRTglQTElOEMlRTMlODElODYmdHh0LWFsaWduPWxlZnQlMkN0b3AmdHh0LWNvbG9yPSUyMzIxMjEyMSZ0eHQtZm9udD1IaXJhZ2lubyUyMFNhbnMlMjBXNiZ0eHQtc2l6ZT01NiZzPWY2YWFjNjM1ODI4ZGE2YTllZmU4YjY2Y2RjYzQ1MzU3&mark-x=142&mark-y=57&blend64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZoPTc2Jnc9NzcwJnR4dD0lNDBva3VoaWlybyZ0eHQtY29sb3I9JTIzMjEyMTIxJnR4dC1mb250PUhpcmFnaW5vJTIwU2FucyUyMFc2JnR4dC1zaXplPTM2JnR4dC1hbGlnbj1sZWZ0JTJDdG9wJnM9YjAyMzgwODkyNmVkNDJlM2U2ZTVjYzhiYTEyZjk3Zjg&blend-x=142&blend-y=436&blend-mode=normal&txt64=aW4g5qCq5byP5Lya56S-IGd1bWk&txt-width=770&txt-clip=end%2Cellipsis&txt-color=%23212121&txt-font=Hiragino%20Sans%20W6&txt-size=36&txt-x=156&txt-y=536&s=adbf9a9897fff85dbdb782051b88d17f)
private float timeleft = 1.0f;
void Update () {
//だいたい1秒ごとに処理を行う
timeleft -= Time.deltaTime;
if (timeleft <= 0.0) {
timeleft = 1.0f;
//ここに処理
}
}
ただ、これを実行するとなぜか処理がガクついたりしてしまいました。
原因を切り分けていると、timeleft = 1.0f; が原因のようです。
なんで?
って思ったけど事実そうだったので、別の方法を検討。
改善検討
Update関数の種類
色々と調べていると、Update関数は実行環境(PCのスペックとか)によって1秒間に呼び出される回数が違うようです。
もっと調べてみると、MonoBehaviourを継承したクラスでは以下のUpdate関数を使うことができるとのこと。
- Update
- LateUpdate
- FixedUpdate
こちらのページを参考にしました。
![](https://gametech.vatchlog.com/wp-content/uploads/cocoon-resources/blog-card-cache/196ba3840759cbb9946ba99ffa1d1781.png)
中でも、FixedUpdateは決められた間隔で実行されるらしいので、〇秒間に1回、という処理を実装しやすいとのこと。
というわけで、Update関数ではなくFixedUpdate関数を使用することにします。
デフォルトでは1秒間に50回呼び出されるようです。
このフレームレートはUnityメニューのEdit→Project Settings→Timeで設定出来ます。
https://gametukurikata.com/basic/update
とのこと。
これをいじればそれだけで1秒間に1回、とかできそうですが、そんなことしてほかに影響でないのか分からんかったのでデフォルトのまま。
タイマー変数の初期化のタイミング
↑で
timeleft = 1.0f; が原因
と書きましたが、なぜそれが原因になるのかまではわかりませんでした。
が、いろいろ試した結果、ifブロックの中でtimeleftに何か値を代入するとカクつくのがわかりました。
ので、これを極力単純化します。
そもそもUpdate関数ではなくFixedUpdate関数を使用するようにしたので、時間を計算する必要はなくなりました(秒間に呼び出される回数は一定なので)
ので、Time.deltaTimeは使用せず、単純にカウントアップすることにします。
また、ifブロックの中での代入を極力避けるように実装。
結論
というわけで実装がこちら。
// カウントアップ用の変数
private int count = 0;
void FixedUpdate() {
if (count % 50 == 0) {
//ここに処理
}
if (count >= 4320000){
count = 0; // 24時間分カウントアップしたら初期化する
}
count++; // カウントアップ
}
countの値がmod50(50で割った余りが0)の時に処理を実行するように。
FixedUpdateは1秒間に50回実行されるので、mod50の時に処理を実行することで
実質的に秒間処理を実現しています。
また、count変数の初期化の回数を減らすことで処理のカクつきも抑えられました。
この書き方のいいところは
void FixedUpdate() {
if (count % 50 == 0) {
//1秒間に1回処理
}
if (count % 500 == 0) {
//10秒間に1回処理
}
if (count % 3000 == 0) {
//1分間に1回処理
}
if (count >= 4320000){
count = 0; // 24時間分カウントアップしたら初期化する
}
count++; // カウントアップ
}
のように、1つのFixedUpdate関数内でそれぞれ違う間隔で違う処理を実行させることができることですかね。
多分、他にいい方法があると思うのですが、これが自分の脳みそでもわかる程度には簡単な実装方法だと思いました。
以上、備忘録。
コメント