Graphics.frame_resetを多用しても問題ない?

アバター
seea
記事: 84
登録日時: 2016年6月04日(土) 21:48
連絡を取る:

Graphics.frame_resetを多用しても問題ない?

投稿記事by seea » 2017年6月03日(土) 01:17

今、VXAceのマップ画面のフレームスキップ(「カクつき」現象)を減らすための
効果的な方法を探しています。
安定した描画はゲームの基礎となるもので、安定していないとゲームの中身が良かろうが悪かろうが
全く見てもらえなくなります。特に2Dでスクロールのカクつきは厳しいです。
「カクつき」現象に限っては、絶対に解決しなくてはなりません。

Graphics.frame_resetについて詳しい方、
または詳しい解説サイトをご存じの方いらっしゃいませんか。

ヘルプは勿論、解説サイトも私なりに調べてはみましたが、ヘルプ以上のことを語っているサイトは
無さそうです。


前提として、ウィンドウモードでのプレイです。全画面は使用しません。

VXAceのマップ画面ではPCのスペックが足りていても
標準ではフレームスキップが多く発生することがあります。
素材RGSS3を一切組み込んでいない初期プロジェクトのサンプルマップでも
キャラクターを歩かせていると発生するので、簡単に確認することができます。


現在、次の方法でフレームスキップの発生を相当程度抑え、目立たなくする
ことができることが分かっています。検証期間が短いため安定性は不明です。

・ゲームモードON(Creators Update以降は、設定しないとむしろCPUを割り当ててくれない)
・標準の 60 FPS を 80 FPS に変更 (70 FPSは効果なし。75 FPSは効果あり。80 FPSは暫定値)
・「画面描画のちらつきを抑える」にチェックON
  チェック無しでは(80 FPSで描画されてしまうため)余計悪化。カクつきの見本市状態。
・適切なタイミングで、フレーム毎に Graphics.frame_reset を使用する。
 どのタイミングがベストかは調査中

フレームスキップ(「カクつき」現象)が完全に無くなるわけではなく、発生回数が減り
発生しても目立ちにくくなるといった改善効果です。

こんな方法でなぜ改善するのか理由はよくわかりませんが
どうもVXAce本体側の「60 FPSを保つための仕組み」には、些細なバグが残っている
としか考えられません。些細なものなのでフレームスキップは稀にしか発生しません。
しかし、マップのスクロール中のフレームスキップは1回でも目立つため非常に気になります。
この点は、本体側の描画のロジックが優れているウディタが羨ましくなりますね。

VXAce本体側の修正はもう無いですよね……。ということは、RGSS3側で何とかするしかありません。

また上記の方法には欠点もありまして、FPSの測定が全くできなくなります。
タイトルバーには常時 "61 FPS" と表示されます(本当に 61 FPSとなっているわけではない)
プレイする上での不都合はありませんが、制作中は面倒かもしれません。

これは質問でもあるのですが、
Graphics.frame_resetを使いまくりますので(毎秒80回)、
何か見落としている重大な欠点や、副作用がないかどうか知りたいです。

効果が無かったり、逆効果になるケースもあると思いますので、
そのあたりはテストプレイなどで調べて判断すればいいかなと考えています。

複雑で、答えにくい質問ですみません。
基本、私が時間をかけて調べて、結果を報告すればいいことだとは思っています。
安定して動くなら、素材化してもいいでしょう。
ただ、それには時間がかかりますし、限界もあります。間違った方向に進むこともあります。
詳しい方に教えていただけたら、とても嬉しいです。

SBR

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by SBR » 2017年6月03日(土) 07:33

カクつきはバグというよりもRubyの仕様のように思えます。
例えば

$foo = Array.new(100000000)

のようなコードを紛れ込ませると。ガクガクになってしまいますが

$foo = Array.new(100000000)
GC.disable

のようにガベージコレクションを無効にするとカクつきはかなり抑えられます。(定期的に有効にしないと落ちますが…)実際どうなっているか知りませんがGCが配列やハッシュの中身を定期的にチェックしているようです。(例え中身がnilやfalseだけでも)

個人的な改善案は配列やハッシュを使い終わった後に即clearしてしまう事です。
アバター
seea
記事: 84
登録日時: 2016年6月04日(土) 21:48
連絡を取る:

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by seea » 2017年6月03日(土) 20:12

ありがとうございます。
GC.disableを付けて検証しましたが、カクつきは発生してしまうようです。
私が見ているカクつきは、GCが引き起こすカクつきとは別のものなのかもしれません。
SBR

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by SBR » 2017年6月04日(日) 02:24

そうですか…

フレームレートの調整やフレームスキップを自分で実装しなければなりませんがWin32APIのInvalidateRgn関数とUpdateWindow関数を使用してみてはいかがでしょうか?この2つの関数を使用すれば強制的にゲーム画面の更新が可能です。
アバター
seea
記事: 84
登録日時: 2016年6月04日(土) 21:48
連絡を取る:

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by seea » 2017年6月04日(日) 10:47

Win32APIを使うとなると、その関数になるのですね。ありがとうございます。
アプリの画面更新を完全に自力で制御してしまう場合はそのようにいたします。
これは最終手段でしょうか……。
(既に多くのAPIを併用していて今更ですが……)

RGSS3の仕組みに頼る場合は、
Scene_Baseのupdate_basicにあるGraphics.updateが
マップ画面描画のタイミングを決めているようなので
このタイミングを、正確なタイマをもとに制御できれば、カクつきを減らせるかもしれません。

現状でも、80 FPSに変更して、Graphics.frame_resetを適切なタイミングでフレーム毎に呼ぶことで
カクつきを目立たないように出来ていますので、このまま安定するようであれば
Graphics.frame_resetに頼ろうかなと考えています。

マップ画面だけ 80 FPSにして、他は60 FPSに戻す方針で考えていますが、それが無理なら
各種タイミングを80 FPSに合せて作り直せば良いことなので、これは時間をかければ可能な範囲かと思います。
FPSの測定が出来ない件は、VXAce本体側に頼らずに自力で測定して解決できそうです。

また、Graphics.frame_resetの多用に関して、もうひとつ欠点(?)が見つかりました。
F12キーによるリセットを行うと、Windows10が(リセット前と比べて)CPUを割り当ててくれなくなり、
以降の描画が極端に遅くなってしまうことです。原因はよくわかっていません。
F12キーによるリセットの問題点はスクリプトにより解決されていたのですが、
より目に見える形で問題点が発覚しました。
リセットはそれはどうやら完全ではなく、F12リセット前とリセット後でアプリは異なる挙動をするようです。
それはリセットとは呼べません。
この際ですので、F12キーのリセット機能は封印するほうが良さそうな気もします。
SBR

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by SBR » 2017年6月04日(日) 12:38

RGSS3はリセット時に

・Audio.__reset__
・Graphics.__reset__

の2つのメソッドを呼び出します(自作したデバッガで呼び出されていることを確認しています)この2つを再定義すれば問題を解決できませんかね?

Graphics.__reset__と同等の解放処理を行いたいのであれば

[Window,Plane,Viewport,Sprite,Bitmap].each do |klass|
ObjectSpace.each_object(klass){|obj|obj.dispose rescue nil}
end

みたいな感じですかね?

僕がツクマテにアップした自動戦闘強化AIのプロジェクト内に__reset__の呼び出しの阻止とF12対策が可能なスクリプトを入れてありますので参考にしてみるといいかもしれません。
アバター
seea
記事: 84
登録日時: 2016年6月04日(土) 21:48
連絡を取る:

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by seea » 2017年6月04日(日) 18:55

ありがとうございます。
リセットを生かす場合の参考にさせていただきます。

すみません、今回はよくわからないものにフタを……F12を無効化してしまいました。
F12キーを押しても、連打しても何も起こらないようになりました。
PCゲームのプレイヤーから見れば、右上の「×」を押せばいいことですし
まさかF12がリセットボタンとは思わないでしょうから。

そしてGraphics.frame_resetの謎は残ります。
アプリが落ちたりはしないようですが……。
アバター
seea
記事: 84
登録日時: 2016年6月04日(土) 21:48
連絡を取る:

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by seea » 2017年6月05日(月) 01:15

一応、スクリプトを置いておきますね。
副作用が見つかるといいなぁ。
(このまま安定して動いてくれたら嬉しいですけど)

カクつき自体はある程度は残ってしまいますが、
カクつきによる画面の停止を短くする効果があるため、目立たないようになります。

注意点
※「FPS_Hud」は正常な値を表示しません。
※見落とした副作用があるかもしれないので(多分何かはある)、
 何か変な動きをしたら教えてもらえると助かります。

コード: 全て選択

# Precise Anti-Lag by seea  (2017/06/04)
#
# License : Public domain
#
# 他のスクリプトよりも後に定義されるように設置します。
#
# ゲームのプロパティの
# 「画面描画のちらつきを抑える」チェックあり が前提です。
#
# F12キーによるリセットは正常に動作しないことがあります。

class Spriteset_Map
  #--------------------------------------------------------------------------
  # ● フレーム更新                                                  EXPANDED
  #
  # 2017/06/04 Created
  #--------------------------------------------------------------------------
  alias precise_anti_lag_update update
  def update
    precise_anti_lag_update
    # ▼ 2017/06/04 ADD by seea
    Graphics.frame_reset
    # ▲ 2017/06/04 ADD by seea
  end
end

class Scene_Map < Scene_Base
  #--------------------------------------------------------------------------
  # ● 開始処理                                                      EXPANDED
  #
  # マップ画面ではFPSを80に引き上げる
  #
  # 2017/06/04 Created
  #--------------------------------------------------------------------------
  alias precise_anti_lag_start start
  def start
    precise_anti_lag_start
    Graphics.frame_rate = 80
  end

  #--------------------------------------------------------------------------
  # ● 終了前処理                                                    EXPANDED
  #
  # FPSを既定値の60に戻す
  #
  # 2017/06/04 Created
  #--------------------------------------------------------------------------
  alias precise_anti_lag_pre_terminate pre_terminate
  def pre_terminate
    Graphics.frame_rate = 60
    precise_anti_lag_pre_terminate
  end
end
SBR

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by SBR » 2017年6月05日(月) 07:20

先ほどのスクリプトですが試してみたところWindows7ではガクガクになってしまいました。FPS(FPS_Hudを改造したものです)は常に60になります。
無題.jpg
無題.jpg (88.93 KiB) 閲覧数: 6487 回

色々調べてみたのですが今回の問題はDWM(デスクトップウィンドウマネージャー)が原因のような気がします。
Windows7でDwmEnableComposition関数を使用してDWMを無効化した結果、ティアリングが発生するもののカクつきは劇的に改善されました。ただ、Windows8~10はDWMを無効化できないので無意味です。
アバター
seea
記事: 84
登録日時: 2016年6月04日(土) 21:48
連絡を取る:

Re: Graphics.frame_resetを多用しても問題ない?

投稿記事by seea » 2017年6月06日(火) 22:39

ありがとうございます。
Windows7の環境を用意して、実験してみます。
やっぱりWindows7のテスト環境も、残しておいたほうが良いのかな。

OSを見分けて、別々の対策をとることになりそう。
OS判別して、なおかつゲーマーが選択した場合に限り、このカクつき対策を有効にするといった感じでしょうか。

“VX / Ace:質問” へ戻る