0

私は XNA 3.1 を使用して xna game studion 向けに開発を行っていますが、一部のゲームで、処理するためのリソースがシステムに十分にあるにも関わらずゲームが遅くなる問題に気付きました。ゲームのウィンドウがフォーカスされると、プロセス #1 (タスク マネージャー内) の使用率が 100% になり、ゲームにマイナー ラグの兆候が見られます (サウンド エフェクトが順番に繰り返される場合に特に顕著です)。ゲームがウィンドウのフォーカスを失うと、リアルタイムで描画と更新を続けますが、プロセスの使用量が減り、ラグがなくなります。

これをさまざまなゲームでテストしましたが、結果は変わらず、コードやコードの効率とは関係がないことが証明されました。

これは Xna 3.1 に限定された問題ですか? また、修正はありますか? それとも、4.0 に切り替えて、下位互換性のないものをゲームで使用しないようにする必要がありますか?

4

3 に答える 3

0

私の経験では、XNA は、焦点が合っているときは 1 秒あたり最大 60 フレーム、焦点が合っていないときは 1 秒あたり約 20 フレームで実行されます。ただし、IsFixedTimeStep = false;プロセスがフォーカスされているときにゲームが可能な限り速く実行されるように設定している場合. 私のゲームでは、私のマシンでは、約 500 ~ 700 fps で実行されます。これは、発生する呼び出しの数にも関係しています。Update()そのため、私のゲームも毎秒 500 ~ 700 回更新されています。

私の賭けは、固定タイムステップを無効にしており、膨大な数の Update および Draw 呼び出しがコアの 100% を消費しており、音楽を台無しにしているということです。IsFixedTimeStep = false;行がある場合は削除することをお勧めします。その行がコードに存在しない場合、これは問題ではありませんが、Update または Draw が必要以上の作業を行っていることは間違いありません。

自分のゲームでこれに気づきました。更新ループに Console.WriteLine ステートメント (デバッグ用) があるため、多くの遅延が発生します。

于 2011-09-02T20:04:14.427 に答える
0

この問題は、ガベージ コレクターが原因で発生する可能性があります。ガベージ コレクターが実行されるたびに、フレーム レートが 1 ~ 2 秒間低下することがありますが、Windows では問題になりません。

この行をコードに追加して、生成されるヒープ メモリの量を確認します。値が下がるたびに、ガベージ コレクターが実行されます。

 SpriteBatch.DrawInt64(FONT, GC.GetTotalMemory(false) / 1000 /* in kilobytes */, new Vector2(5, 30), Color.White, 0f);

SpriteBatch.DrawInt64 は、int や long などでガベージを生成しない SpriteBatch 拡張機能です。代わりに、SpriteBatch.DrawString(..., (GC.GetTotalMemory(false) / 1000).ToString(), ... ) を使用することもできます。

SpriteBatchExtensions.cs : http://pastebin.com/z9aB7zFH

于 2011-09-02T22:09:51.183 に答える
0

XNA は、ウィンドウがフォーカスされていないときにスリープを追加します! Game クラスをオーバーライドし、Game クラスがそのフォームがアクティブかどうかを理解する方法を変更する前に、この問題を解決しました。

私の知る限り、Game クラスの動作をコードで変更せずにこの動作を無効にする方法はありません。

特に、私が少し前に見つけた方法は、本当のハック\クワックです! 非常に汚れた解決策ですが、私が見つけた唯一の方法です。

public class MyGame
{
    private MethodInfo pActivate;

    public MyGame()
    {
        // We need to access base HostActivate method, that unfortunally, is private!
        // We need to use reflection then, of course this method is an hack and not a real solution!
        // Ask Microsoft for a better implementation of their class!

        this.pActivate = typeof(Game).GetMethod("HostActivated", BindingFlags.NonPublic | BindingFlags.Instance);
    }

    protected sealed override void OnDeactivated(object sender, EventArgs args)
    {
        base.OnDeactivated(sender, args);

        // Ok, the game form was deactivated, we need to make it believe the form was activated just after deactivation.

        if (!base.Active)
        {
            // Force activation by calling base.HostActivate private methods.
            this.pActivate.Invoke(this, new object[] { sender, args });
        }
    }
}
于 2011-09-02T20:08:40.430 に答える