ウィンドウのサイズ変更/移動中にXNAが更新を一時停止しないようにするにはどうすればよいですか?


15

XNAは呼び出しUpdateを停止Drawし、ゲームウィンドウがサイズ変更または移動されている間。

どうして?この振る舞いを防ぐ方法はありますか?

(ネットワークメッセージがポンプされていないため、ネットワークコードの同期が取れなくなります。)

回答:


20

はい。XNAの内部を少しいじります。修正のデモンストレーションがありますこのビデオの後半で

バックグラウンド:

これが発生する理由は、XNA Gameの基盤のFormサイズが変更された(または移動され、イベントが同じである)ときにXNAがゲームのクロックを一時停止するためです。これは、ゲームループをから駆動しているためApplication.Idleです。ウィンドウのサイズが変更されると、Windowsは発火を防止するいくつかのクレイジーなwin32メッセージループ処理Idleを実行します。

そのため、Gameクロックを一時停止しなかった場合、サイズ変更後に膨大な時間が蓄積され、1回のバーストで更新する必要があります-明らかに望ましくありません。

修正方法:

XNAでのイベントの長鎖(あなたが使用している場合がありGame、基本的には基礎となるのresizeイベント接続し、これは、カスタムウィンドウには適用されません)Form、へSuspendResumeゲームクロックのための方法は。

これらはプライベートなので、リフレクション使用してイベントをアンフックする必要があります(thisGame)。

this.host.Suspend = null;
this.host.Resume = null;

必要な呪文は次のとおりです。

object host = typeof(Game).GetField("host", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
host.GetType().BaseType.GetField("Suspend", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(host, null);
host.GetType().BaseType.GetField("Resume", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(host, null);

(チェーンを別の場所で切断することもできます。ILSpyを使用して把握できます。ただし、タイマーを一時停止するウィンドウのサイズ変更以外には何もありません。したがって、これらのイベントはどれほど優れています。)

次に、XNAがからティックしていないときのために、独自のティックソースを提供する必要がありますApplication.Idle。私は単に使用しましたSystem.Windows.Forms.Timer

timer = new Timer();
timer.Interval = (int)(this.TargetElapsedTime.TotalMilliseconds);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();

今、timer_Tick最終的にを呼び出しますGame.Tick。クロックが一時停止されていないため、XNA独自のタイミングコードをそのまま使用できます。簡単!完全ではありません:XNAのビルトインティックが発生しない場合にのみ、マニュアルティックが発生するようにします。これを行う簡単なコードを次に示します。

bool manualTick;
int manualTickCount = 0;
void timer_Tick(object sender, EventArgs e)
{
    if(manualTickCount > 2)
    {
        manualTick = true;
        this.Tick();
        manualTick = false;
    }

    manualTickCount++;
}

そして、UpdateXNAが正常にカチカチ音をたてたら、このコードを入れてカウンターをリセットします。

if(!manualTick)
    manualTickCount = 0;

このカチカチ音は、XNAのそれよりかなり正確ではないことに注意してください。ただし、それはほぼリアルタイムで並んでいる必要があります。


このコードにはまだ1つの小さな欠陥があります。馬鹿げたWinい顔を祝福するWin32 は、ウィンドウのタイトルバーをクリックすると、マウスが実際に移動する前に、本質的にすべてのメッセージを数百ミリ秒間停止ます(同じリンクをもう一度参照)。これにより、Timer(メッセージベースの)ティックが発生しなくなります。

XNAのゲームクロックを一時停止しないため、タイマーが最終的に再びカチカチ音を立て始めると、更新のバーストが発生します。そして、残念なことに、XNAは累積可能な時間を、タイトルバーをクリックしたときにWindowsがメッセージを停止する時間よりもわずかに短い時間に制限します。そのため、ユーザーがたまたまタイトルバーを移動せずにクリックしたままにすると、更新のバーストが発生し短いリアルタイムの数フレームを落ちます。

(ただし、ほとんどの場合、これでも十分なはずです。XNAのタイマーは、sacrifice音を防ぐために精度を既に犠牲にしているため、完璧なタイミングが必要場合は、他のことを行う必要があります。)


2
いい包括的答え。
マイケルハウス

1
なぜ正確に質問をして、すぐに答えたのですか?
アラステアピッツ

4
公正な質問。それはだ、明示的に奨励します。質問UIには、「独自の質問に答える」ボックスもあります。もともと私はそれをこの質問に対する答えにするつもりでしたが、それは古い答えの編集に過ぎず、私の解決策はその質問の一部を解決しません。これにより、可視性が向上します(新規であり、SOではなくGDSEのXNAである)。そして、この情報は私のブログよりもここでの方が適しています。
アンドリューラッセル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.