1. このサイトではcookie (クッキー) を使用しています。サイトの利用を継続した場合、cookieの使用に同意したものとみなさせていただきます。 詳しくはこちらをご覧ください。

ゲームの『重さ』対策を研究して改善に励むスレ

たかッシュ2018-03-18に開始した「ゲーム制作」の中の討論

  1. たかッシュ

    たかッシュ ユーザー

    処理の重さ対策について考えてみませんか?

    以下長文になりますが、検証したことなどを一つずつ実践して重さ対策について考えていきたいと思いますので
    よろしければお読みいただいて皆さんにお付き合いいただけましたら嬉しいです。

     18年10月13日追記
     ずっとスレッドを放置してしまい、もう自分からの調査進展もないと思いますが、
     重さ対策をこれから考えようとして調べたい人がここに辿り着くかもしれないので
     重さ対策観点で重要視すべきことを指標として書いておきます
     ●重さに影響高そうな動作まとめ
      ・並列処理、並列処理やループ中の条件分岐の繰り返し、条件分岐のネスト、
      ・スイッチ、変数、セルフスイッチの一斉大量反映
      ・広いマップやイベント人口の多いマップの制作
      ↑こういったシステムが制作時にあると重くなりやすいので、
      これらのシステムを利用した際にはご自身ですぐテスト動作確認をして
      「重くないかどうか」を動かして見て調べるのが原始的ですが一番いいと思います。
      その際、制作に使われるPCではスペックが高く動作に問題ないように思えることもあるのですが、
      低スペ環境(スマホなど)で重さを確かめて見るとスペック差で重さが顕著になることもあります。
      スマホ向けゲームを視野にする方はスマホからの動作確認も忘れずに気をつけてください。

      (べつにこれらのシステムを「使うな!」と過激に否定するところではありません。)
      (むしろ複雑なシステムを実装しようと思えば絶対に必要になるシステムですのでどんどん使うべきです。)
      (どれも便利で必要なシステムですから恐れずに使ってください…!!更に動作良好に保てたら嬉しいねってだけのことです)

      さて、スイッチは少し意外なところなのでなぜ重さに影響しそうなのかというと
      スイッチ反映時にマップ内のスイッチ反映やコモンイベントのスイッチ動作実行などが監視されているので
      その際にマップ内に作成されているイベントやコモンイベントをすべて探索チェック処理をするためです。
      そのへんが少し重さに掛かる可能性があります。

      実はマップ内更新のリフレッシュ作動を通さないスイッチ反映法もあり、
      $gameVariables._data[変数番号] = 代入 などでマップ内リフレッシュを走らせずにこっそり値だけ変えることも可能です。
      (スレ内のビービーさんも変数処理で触れてくださっています)

      マップ内リフレッシュを走らせずこっそり各種スイッチを書き換える方法
       スイッチの場合:$gameSwitches._data[スイッチ番号] = true or false
       変数の場合:$gameVariables._data[変数番号] = 値や"文字"
       セルフスイッチの場合↓
       var key = [マップID, イベントID, "A"] //"B" "C" "D"可
       $gameSelfSwitches._data[key] = true or false

      基本的な考えとしては $game~~._data[配列] で直接代入できるみたいです。

      状況によってはこうやってマップの更新をさせずに書き変えても大丈夫なシステム構築時なら
      この方が重くしないで済むこともあるかもしれません。

      各自、制作者さまで試行錯誤は必要なことだと思いますが、いろいろ試して重さを緩和させてみてください。

     3月18日追記:
     https://game.nicovideo.jp/atsumaru/games/gm6354?key=9f181052a0d3
     スレで書いてる長々とした実験は文章を読むだけでは何を言ってるのか伝えづらいと思うので
     こちらを開いてもらって把握してもらう方が手っ取り早いかもしれません


    ↓以下古い書き込みで重さ実験などをしてたときのもの

    ARPGやアクションゲームやシューティングゲームなどをツクールでつくろうとすると
    並列処理やスイッチ処理などが大量に出てくると思います。
    でも並列処理とスイッチ処理が常時稼働なアクションゲームなどを無理やりツクっても
    『重い』
    ですよね?

    ツクールは「RPG」と冠した名前ではありますがRPG以外のジャンルのゲームもツクって公開できます。
    が、そのようなRPGとは違った特殊ゲームを実装しようとすると
    処理が重かったりして思うように動いてくれなくて難航したりします。

    そこで、重さ対策に良いアルゴリズムや処理自体の重さを熟知して重さ対策を講じて実装していくことで
    そういった特殊ゲームを作っても重くならないようにしていこう、というのを考えたり研究したりするのが趣旨のスレッドです。

    私はまず、重くなる要因トップとしてよく語られているであろう
    「スイッチを動かすとそのマップ内にいる全イベントとコモンイベント全件がスイッチを監視して同期する必要があるため重くなる」
    という言説を度々見たことがありますが
    その状態が本当に重くなってるのかどうか自分で確かめたわけではないので
    実際にそれを試してみました。


    Image00001.png
    この画像のような並列処理実行マシーンを50x50のマップ内に1マス間隔に大量に設置していき400人程度コピペし
    こいつらにスイッチ操作を施して本当に重くなるのかを検証していくことにしました。
    実際の動作を実際に確かめて見るわけですからちゃんと重いかどうか肌で感じて分かります。

    2.png 3.png 4.png 5.png 6.png 7.png 8.png
    こいつらの中身は上記画像の通りでこんな感じです。
    スイッチを動かせば並列処理で発動してコモンイベントからの操作で自由にイベントコマンドを全員が展開できるように6段分スイッチをセットしました。
    (セルフスイッチAの箇所だけ人物画像が違うのは後で実験に使われますが今は違う簡単なスイッチ操作について検証したいのでそこは置いておきます)


    コモン変数プラス1版.png 変数加算.png
    コモンイベントはこのように変数の操作でもやってみましょうか。

    400人並列コモン参照で変数1に対して+1の値を加算し続けるという過酷な処理が見込まれます。
    一体どれだけ重くなって動かなくなって暴走してしまうのか楽しみですね♪

    続きます。
     
    最後に編集: 2018-10-13
    #1
    yura, metab, ワタベ他4人がいいね!しています
  2. たかッシュ

    たかッシュ ユーザー

    あとはスイッチ操作用の仕掛け人が要るので
    話し掛けたら安全に実行できるスイッチ作動人を設置します。
    こいつはスイッチ作動させてスイッチ作動後には変数の値を確認できるという変数値開示君にでもするといいでしょう。

    スイッチ仕掛け人1.png スイッチ仕掛け人2.png マップ.png

    これで準備OKです。

    ではお待ちかねの実験場マップへ飛び込んで並列処理地獄の変数操作に暴れてもらいましょうヾ(*´▽`*)ノ


    設置したスイッチ仕掛け人に話し掛けてスイッチ作動させて何事もないのでもう1回押して変数を聞くと…

    3万.png

    (ちょっと一呼吸置いただけの1回目の会話で)
    あっという間に3万も増えてます( ゚д゚ )!

    どんどん増える.png

    話す度にどんどん値が増えていきます!

    この状態でマップ内を歩いてみたりしてもカクカク感や大きな処理落ちや重さはそれほど感じません。
    この時点の動作状況が実際のゲームのプレイ中に生じたとしても
    私は「許容できるレベル」だと思います。


    つまり、
    「並列処理とスイッチ操作等は重さの元凶と言われているが実際にやってみれば変数などを大量操作しても必ずしも重くなるわけではない。」ということが見えてきます。
    並列処理とスイッチ操作で重くなる事例が多く見られるのはその中で『重くなる処理』を抱えてツクってるからということになるのでしょう。
    これで並列処理とスイッチ操作の汚名は少し晴らせた気がします。


    コンピューターってやつは凄いもので演算やさまざまな計算処理というものが大得意です。
    一瞬の間に膨大な数の処理を終わらせてしまいます。
    変数を加算したりスイッチ操作したりしても重くない動作範囲内でのスイッチ操作なら重くなかったのですね。
    変数をあれだけ大量に掴ませて+1加算をさせ続けても普通に動くのだからすごいものです。


    こんな感じで重さ対策を学んでサクサク動作する良いゲームを作って世に出せれば
    プレイする人も気持ちよくプレイして遊んでくれるでしょうから
    ゲーム動作時の『重さ』に対しても軽視せずに向き合っていきたいものです。


    さて、このあとコモンイベントを操作して400人軍のイベントコマンド動作テストをいろいろやったのですが
    移動ルートの設定で 400人を適当に歩かせる などをすると少し重くなったように感じました。

    上下動コモン.png 上下に動く.png
    (上記コモンは一斉に400人分を上下に常に歩くようにセットし
    その起爆に使ったスイッチをOFFって並列処理もOFFられて
    移動ルートを継承したカスタム自立移動から常に上下に歩いてもらうという内容になります)

    キャラを歩かせて動かすという動作には位置を読んだり書いたり人物の画像も上向き画像下向き画像と方向に合わせて描画したりして大変なので重くなるのでしょうか??
    先ほどの変数+1加算と比べた体感としても、400人常時歩かせてる方が重かったです。
    この歩きテストの実動時は「スイッチ」も「並列処理」も一切触れていない状態なのに
    重いもんは重いわけですからね。
    スイッチや並列処理のせいにするのは良くないなとよく分かりましたよ。

    まあでも移動ルートコマンド内にもいろいろな動作がありますが
    ジャンプはそこまで重くなかったような気がします…
    ジャンプ.png
    ジャンプが重くないのなら、歩き移動の何がどう作用して重さに掛かってるのかはよくわからないですね。

    (書き込み次に続きます
    必要な検証や情報を書いているつもりですが、長い…
     
    最後に編集: 2018-03-19
    #2
    metab, 神無月サスケネコタ がいいね!しています
  3. たかッシュ

    たかッシュ ユーザー

    7.png セルフAON.png セルフA.png

    また、セルフスイッチA箇所に画像の違う人物を設定しておいてありましたが
    あのセルフスイッチAを仕込んでコモンイベント15(セルフスイッチAに対応のコモン内)にセルフスイッチAをOFFというものを入れると
    キャラクター画像が瞬時にビガビガ入れ替わる状況になります。
    これは動作上はカクカクしたりせず大丈夫でしたが、PCのCPU使用率は上がってとても全力疾走で頑張って処理させる感じになっていました。
    一斉に切り替わり瞬点滅を繰り返す.png


    8.png セルフBON.png セルフB.png
    逆にセルフスイッチBのON操作を入れると同じ人物画のままで似たような状況ができるようにあらかじめ仕込んでありましたが、
    人物画に変化のないこちらでなにかをさせるとCPU使用率も平時と変わらず重くないのです。
    つまりスイッチ読んで 人物画を切り替える必要が生じたというその描画の方の処理が重いのではないでしょうか?


    描画が入ると重いのか?ということで
    次にイベントコマンドの「ピクチャの表示」で48x48サイズのスライムピクチャを用意し
    このピクチャを大量展開してみると、
    これは意外なことに重くなかったです。
    ピクチャコモン.png Image00044.png

    先述のセルフスイッチA箇所の検証では人物画描画に変化があると少し動作が重くなると言いましたが
    じゃあピクチャの表示も絵の描画だから重いのかというとそういうわけでもなく、
    結局はツクールから生まれたゲームの内部処理のことなので
    その処理工程がプログラム的にパワー要るのかその処理は重いのかどうかみたいなところなんでしょうね。



    こうやって色々試してみるとわかりましたが
    ツクール内にあるイベントコマンドの処理だけでみても重い処理と重くない処理というものは確実に存在します。
    負荷の大小を見極めることが重くない軽快なゲームを作るカギだと思います。

    「ストーリーも練ってゲームバランス調整も完璧で素晴らしい部品の集合体で良質なゲームが作れたと思ったら最後に動かしてみるとゲームが重かった!」なんて完成の段階で重さにやられないためにも
    常日頃から重さ対策を学ぶ必要はあると思います。

    皆さんの重さ対策の実践技や体験談など、理論や工夫や小技などいろいろ教えてもらえるととても嬉しいです。
    重くない快適なゲームを目指して良いゲームをツクりましょう♪
     
    最後に編集: 2018-03-18
    #3
    神無月サスケ, チョコワ部ネコタ がいいね!しています
  4. たかッシュ

    たかッシュ ユーザー

    私がこのように重さ対策の必要性を感じたのは現在アクション系のゲームを一からツクっていて
    最初に適当に設計して動いたのを確認して、それ以降ガンガンいこうぜとノリに乗ってツクっていくという作業をしていたのですが
    いざキリのいいところで実際にテストプレイをしてみるとこれがすごくカックカクで重かったのです。
    重さに頭を抱えながらその最初の実装の骨組みから見直して
    処理の流れを少しでもスムーズにいけるように組み直したり重そうな箇所を切ってと改良していったら
    やっと動作の重かった部分が解消されてプレイ時に良好に動作するようになって、なんとかなったのですが
    始めから『重さ』に気をつけて考慮する視点を持っていればこんな改修工事をしなくて済んだのになと、
    これからはちゃんとゲームをプレイする人のことを考えて重さ対策しなきゃいけないなと、
    重量級の激重ゲームを自ら生み出してしまった経験から反省したのです。

    今の時代はネットに繋ぐのもスマホの人が増えているという傾向もあり
    スマホのプレイヤーも増えているので、世間にはPCよりも非力スペックなスマホで遊んでくれる人もいるかもしれません。
    そのときに『重い』ということだとゲームを遊んだときの印象が下がってしまうでしょう。
    どう重さ対策をしていくかというのはゲーム作りにとても大事な要素だと思います。
    皆さんも処理の重さの改善に励んでみませんか。
     
    最後に編集: 2018-03-19
    #4
    神無月サスケ がいいね!しました
  5. ネコタ

    ネコタ ユーザー

    こんにちは。

    コモンイベントの処理が長くなると重くなるというのを聞いたことがあります。どの程度を言うのかは分かりませんが、条件分岐と変数の処理(1回)だけの塊を255個組んでみたところ、私のゲームでは全く重くなりませんでした。

    自分で見つけたものに、条件分岐とループを重ねすぎると重くなる現象を確認しました。

    どちらが原因の主体かは切り分けて検証していないので、はっきりしていないのですが、条件分岐に条件分岐を入れ子して、それが8個続いた時、急激に重くなりました。

    もともとループ構造内の処理としていたので、その中で工夫して条件分岐処理を分割させることに成功した結果、処理速度が元に戻りました。どうやら条件分岐をある程度(たぶん8個以上)重ねると非常に重くなるようです。

    (あるいは、このシステムが乱数を用いた確率での分岐を多様していたため、数パーセントを得るために大量の思考を重ねたためとも考えられます。しかし、これについてはその時々で処理時間がまちまちだったように記憶してるので、無関係ではないにしろ、急激に重くなった原因の主体では無いと判断しました)

    だいぶ前の事(日本でのツクールMV発売前後のあたり)でうろ覚えな情報ですので、実際に検証していただけると助かります。
     
    最後に編集: 2018-03-18
    #5
    まるたん, 神無月サスケたかッシュ がいいね!しています
  6. たかッシュ

    たかッシュ ユーザー

    ネコタさんこんにちは。情報ありがとうございます。
    コモンイベントの長さや条件分岐からのループや、条件分岐の入れ子実装が重くなるということはありそうですね。
    今はまだ試せていませんが、要検証事項ということで頭に入れておきたいです。


    先ほどの400人構成のテストが例えると横に太さを太くした処理体制だとすると
    太さよりも深さ(一人に対する処理が長かったり、複雑である)の方が重くなるなどの着眼点はありえそうな話です。
    実際にイベント10件程度しか置いてないマップであろうとも
    そいつらにそれぞれ複雑な処理を割り振ってゲームを組んで動作させると なんじゃこの重さはと嘆きたくなるくらい重くなることはよくありますからね。
    深さの方が重さに密接に影響するのかもしれません。

    よく世間で言われる「並列処理とスイッチが重いという話」も
    実際はそのなかに多段で組んだ複雑な条件分岐なども組み込まれているでしょうから
    そういう連動関係のなかで重いと認知されているのかもしれません。


    ところで、前述した400人並列テストで変数加算+1を400人体制で一生やり続ける処理は重くないと言ったわけですが
    変数ではなく「経験値の増減」を+1とやるとめちゃくちゃ重かったことを報告します。
    経験値の増減.png Image00008.png
    ゲームデータ内の経験値にアクセスすることがそこまで重くなるとでもいうのでしょうか?


    所持金の増減.png Image00010.png
    しかし経験値増減と似たような「所持金の増減」の方は重くならないのです。
    CPU使用率で見ても経験値増減の重さの忙しさとは打って変わって楽勝な感じです。
    これは変数加算+1と同じような感じです。
    所持金操作なんてへっちゃらさと常時400並列体制なんかでは無傷です。


    でもこの比較で差が生まれたことにより
    「経験値の増減」は理由は謎すぎますが「こいつは重い処理なのだ」と差が明確になったので
    やはり単一のイベントコマンドの処理内容によっても重さに違いがあり
    それぞれイベントコマンド自体を見極めて区別して組んでいくべきだという指標になります。
    重いヤツは重いし、重くないヤツは重くないのです。
    作る人が自分でテストしながら重さに気付いて『重い…』と実感するほどの違和感があったら
    重くなった要因の箇所を切ったり、重かった処理手順を直しつつも同じような描写ができるやり方に切り替えていって対処するというのが現実的な重さ対策だとも思います。
    やはり作ってる人が着手中の面白いゲームを作ってやりたい願望は一番でしょうから
    重さに敏感に気付いて察知して直すのも制作者の課題だといえそうです。
     
    最後に編集: 2018-03-18
    #6
    神無月サスケネコタ がいいね!しています
  7. くろうど

    くろうど ユーザー

    こんにちは。
    いつも、ゲームの動作を軽くしたいと思っているので、よい研究だと思います。

    ただ、水を差すようですが、JavaScriptのソースコードを見て、当たりを付けるのもひとつの手かと思います。
    このままでは、全部のイベントコマンドに対して動作検証することになりそうなので。

    そこで、オーダー(計算量)という物があります。
    簡単に言うと、その処理での最大処理回数を求めて処理の重さを表現するものです。

    単純な例を挙げると、
    1つの処理は、1です。
    ループ回数 n回の処理は、nです。
    n回のループが2重になっていたら、nの2乗です。

    nの2乗 > n > 1 なので、2重ループは重い処理だなぁ~って感じます。

    つまり、RPGツクールMVのイベントコマンドの裏で行われている処理がどの程度の計算量なのかを調べれば、重そうなイベントコマンドの当たりが付けられると思われます。

    もっとも、コアスクリプトの向こう側で、ライブラリの処理や、ブラウザの処理もありますので、最終的には実際に動かさないと分からないと思いますが、軽そうな処理と重そうな処理に分ける事くらいは出来ると思います。

    ご参考までに。

    ▼参考
    [初心者向け] プログラムの計算量を求める方法
    https://qiita.com/cotrpepe/items/1f4c38cc9d3e3a5f5e9c
     
    #7
    metab, 神無月サスケ, たかッシュ他1人 がいいね!しています
  8. ビービー

    ビービー ユーザー

    こんばんは。
    私も以前処理を軽くしたくてちょっと調べたので情報提供させていただきます。

    変数の処理やスイッチの切り替えをするとマップがリフレッシュされてマップ内のすべてのイベント、すべてのページの出現条件を判定するので重くなるという記事を見たのでそこを検証してみました。

    検証は
    ・イベントコマンドの変数の加算で+1
    ・スクリプトでリフレッシュが入る$gameVariables.setValue(1,$gameVariables.value(1) + 1)
    ・スクリプトでリフレッシュをしない$gameVariables._data[1] = $gameVariables.value(1) + 1
    ・プラグインコマンドでリフレッシュが入る
    ・プラグインコマンドでリフレッシュをしない
    の5パターンで変数が10000になるまでの時間を計測しました。

    イベント内容
    ◆変数の操作:#0001 = 0
    ◆変数の操作:#0002 = 0
    ◆変数の操作:#0003 = 0
    ◆変数の操作:#0004 = 0
    ◆変数の操作:#0005 = 0
    ◆変数の操作:#0006 = 0
    ◆変数の操作:#0007 = 0
    ◆変数の操作:#0008 = 0
    ◆変数の操作:#0009 = 0
    ◆変数の操作:#0010 = 0
    ◆変数の操作:#0011 = 0
    ◆変数の操作:#0012 = 0
    ◆変数の操作:#0013 = 10000
    ◆スクリプト:console.time('イベントコマンド');
    ◆ループ
    ◆変数の操作:#0001 += 1
    ◆変数の操作:#0002 += 1
    ◆変数の操作:#0003 += 1
    ◆変数の操作:#0004 += 1
    ◆変数の操作:#0005 += 1
    ◆変数の操作:#0006 += 1
    ◆変数の操作:#0007 += 1
    ◆変数の操作:#0008 += 1
    ◆変数の操作:#0009 += 1
    ◆変数の操作:#0010 += 1
    ◆変数の操作:#0011 += 1
    ◆変数の操作:#0012 += 1
    ◆条件分岐:#0001 ? #0013
    ◆ループの中断

    :分岐終了

    :以上繰り返し
    ◆スクリプト:console.timeEnd('イベントコマンド');
    ◆変数の操作:#0001 = 0
    ◆変数の操作:#0002 = 0
    ◆変数の操作:#0003 = 0
    ◆変数の操作:#0004 = 0
    ◆変数の操作:#0005 = 0
    ◆変数の操作:#0006 = 0
    ◆変数の操作:#0007 = 0
    ◆変数の操作:#0008 = 0
    ◆変数の操作:#0009 = 0
    ◆変数の操作:#0010 = 0
    ◆変数の操作:#0011 = 0
    ◆変数の操作:#0012 = 0
    ◆スクリプト:console.time('スクリプトsetValue');
    ◆ループ
    ◆スクリプト:$gameVariables.setValue(1,$gameVariables.value(1) + 1);
    :     :$gameVariables.setValue(2,$gameVariables.value(2) + 1);
    :     :$gameVariables.setValue(3,$gameVariables.value(3) + 1);
    :     :$gameVariables.setValue(4,$gameVariables.value(4) + 1);
    :     :$gameVariables.setValue(5,$gameVariables.value(5) + 1);
    :     :$gameVariables.setValue(6,$gameVariables.value(6) + 1);
    :     :$gameVariables.setValue(7,$gameVariables.value(7) + 1);
    :     :$gameVariables.setValue(8,$gameVariables.value(8) + 1);
    :     :$gameVariables.setValue(9,$gameVariables.value(9) + 1);
    :     :$gameVariables.setValue(10,$gameVariables.value(10) + 1);
    :     :$gameVariables.setValue(11,$gameVariables.value(11) + 1);
    :     :$gameVariables.setValue(12,$gameVariables.value(12) + 1);
    ◆条件分岐:#0001 ? #0013
    ◆ループの中断

    :分岐終了

    :以上繰り返し
    ◆スクリプト:console.timeEnd('スクリプトsetValue');
    ◆変数の操作:#0001 = 0
    ◆変数の操作:#0002 = 0
    ◆変数の操作:#0003 = 0
    ◆変数の操作:#0004 = 0
    ◆変数の操作:#0005 = 0
    ◆変数の操作:#0006 = 0
    ◆変数の操作:#0007 = 0
    ◆変数の操作:#0008 = 0
    ◆変数の操作:#0009 = 0
    ◆変数の操作:#0010 = 0
    ◆変数の操作:#0011 = 0
    ◆変数の操作:#0012 = 0
    ◆スクリプト:console.time('スクリプト_data');
    ◆ループ
    ◆スクリプト:$gameVariables._data[1] = $gameVariables.value(1) + 1;
    :     :$gameVariables._data[2] = $gameVariables.value(2) + 1;
    :     :$gameVariables._data[3] = $gameVariables.value(3) + 1;
    :     :$gameVariables._data[4] = $gameVariables.value(4) + 1;
    :     :$gameVariables._data[5] = $gameVariables.value(5) + 1;
    :     :$gameVariables._data[6] = $gameVariables.value(6) + 1;
    :     :$gameVariables._data[7] = $gameVariables.value(7) + 1;
    :     :$gameVariables._data[8] = $gameVariables.value(8) + 1;
    :     :$gameVariables._data[9] = $gameVariables.value(9) + 1;
    :     :$gameVariables._data[10] = $gameVariables.value(10) + 1;
    :     :$gameVariables._data[11] = $gameVariables.value(11) + 1;
    :     :$gameVariables._data[12] = $gameVariables.value(12) + 1;
    ◆条件分岐:#0001 ? #0013
    ◆ループの中断

    :分岐終了

    :以上繰り返し
    ◆スクリプト:console.timeEnd('スクリプト_data');
    ◆変数の操作:#0001 = 0
    ◆変数の操作:#0002 = 0
    ◆変数の操作:#0003 = 0
    ◆変数の操作:#0004 = 0
    ◆変数の操作:#0005 = 0
    ◆変数の操作:#0006 = 0
    ◆変数の操作:#0007 = 0
    ◆変数の操作:#0008 = 0
    ◆変数の操作:#0009 = 0
    ◆変数の操作:#0010 = 0
    ◆変数の操作:#0011 = 0
    ◆変数の操作:#0012 = 0
    ◆スクリプト:console.time('PコマンドSetVal');
    ◆ループ
    ◆プラグインコマンド:SVR+ 1 1
    ◆プラグインコマンド:SVR+ 2 1
    ◆プラグインコマンド:SVR+ 3 1
    ◆プラグインコマンド:SVR+ 4 1
    ◆プラグインコマンド:SVR+ 5 1
    ◆プラグインコマンド:SVR+ 6 1
    ◆プラグインコマンド:SVR+ 7 1
    ◆プラグインコマンド:SVR+ 8 1
    ◆プラグインコマンド:SVR+ 9 1
    ◆プラグインコマンド:SVR+ 10 1
    ◆プラグインコマンド:SVR+ 11 1
    ◆プラグインコマンド:SVR+ 12 1
    ◆条件分岐:#0001 ? #0013
    ◆ループの中断

    :分岐終了

    :以上繰り返し
    ◆スクリプト:console.timeEnd('PコマンドSetVal');
    ◆変数の操作:#0001 = 0
    ◆変数の操作:#0002 = 0
    ◆変数の操作:#0003 = 0
    ◆変数の操作:#0004 = 0
    ◆変数の操作:#0005 = 0
    ◆変数の操作:#0006 = 0
    ◆変数の操作:#0007 = 0
    ◆変数の操作:#0008 = 0
    ◆変数の操作:#0009 = 0
    ◆変数の操作:#0010 = 0
    ◆変数の操作:#0011 = 0
    ◆変数の操作:#0012 = 0
    ◆スクリプト:console.time('PコマンドNotRef');
    ◆ループ
    ◆プラグインコマンド:SV+ 1 1
    ◆プラグインコマンド:SV+ 2 1
    ◆プラグインコマンド:SV+ 3 1
    ◆プラグインコマンド:SV+ 4 1
    ◆プラグインコマンド:SV+ 5 1
    ◆プラグインコマンド:SV+ 6 1
    ◆プラグインコマンド:SV+ 7 1
    ◆プラグインコマンド:SV+ 8 1
    ◆プラグインコマンド:SV+ 9 1
    ◆プラグインコマンド:SV+ 10 1
    ◆プラグインコマンド:SV+ 11 1
    ◆プラグインコマンド:SV+ 12 1
    ◆条件分岐:#0001 ? #0013
    ◆ループの中断

    :分岐終了

    :以上繰り返し
    ◆スクリプト:console.timeEnd('PコマンドNotRef');

    結果は以下になりました。
    =========================
              一回目  二回目  三回目
    イベントコマンド : 102.872 : 105.265 : 105.512
    スクリプトSetVal : 936.899 : 855.410 : 959.678
    スクリプトNotRef : 945.602 : 958.501 : 929.143
    PコマンドSetVal : 143.103 : 123.937 : 137.849
    PコマンドNotRef : 118.864 : 101.229 : 100.920
    =========================
    イベントコマンドでやるのが一番安定して早いという結果になってしまいました…
    そしてスクリプトで行うと9倍の時間がかかっていますね。
    マップ内のイベント数やページ数によっても変わってくるんでしょうけど一応結果はこんな感じでした。

    ですがプラグインコマンドでリフレッシュをおこなわない方法もなかなか好タイムですよね。
    なので私の個人的見解ではプラグインコマンドでスイッチ・変数を切り替えた際にマップのリフレッシュをするかしないかを切り替えることができるプラグインがあれば最速タイムになるのではないかと思ったんですが、私の技術では作れないので諦めて検証を終えました。

    以上が私の検証内容になります。
    何かの参考になれば幸いです。

    以下に参考にした記事へのリンクを張っておきます。
    ツクールMVで作ったゲームが重くなったときの指針
    処理の時間計測方法
    並列処理でスイッチや変数を操作すると重くなる

    使用した自作プラグインもアップしておきます。
     

    添付ファイル:

    #8
    metab, 神無月サスケ, terunon他3人がいいね!しています
  9. たかッシュ

    たかッシュ ユーザー

    >くろうどさん
    情報ありがとうございます!
    とても勉強になります。

    水をさすなんてことはないです。
    「オーダー」という計算量の考え方を知らなかったので教えていただけてとても勉強になりました。
    こういった計算や思考ができるようになると処理の重さに優しい快適なゲームが作れるようになるんでしょうね。
    良いゲームをツクるためには幅広い知識が必要なんだなと思います。


    >ビービーさん
    情報ありがとうございます!
    ベンチマークのテストのようにやってくださった結果を教えていただけて
    どの変数処理が速いか遅いか明確によくわかりました。

    変数が操作されるという点だけで見ればプレイヤーにとって返ってくる展開は同じようなものですが
    内部的な処理速度ではまったく違った結果になってきそうですね。
    変数を取り扱う際にはいただいた情報をもとに気をつけていきたいです。
    スクリプト書きは速いのかと思ったらイベントコマンドの方が速いのにはビックリです。
    プラグインコマンドはスクリプトよりは速いようなので、
    お手製のゲーム内システムにおいてもプラグイン化できそうな処理工程をプラグイン化すると速くできそうですね。


    皆さん書き込み・閲覧いただいてありがとうございます!
    引き続き、制作の重さ対策に関するあれやこれやのお話をお待ちしています!
     
    #9
    神無月サスケ がいいね!しました
  10. リンクス

    リンクス ユーザー

    良いスレッドだと思います。個人的にはAce以前の古いRPGツクールやラノゲツクールも対象に入れて良いと思います。
    せっかく良いシステムやスクリプト(プラグイン)を作っても重かったら意味が無いと思うので。
     
    #10
    神無月サスケ がいいね!しました
  11. しぐれん

    しぐれん ユーザー

    並列動作が重くなる原理ですが、以下のような話です。

    まずイベントコマンド「スクリプト」が重いのはeval()という重い関数が走るためです。
    eval()は毎回ソースコードをコンパイルして、キャッシュしないためどうやっても遅いです。

    通常の変数操作では$gameMap.requestRefresh()が呼び出されます。
    なお1回requestRefresh()を呼び出してしまったら、2回目以降のrequestRefresh()でも関係ありません。
    ただ、そんな状態は間違いなく重いでしょう。

    ビービーさんも書き込んでいますが、一時的にプラグインコマンドでリフレッシュを抑制する方法ですが、これは結構確実です。

    そもそもツクールで変数の操作をやるのは結構オーバーヘッドが大きいです。
    具体的には変数の操作のイベントコマンドを見つけ出して、さらに操作パターンを解析するためです。

    Game_Map.update()から数えて7個関数を挟むので、アクションゲームを動かすには問題が出そうなレベルです。
    イベントコマンドを1個動かすだけで関数が3つぐらい呼び出されるので、コマンド処理数*3でかなり大きくなります。

    経験値の増減が重いとありますが、これは経験値曲線からレベルアップを再計算するからだと思います。
    レベルアップの方法を変えれば、軽くできる可能性があります。

    最速はアクション部分をプラグインとして作成する方法です。
    正直、イベントコマンドでややこしいのを組むのであればプラグインを書いた方が楽です。
    プログラムは何度も書けば練習できます。
    ただ、そこまでやるとツクールを使わずUのつくゲームエンジンを使う方が早いという疑惑が出てきます。
     
    #11
    metab, 神無月サスケ, たかッシュ他4人がいいね!しています
  12. たかッシュ

    たかッシュ ユーザー

    >リンクスさん
    ありがとうございます!
    そう言っていただけるとスレを立てて良かったです。
    皆さんから重さ対策や知見をいただける場になってありがたいです。

    >しぐれんさん
    ありがとうございます!

    イベントコマンドからの「スクリプト」が重くなる理由がよくわかりました。
    プラグインコマンドでの変数のリフレッシュ抑制技は使い所で導入できれば有効そうなので心得ておきたいです。
    関数の経由についてなど具体的に解説いただけて自分の知らなかった部分を詳しく噛み砕いて教えていただけてとてもありがたいです!

    経験値の増減が重い理由も経験値曲線の再計算があって処理の工程が増えてるからだったんですね。納得です。

    『敵を倒せばお金と経験値が取得できる』はゲームでは常識ですが
    お金を増やすことと経験値を増やすことの処理に内部で差があったことには気付けなかったです。

    原因がわかると対策が立つというか、もし今後レベル制のアクションゲームやARPGなどをツクるときは
    経験値システムの根幹を改修するか、それかデフォルトの経験値の増減を使わずに何か別の機構を自力で作って用意しておいた方が良さそうですね。
    経験値の増減の度にモッサリ動作になってしまうようではアクション系ゲームとしては致命的ですからね。
    そういう小さな問題点が積み重なっていくことが処理落ちへ繋がるのかもしれませんし。

    今回皆さんにいろいろ教えていただいて、良好動作を目指すためには幅広い知識が必要なのだとよくわかりました。
    何も考えもせずにいい加減に簡単に組んで実現させたものと軽い処理を考慮して実装されたものとでは処理の動作状況に差が出てしまいますよね。
    ツクったゲームが重いと心苦しいですし、軽いに越したことはないです。
    おかげさまで重さ対策について知見がついてきて制作に活かせそうです!


    こんなに長ったらしい前提のスレッドを読んでいただいて重さ軽さの処理について教えていただけて皆さんに心から感謝です!
    本当にありがとうございます!
    自分のゲーム作りに活かして良好快適動作を目指します!!

    皆さんのおかげでいいスレッドになってるので、ツクったゲームが重かったりして悩んでる方も気軽に書き込んでご相談くださいね。
     
    最後に編集: 2018-03-20
    #12
    神無月サスケネコタ がいいね!しています
  13. 神無月サスケ

    神無月サスケ ユーザー

    どうも、たかッシュさん、こん**は。
    軽量化についてですが、かつて僕が、「RPGツクールXPは重い」と言われていた時期に
    施した軽量化についてのメモがあります。
    こちらはツクールXPのRGSSを熟読して作成したものですが、
    驚くことに、今のツクールMVでも、同じような考え方での軽量化が可能なので、
    僭越ながら紹介させていただきます。

    http://d.hatena.ne.jp/ktakaki/20120101/p3

    この中で、イベントが増えた時に特に効果のあった方法:
    ・イベントの位置情報テーブルを作り、衝突判定の回数を減らす
    ・移動もアニメーションもしない「置物」タイルは、updateのうち、動作に関するものを全スキップ
    です。

    このように、Game_Event (Game_Character) と Sprite_Character には、
    軽量化の余地があります。
    しかし軽量化をスクリプトレベルで行ってしまうと、拡張性が損なわれてしまうため、
    コアスクリプトは、敢えて軽量化より拡張性を意識したスクリプトになっているというわけです。
    逆にいうと、コアスクリプトは、どんなゲームにするかによって、様々な軽量化の余地がある、
    ということです。

    RGSS3くらいまでは、このあたりを意識した軽量化プラグインを多く見かけました。
    MVでも、こういうのが既にあるかもしれませんね。

    以上、何かご参考になれば幸いです。
     
    最後に編集: 2018-03-21
    #13
    ビービー, salaspitg, たかッシュ他3人がいいね!しています
  14. たかッシュ

    たかッシュ ユーザー

    神無月サスケさん、こんにちは。
    軽量化の手法を詳しく教えていただき、ありがとうございます!
    すごく参考になります!

    記事も拝見しましたがこんなにも細部まで軽量化に取り組んでゲームを作ったなんて凄すぎます。
    ちゃんと解析やプログラムに基づいて軽量化を成し遂げたというのが偉大すぎます。
    軽量化の方法論がこんなにあったのだと知れて感激です。
    参考にさせていただきます!
    貴重な情報をありがとうございました!
     
    #14
    神無月サスケ がいいね!しました
  15. シトラス

    シトラス ユーザー

    自分は、シンボルエンカウントのゲームを作ったことがあるのですが
    エンカウントシンボルが20体くらいいたせいか重くて仕方ありませんでした。
    ただ、ここの話を聞いてもう少し工夫できるかと思いました。

    https://plicy.net/GamePlay/57143
    パスワード:symbolTest
    ユーザー名は適当なものを入力してください

    このゲームは、シンボルエンカウントによる負荷を調べるために作ってみたものです。
    上の部屋には戦闘後に「イベントの一時消去」で消滅するエンカウントシンボルが左から10,15,20体います。
    下の部屋には戦闘後にセルフスイッチを使い、透明になるエンカウントシンボルが20体います。
    この2パターンの部屋で、負荷の違いをスマホプレイから確かめたいと思います。
     
    #15
    たかッシュ, まるたん, ネコタ他1人 がいいね!しています
  16. シトラス

    シトラス ユーザー

    戦略シミュレーションゲームの作り方」に
    「スマホゲームに60fpsは重すぎる、アクション要素が少なければ30くらいで充分」と書いてありました。
    というわけで、どうにかしてfpsを下げられませんかね?

    重さ対策とはベクトルが違いますが、スマホでプレイしていると本体が熱くなるので
    それに備えてゲーム時間を細かく分けられる、すなわちどこでもセーブが可能だとか
    ダンジョンの攻略を短めにしたり脱出ポイントを置いておくなどの
    対策も有効なのではと思いました。
     
    #16
    神無月サスケたかッシュ がいいね!しています
  17. たかッシュ

    たかッシュ ユーザー

    シトラスさんこんにちは。お疲れ様です。
    シンボルエンカウント方式は数が多くなると重さが気になってくることもよくありますよね。

    イベントの一時消去と、セルフスイッチで何も見えない状態で置いておくのではどちらがいいかですが
    「イベントの一時消去」の方が消えてくれるので消した分だけ(倒す度に)処理上は軽くなってくれそうな気がします。

    それとスマホプレイは確かにすぐ熱くなったりするので、MV製でウェブ公開するときは気をつけたいですよね。
    スマホの熱持ちを考慮して小刻みに短時間プレイしやすい構成にするという視点も
    重さ対策の親戚みたいなものなのでそれも大事な視点だと思います。
    やはり現代のゲームのユーザー層は 「スマホから」 という層も増えているので、
    ツクる側はPC環境なのでPC前提な基準で見てしまいがちですが、
    プレイしてくれる人達はスマホ層も多かったりするので
    スペックや環境差も配慮したつくりがこれからは大事になってきそうですよね。
    重さだけでなくそういった視点にも配慮して、なるべく多くの人に楽しんでもらえるゲームをツクりたいですね。
     
    #17
    神無月サスケシトラス がいいね!しています
  18. 神無月サスケ

    神無月サスケ ユーザー

    どうも、シトラスさん、こん**は。
    「フレームレートを半分にしても大体動作するようにする」
    これ、実は僕が前述のゲームでもやったことであります。

    具体的にはシステムのフレームレートを半分30fpsにした後、「wait()」の中の数値(待ちフレーム数)を
    全て半分にする、というやり方です。
    これは場合によってはシステム全体に変更が及ぶため、かなり苦労しましたが、
    その他の条件も考慮してうまく作ることができました。

    これはツクールXPの話ですが、MVでも同じやり方が出来ないかな……と思っています。
     
    #18
    シトラス がいいね!しました
  19. munokura

    munokura ユーザー

    以前から疑問に思っていたのですが、好奇心に負けてしまい質問いたします。
    あまりに効果が小さすぎて話題にならないのだろうと予想はしています。


    1.変数とスイッチの違い

    1-1.変数に出来なくて、スイッチに出来ることはありますか?
    1-2.変数とスイッチの処理の負荷に差はありますか?
    1-3.スイッチとセルフスイッチの負荷の差はありますか?


    2.条件分岐とラベルジャンプ
    例:乱数1から10を設定
    乱数に対して10通りの処理の分岐を作るとします。
    この場合、下記の処理(以外の処理は思いつかないだけです)では負荷はどの順で軽いですか?

    2-1.条件分岐で「条件を満たさない時の分岐を作成」にそれぞれの条件分岐を内包する。
    2-2.条件分岐で条件を満たした時に、以下の条件分岐を終了した時点のラベルへジャンプさせる。
    2-3.「条件を満たさない時の分岐を作成」もラベルジャンプもなく、すべての条件分岐を直列に並べる。


    3.ループ処理と同じコマンドを並べた時の差
    これは3-2の方が軽いと予想しますが、条件によっては変数で繰り返し処理の回数を変える場合は3-1を取らざるを得ないケースもあるのかな?
    上級者は、そんなことはスクリプトでクリアしてしまうのかも知れませんが。

    3-1.ループ処理で1回変数に+1してカウントし、条件分岐で一定の回数に達した場合にループの中断。
    3-2.同じコマンドをただ回数分並べる。


    プログラミング言語の初歩的な知識かもしれませんが、専門ではないので素朴に疑問に思ったら、気になって仕方がなくなってしまいました。
    もちろん、どれでやろうと現状の環境で差が出るほどの処理はしていないので、完全に興味本位です。
    差というほどのものでないでしょうから、可読性・メンテナンス性を優先すべきだろうとは思っています。
     
    最後に編集: 2019-01-30
    #19
    神無月サスケ がいいね!しました
  20. くろうど

    くろうど ユーザー

    ひとまず、『1-1.変数に出来なくて、スイッチに出来ることはありますか?』について回答させていただきますと、『あります』です。

    思い付いた所で、敵キャラの行動条件、バトルイベントの発生条件、コモンイベントで並列処理などの制御に使う、辺りでしょうか。
    つまり、エディタ上でスイッチしか枠がない部分です。
     
    #20
    神無月サスケmunokura がいいね!しています

このページを共有