XNAは呼び出しUpdate
を停止Draw
し、ゲームウィンドウがサイズ変更または移動されている間。
どうして?この振る舞いを防ぐ方法はありますか?
(ネットワークメッセージがポンプされていないため、ネットワークコードの同期が取れなくなります。)
XNAは呼び出しUpdate
を停止Draw
し、ゲームウィンドウがサイズ変更または移動されている間。
どうして?この振る舞いを防ぐ方法はありますか?
(ネットワークメッセージがポンプされていないため、ネットワークコードの同期が取れなくなります。)
回答:
はい。XNAの内部を少しいじります。修正のデモンストレーションがありますこのビデオの後半で。
バックグラウンド:
これが発生する理由は、XNA Game
の基盤のForm
サイズが変更された(または移動され、イベントが同じである)ときにXNAがゲームのクロックを一時停止するためです。これは、ゲームループをから駆動しているためApplication.Idle
です。ウィンドウのサイズが変更されると、Windowsは発火を防止するいくつかのクレイジーなwin32メッセージループ処理Idle
を実行します。
そのため、Game
クロックを一時停止しなかった場合、サイズ変更後に膨大な時間が蓄積され、1回のバーストで更新する必要があります-明らかに望ましくありません。
修正方法:
XNAでのイベントの長鎖(あなたが使用している場合がありGame
、基本的には基礎となるのresizeイベント接続し、これは、カスタムウィンドウには適用されません)Form
、へSuspend
とResume
ゲームクロックのための方法は。
これらはプライベートなので、リフレクションを使用してイベントをアンフックする必要があります(this
はGame
)。
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++;
}
そして、Update
XNAが正常にカチカチ音をたてたら、このコードを入れてカウンターをリセットします。
if(!manualTick)
manualTickCount = 0;
このカチカチ音は、XNAのそれよりかなり正確ではないことに注意してください。ただし、それはほぼリアルタイムで並んでいる必要があります。
このコードにはまだ1つの小さな欠陥があります。馬鹿げたWinい顔を祝福するWin32 は、ウィンドウのタイトルバーをクリックすると、マウスが実際に移動する前に、本質的にすべてのメッセージを数百ミリ秒間停止します(同じリンクをもう一度参照)。これにより、Timer
(メッセージベースの)ティックが発生しなくなります。
XNAのゲームクロックを一時停止しないため、タイマーが最終的に再びカチカチ音を立て始めると、更新のバーストが発生します。そして、残念なことに、XNAは累積可能な時間を、タイトルバーをクリックしたときにWindowsがメッセージを停止する時間よりもわずかに短い時間に制限します。そのため、ユーザーがたまたまタイトルバーを移動せずにクリックしたままにすると、更新のバーストが発生し、短いリアルタイムの数フレームを落ちます。
(ただし、ほとんどの場合、これでも十分なはずです。XNAのタイマーは、sacrifice音を防ぐために精度を既に犠牲にしているため、完璧なタイミングが必要な場合は、他のことを行う必要があります。)