XNA Sprite Flash-Effekt

8

Ich suche nach einer Möglichkeit, jedes nicht transparente Pixel in einem festen Sprite-Weiß zu rendern (um das Sprite-Weiß zu "blinken", wenn der Spieler Schaden nimmt usw.). Dies ist unter Windows Phone 7.

Ich habe einen sehr einfachen benutzerdefinierten Shader verwendet, um dies unter XNA 3.1 zu tun, aber WP7 unterstützt diese nicht und es ist schwierig, eine Alternative zu finden.

Ich würde mich über Hilfe oder Vorschläge freuen. Ich möchte jedoch lieber nicht manuell eine solide weiße Kopie jedes Sprites in meinem Spiel erstellen.

Ryan McD
quelle
1
Okay, ich habe einen Weg gefunden, aber es ist nicht schön. Lassen Sie es mich ein wenig aufräumen und ich werde meine Antwort aktualisieren.
David Gouveia

Antworten:

9

Methode 1

Sie müssen nicht manuell eine solide weiße Version jedes Sprites in Ihrem Spiel erstellen - Sie können den Prozess auch beim Laden automatisieren. Mit anderen Worten, Sie können Texture2D.GetData()auf die Pixel Ihrer Textur zugreifen (und sie einfach abrufen Color[]), sie durchlaufen und nicht transparente Pixel durch festes Weiß ersetzen und sie dann mit und in einer neuen Textur speichern Texture2D.SetData().

Methode 2

Ich habe versucht, damit herumzuspielen BlendState, konnte aber keinen Weg finden, alles weiß zu machen, zumindest nicht innerhalb der Grenzen des Reach-Profils. Aber wenn jemand einen Weg kennt, lass es mich wissen. Was ich jedoch gefunden habe, war eine Möglichkeit, dies mit dem Schablonenpuffer und der eingebauten AlphaTestEffectKlasse zu tun . Die Idee ist die folgende:

  1. Erstellen Sie einen Backbuffer mit einem Schablonenpuffer.
  2. Löschen Sie den Schablonenpuffer auf Null.
  3. Zeichnen Sie die Sprites, die Sie weiß tönen möchten, und setzen Sie den Schablonenpuffer an dieser Stelle auf 1, wenn sie den Alpha-Test bestehen.
  4. Zeichnen Sie ein weißes Quad, das den gesamten Bildschirm abdeckt, jedoch nur, wenn der Wert des Schablonenpuffers 1 beträgt.

Hier ist der Code, den ich verwendet habe:

(Schritt 1) ​​Stellen Sie zunächst sicher, dass der Backbuffer mit Platz für einen Schablonenpuffer erstellt wird:

graphics = new GraphicsDeviceManager(this) { PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 };

(Schritt 2) Erstellen Sie eine 1x1 weiße Textur, die so skaliert wird, dass sie den gesamten Bildschirm ausfüllt:

private Texture2D pixel;
pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new[] { Color.White });

(Schritt 3) Und jetzt der schwierige Teil - das Rendern. Nun, nicht wirklich schwer, erfordert aber zwei DepthStencilStateObjekte und ein AlphaTestEffectObjekt. Sie sollten diese nur einmal erstellen.

// Clear stencil buffer
GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0f, 0);

// Prepare the alpha test effect object (create it only once on initilization)
AlphaTestEffect alphaTestEffect = new AlphaTestEffect(GraphicsDevice)
{
    DiffuseColor = Color.White.ToVector3(), 
    AlphaFunction = CompareFunction.Greater, 
    ReferenceAlpha = 0, World = Matrix.Identity, 
    View = Matrix.Identity, 
    Projection = Matrix.CreateTranslation(-0.5f, -0.5f, 0) * 
    Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1)
};

// Prepare the first DepthStencilState (create only once, or put it in a static class)
DepthStencilState beforeDepthStencilState = new DepthStencilState
{
    StencilEnable = true, 
    StencilFunction = CompareFunction.Always,
    StencilPass = StencilOperation.Replace, 
    ReferenceStencil = 1
};

// Draw your sprites using the structures above
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, beforeDepthStencilState, null, alphaTestEffect);
spriteBatch.Draw(sprite, new Vector2(300, 150), Color.White);
spriteBatch.End();

// Prepare the second DepthStencilState (create only once, or put it in a static class)
DepthStencilState afterDepthStencilState = new DepthStencilState
{
    StencilEnable = true, 
    StencilFunction = CompareFunction.Equal, 
    ReferenceStencil = 1
};

// Draw a full screen white quad with the structure above
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, afterDepthStencilState, null);
spriteBatch.Draw(pixel, GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();

Und das Ergebnis:

Geben Sie hier die Bildbeschreibung ein

David Gouveia
quelle
Tolle! Vielen Dank, dass Sie sich so viel Mühe gegeben haben, David. Schade, dass es keine einfachere Lösung gibt, aber das sollte den Trick gut machen.
Ryan McD