XNA 3.1 a 4.0 requiere redibujado constante o se mostrará una pantalla de color púrpura

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

  •  26-09-2019
  •  | 
  •  

Pregunta

Para los menús en mi juego, que dibujen una vez a la pantalla, a continuación, volver a dibujar solamente si han sido consideradas sucias. Esto se maneja a través de un conjunto booleano true cuando el usuario realiza una acción que debe causar un redibujado, y luego el bucle de tracción comprobará que el valor antes de sacar el menú. Esta lógica funcionó a la perfección en 3.1, 4.0, sino en el menú parpadeará (dibujado por 1 marco) a continuación, mostrar una pantalla de color púrpura hasta el dibujado de nuevo.

He creado un juego muy simple de prueba en 4.0 para demostrar el problema se muestra a continuación. Usted notará que la pantalla sólo se ve de color púrpura. Si se quita la línea de establecer _isDirty en false, verá el fondo azul aciano.

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

¿Cómo hago para conseguir el comportamiento de XNA 3.1? He visto a varias personas mencionan PreserveContents, pero eso no parece tener ningún efecto en 4.0 a menos que esté aplicando de forma incorrecta.

¿Fue útil?

Solución

Aquí es una visión general de lo que se llama en un juego de XNA:

Update
BeginDraw
Draw
EndDraw

La implementación predeterminada de EndDraw llama en última instancia GraphicsDevice.Present. Con doble búfer activada, esta permutas el trasero y delantero buffers.

Así que lo que está sucediendo es:

  • Primera vez:. Va a dibujar la escena en la memoria intermedia hacia atrás y luego dejar XNA de intercambio a la parte delantera

  • Segunda vez: va a dibujar nada, dejando la superficie llena de color púrpura que DirectX inicializa a estas superficies, y el trueque de que en la parte delantera

  • tiempos posteriores:. Va a dibujar nada, por lo que verá el parpadeo de la pantalla entre estas dos superficies

Hay varias formas de dibujo reprimir en XNA. Voy sobre ellos en esta respuesta a una pregunta similar . Al igual que en esa respuesta, recomiendo que los redefina BeginDraw, así:

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

Cuando BeginDraw devuelve falso, Draw y EndDraw (y así Present) no será llamado ese marco. Nada va a dibujar y los amortiguadores delanteros / traseros voluntad no intercambio.

Otros consejos

Hace poco tropezó con esto también; No creo que sea un problema con voltear tampones. Esa debe ser la misma en 3.1 y 4.0. Miré a GraphicsDevice con ILSpy y descubrí esto:

Lo que ha cambiado es que en 4.0, el actual destino de representación se borra por primera vez en GraphicsDevice.Present () si se establece un indicador privado. Por defecto, esta bandera se fija inicialmente (render objetivo es limpio). Dibujo en el objetivo de hacer que borra este indicador (destino de representación ahora sucia). Después de realizar que el deber mismo, GraphicsDevice.Present () de nuevo establece el indicador (destino de representación fue "purgada" a su ventana y se volvió a examinar ahora limpia).

Para obtener resultados de GraphicsDevice.Present (), tendrá que llamar Draw () y EndDraw () en secuencia estricta.

Si llama EndDraw () sin una llamada antes de dibujar (), este beneficio no incluye el contenido del objetivo de hacer (que se limpia), sólo la pantalla de color púrpura en su lugar.

Por desgracia, la bandera es privada y no hay manera limpia para llegar a ella. Puede utilizar la reflexión para borrar el indicador de este tipo, obligando a la sucia objetivo render sin dibujar nada en él:

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

(GraphicsDevice es la instancia GraphicsDevice actual)

Coloque la línea anterior antes de su llamada a EndDraw (), y los revierte el comportamiento a lo que era en 3.1

En mi caso particular, tengo una máquina de estado que cambia entre estados que son responsables de la elaboración. Así que cuando me transición entre dos estados del juego, no hay nada que dibujar, y la pantalla parpadea de color púrpura hasta el siguiente estado del juego está activo.

Lo que hice para resolver era simplemente, en la actualización, si no tengo estado, llamar a la Método SuppressDraw () en el objeto de juego. Este dibujo se llevara a cabo hasta la próxima actualización se lleva a cabo lo impide.

supongo que no hay nada que le para de llamar siempre que en la actualización, excepto cuando se establece una bandera isDirty. Pero tendría que estar preparado para manejar otros eventos / los casos en que la pantalla puede se deterioran.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top