XNA 3,1-4,0 richiede una costante ridisegnare o visualizzerà una schermata viola

StackOverflow https://stackoverflow.com/questions/4235439

  •  26-09-2019
  •  | 
  •  

Domanda

Per i menu nel mio gioco, io li disegnare una volta per lo schermo, quindi ridisegnare solo se sono stati ritenuti sporchi. Questo è gestito attraverso un insieme booleano true quando l'utente esegue un'azione che dovrebbe causare un ridisegno, e quindi il ciclo sorteggio verifica che il valore prima di prelevare il menu. Questa logica ha funzionato perfettamente in 3.1, ma in 4,0 menu lampeggerà (disegnato per 1 fotogramma) poi mostrare uno schermo viola fino disegnato di nuovo.

ho creato un gioco molto semplice prova in 4,0 per dimostrare il problema indicato di seguito. Si noterà che lo schermo sembra proprio viola. Se si rimuove l'impostazione _isDirty false linea, si vedrà lo sfondo blu fiordaliso.

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);
    }
}

Come potrei fare per ottenere il comportamento da XNA 3.1? Ho visto diverse persone parlare PreserveContents, ma che non sembra avere alcun effetto in 4,0 se non sto applicando in modo errato.

È stato utile?

Soluzione

Ecco una panoramica approssimativa di ciò che viene chiamato in un gioco di XNA:

Update
BeginDraw
Draw
EndDraw

L'implementazione predefinita di EndDraw infine chiama GraphicsDevice.Present. Con il doppio-buffering acceso, questo swap parte posteriore e anteriore buffer.

Quindi, ciò che sta accadendo è il seguente:

  • La prima volta:. Si sta disegnando la scena al buffer posteriore e poi lasciare XNA di swap in primo piano

  • Seconda volta: si sta disegnando nulla, lasciando la superficie riempito con il colore viola che DirectX inizializza queste superfici a, e lo scambio di che per la parte anteriore

  • tempi successivi:. Si sta disegnando nulla, così vedrete il guizzo display tra queste due superfici

Ci sono diversi modi per sopprimere disegno in XNA. Vado su di loro in questa risposta a una domanda simile . Come in quella risposta, vi consiglio di ignorare BeginDraw, in questo modo:

protected override bool BeginDraw()
{
    if(_isDirty)
        return base.BeginDraw();
    else
        return false;
}

Quando BeginDraw restituisce false, Draw e EndDraw (e così Present) non sarà chiamato quel fotogramma. Niente potrà disegnare e il buffer anteriore / posteriore non sarà di swap.

Altri suggerimenti

Recentemente ho inciampato in questo troppo; Non credo che sia un problema con flipping buffer. Questo dovrebbe essere lo stesso in 3.1 e 4.0. Ho guardato con GraphicsDevice ILSpy e scoperto questo:

Ciò che è cambiato è che in 4.0, la corrente di rendering di destinazione viene prima eliminato in GraphicsDevice.Present () se è impostato un flag privato. Per impostazione predefinita, questo flag sarà impostato inizialmente (rendering obiettivo è pulita). Disegno nella destinazione di rendering cancella questo flag (rendering obiettivo ora sporco). Dopo l'esecuzione di esso il proprio dovere, GraphicsDevice.Present () imposta di nuovo la bandiera (rendering obiettivo era "svuotato" alla finestra ed è ora di nuovo considerato pulito).

Per ottenere risultati di GraphicsDevice.Present (), è necessario chiamare Draw () e EndDraw () in stretta sequenza.

Se si chiama EndDraw () senza indizione disegnare (), non sarà possibile ottenere il contenuto del target di rendering (che viene eliminato), solo lo schermo viola, invece.

Purtroppo, la bandiera è privato e non c'è modo pulito per ottenere esso. È possibile utilizzare la reflection per cancellare il flag in questo modo, costringendo il bersaglio sporco render senza disegnare qualsiasi cosa in esso:

graphicsDevice.GetType () getField ( "lazyClearFlags", BindingFlags.NonPublic | BindingFlags.Instance) .SetValue (GraphicsDevice, 0);.

(GraphicsDevice è l'istanza GraphicsDevice corrente)

Posizionare la linea di cui sopra prima della chiamata a EndDraw (), ed i ripristini di comportamento a quello che era in 3.1

Nel mio caso particolare, ho una macchina a stati che commuta tra gli stati che sono responsabili per il disegno. Così, quando ho transizione tra due stati di gioco, non c'è nulla da disegnare, e lo schermo lampeggia viola fino al prossimo stato di gioco è attivo.

Quello che ho fatto per risolvere era semplicemente, in aggiornamento, se non ho stato, chiamare il SuppressDraw () il metodo nell'oggetto gioco. Questo impedisce di disegno di prendere posto fino al prossimo aggiornamento avviene.

Suppongo che non c'è nulla ti impedisce di chiamare sempre in aggiornamento, tranne quando si imposta una bandiera IsDirty. Ma si dovrebbe essere pronti a gestire altri eventi / casi in cui lo schermo potrebbe avere cestinati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top