XNA 3.1 ~ 4.0 では、定期的に再描画が必要になるか、紫色の画面が表示されます。
質問
ゲームのメニューについては、一度画面に描画し、ダーティと判断された場合にのみ再描画します。これは、ユーザーが再描画を引き起こすアクションを実行するたびに true に設定されたブール値によって処理され、描画ループはメニューを描画する前にその値をチェックします。このロジックは 3.1 では完全に機能しましたが、4.0 ではメニューがちらつき (1 フレーム間描画)、その後再度描画されるまで紫色の画面が表示されます。
以下に示す問題を実証するために、4.0 で非常に単純なテスト ゲームを作成しました。画面が紫色に見えるだけであることがわかります。_isDirty を false に設定している行を削除すると、コーンフラワー ブルーの背景が表示されます。
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
bool _isDirty = true;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
}
protected override void Draw(GameTime gameTime)
{
if (_isDirty)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
_isDirty = false;
}
base.Draw(gameTime);
}
}
XNA 3.1 からの動作を取得するにはどうすればよいですか?PreserveContents について何人かの人が言及しているのを見かけましたが、間違って適用しない限り、4.0 では何の効果もないようです。
解決
XNA ゲームで呼び出されるものの概略を次に示します。
Update
BeginDraw
Draw
EndDraw
デフォルトの実装は、 EndDraw
最終的に電話をかける GraphicsDevice.Present
. 。ダブルバッファリングをオンにすると、バックバッファとフロントバッファが入れ替わります。
つまり、何が起こっているのかというと、次のとおりです。
初めて:シーンをバック バッファーに描画してから、XNA にそれをフロント バッファーに交換させます。
2 回目:何も描画せず、サーフェスを DirectX がこれらのサーフェスを初期化する紫色で塗りつぶしたままにし、交換します。 それ フロントへ!
以降の回:何も描画していないので、これら 2 つのサーフェスの間でディスプレイがちらつくのがわかります。
XNA での描画を抑制するには、いくつかの方法があります。私はそれらを調べます 同様の質問に対するこの回答. 。その回答と同様に、次のように BeginDraw をオーバーライドすることをお勧めします。
protected override bool BeginDraw()
{
if(_isDirty)
return base.BeginDraw();
else
return false;
}
いつ BeginDraw
falseを返します、 Draw
そして EndDraw
(など Present
) はそのフレームとは呼ばれません。何も描画されず、前後のバッファーも交換されません。
他のヒント
私は最近、あまりにもこのにつまずきました。私はそれがバッファをひっくり返すに問題はないと思います。これは、3.1と4.0で同じでなければなりません。私はILSpyでのGraphicsDeviceを見て、これを見つけます:
何が変わったのは4.0で、現在のプライベートフラグが設定されている場合は、最初の()GraphicsDevice.Presentにクリアされるレンダーターゲットということです。デフォルトでは、このフラグは、(ターゲットがクリーンであるレンダリング)最初に設定されます。 (今汚いレンダーターゲット)ターゲットは、このフラグをクリアし、レンダリングに描きます。それの義務を実行した後、GraphicsDevice.Presentは()を再度(だったあなたの窓に「フラッシュアウト」と、今再びきれいに考えられているレンダーターゲット)フラグを設定します。
GraphicsDevice.Present()からの結果を取得するには、厳格な順序で(描画)とEndDraw()を呼び出す必要があります。
あなたは)(描画する前にコールなしEndDraw()を呼び出すと、は、あなたが(クリアされます)レンダーターゲットの内容を取得することはできません、だけで紫色の画面の代わります。
残念ながら、フラグがプライベートであり、それを得るために何のきれいな方法はありません。あなたはそれに何も描画せずにレンダーターゲットの汚れを強制的に、このようにフラグをクリアするためにリフレクションを使用することができます:
graphicsDevice.GetType()GetFieldの( "lazyClearFlags"、BindingFlags.NonPublic | BindingFlags.Instance).SetValue(GraphicsDeviceに、0);ます。
(GraphicsDeviceには、あなたの現在のGraphicsDeviceインスタンスである)
それが3.1にあったものにEndDraw()へお電話の前に上記の行、および行動戻しますを置きます。
私の特定のケースでは、私は、描画を担当している状態間で切り替わるステートマシンを持っています。だから私は2つのゲーム状態間の遷移時に、そこに描画するものは何もありませんし、次のゲームの状態がアクティブになるまで画面が紫色に点滅します。
私は状態がない場合は、私はそれを解決するためにやったことは、単純に、アップデートで、ゲームオブジェクト内の SuppressDraw()のメソッドを呼び出しました。次の更新が行われるまで起こってから描くこれを防止。
私はあなたがisDirtyフラグを設定する場合を除いて、常に、アップデートでそれを呼び出してからあなたを止めるものは何も存在しないこととします。しかし、あなたは画面がゴミ箱に移動する恐れがあります他のイベント/ケースを扱うために準備しなければならないであろう。