【GDevelop】テキストオブジェクトに追記するのはヤバいというお話

スコアやステータスなどを表示したいときに便利なテキストオブジェクトですが、正しく利用しないと処理落ちの原因になったりするので注意が必要です。

そこで GDevelop のテキストオブジェクトに対し、どういう処理をすると負荷が高いかを実験してみました。

まず、テキストオブジェクトを 8 個用意し、次のようなイベントを実行してみます。

テキスト1 には普通に「あいうえおかきくけこ」を代入します。
テキスト2 には「あ~こ」までを 1 文字ずつ加算で追加します。
テキスト3 には大量のテキストを代入します。
テキスト4 には他とは違うフォントを設定しています。
テキスト5 にはテキスト1 と同じアクションを実行します。
テキスト6 にはテキスト1 と同じ文字数分、異なるテキストを代入します。
テキスト7 には大量のテキストを一度だけ代入します。
テキスト8 には一度だけ「あ~こ」までを 1 文字ずつ加算で追加します。

それを実行したプロファイラーの結果は、次のとおりです。
(プロファイラーの使い方や見方は、また別の記事を書きます😅)

events セクション内の値を見ることで、それぞれのイベントにどれだけ時間(負荷)がかかったか分かります。

セクション名時間(ms)% of parent% of total
テキスト10.01ms0.67%0.67%
テキスト2(加算で追記)1.34ms94.62%73.09%
テキスト3(多テキスト)0.01ms0.64%0.50%
テキスト4(違フォント)0.00ms0.11%0.09%
テキスト5(同テキスト1)0.00ms0.08%0.06%
テキスト6(違テキスト)0.00ms0.07%0.06%
テキスト7(一度・多)0.00ms0.03%0.03%
テキスト8(一度・加算)0.01ms0.59%0.46%

注目すべき点は、加算で 1 文字ずつ追記した場合の負荷の高さです。

一度に大量のテキストを代入した場合と比べても、100 倍以上の負荷がかかっています😥

追記時に内部的にどのような処理がおこなわれているのかは知りませんが、おそらく文字数が変わるたびに、文字の形状からオブジェクトのサイズを計算し直したり、なんやかんやする必要があるために、これほどの負荷がかかっているのではないかと、何も分かっていない私は推測します🤤

なお、events セクション内の値には画面の描画(render)にかかった時間は含まれていないことに注意してください。

また、テキスト1 と同じことをしているテキスト5 が、テキスト1 より負荷が少ないのは謎ですw
もしかしたらテキスト1 の時点で文字データは取得済みなので、テキスト5 ではその負荷が発生しなかったとかでしょうか。しらんけど。

追記したい場合の解決策

追記は負荷が高い、と言ってもイベント単位で追記したい場合もよくあります。

そんな時は、直接テキストオブジェクトへ追記するのではなく、代わりの変数を用意し、その変数へ追記を繰り返し、最後にその変数の値をテキストオブジェクトへ代入する、という流れにすることで、この問題を回避することができます。

念の為 1000 倍にしてみた(そしたら別の問題が……)

先の実験では、負荷が軽すぎて 0.01ms くらいしか差がなかったのですが、0.01ms なんて 0.00001 秒なわけで、もはや誤差レベルな可能性もあります。

そこで、次の画像のようにそれぞれのイベントを 1000 回繰り返すようにして、再度計測してみました。

小さな差でも、1000 回繰り返せば大きな差になるだろうという目論みです。
その結果は次のとおりです。

さすがに負荷が大きすぎて 521 フレームしか収集できていませんが、差を確認するには充分な数かと思います。

セクション名時間(ms)% of parent% of total
テキスト10.20ms0.05%0.05%
テキスト2(加算で追記)427.97ms99.79%99.70%
テキスト3(多テキスト)0.13ms0.03%0.03%
テキスト4(違フォント)0.13ms0.03%0.03%
テキスト5(同テキスト1)0.13ms0.03%0.03%
テキスト6(違テキスト)0.13ms0.03%0.03%
テキスト7(一度・多)0.01ms0.00%0.00%
テキスト8(一度・加算)0.11ms0.03%0.03%

……差が広がるどころか、見事に差が縮まりましたね😅

文字の多さや種類、フォントの違いでイベントの負荷に差はないようです。
※ なお、先にも書きましたが、画面の描画(render)にかかった時間は含まれていないことに注意してください。

そんなことより解せないのは、テキスト8 の負荷がそれなりにあるという点です。

テキスト8 のイベントには「一度だけ実行する」条件が設定されているのですが、解析を開始する前にその「一度」は実行済みのはずです。

そのためこの 0.11ms という負荷は、「一度だけ実行する」条件そのものによるものと思われます。

実は最初の画像(イベント画面の画像)を見れば分かると思いますが、テキスト7 には「シーンが始まった」条件を使用し、テキスト8 には「一度だけ実行する」条件を使用しています。

どちらも結果的には一度しか実行されないのですが、どうやら「一度だけ実行する」条件のほうが負荷が高いようです😲

実際、テキスト8 の「一度だけ実行する」条件を、「シーンが始まった」条件に変更して解析したところ、0.01ms となり、テキスト7 と同じ結果になりました。

思いも寄らない発見があり、色々と調べたくなってしまいますが、当初の目的は果たせていますので、これにて本件は終了とします😅

コメント

このブログの人気の投稿

ブラウザ上で動く GDevelop オンライン版を試してみた感想

GDevelop の「イベント」を正しく理解しよう

【GDevelop】オブジェクト間の距離で音量を変化させる方法