[SOLVED] How to make sprite flash white.

I’m trying to use a shader, but I can’t figure out how to make it so when an enemy is hit only it turns white. Creating a new spritebatch begin and end in the enemy draw loop gives an error.

public class Game1 : Game
{
    protected override void Draw(GameTime gameTime)
    {
        spriteBatch.Begin();
        currentState.Draw(spriteBatch);
        spriteBatch.End();
        base.Draw(gameTime);
    }
}

public class BattleState : State
{
    public override void Draw(SpriteBatch spriteBatch)
    {
        starField.Draw(spriteBatch);
        hero.Draw(spriteBatch);
        foreach (Enemy enemy in enemies)
        {
            enemy.Draw(spriteBatch);
        }
    }
}

Your error is likely because you didn’t End the already-begun SpriteBatch first. i.e. in your enemy draw you’d need spriteBatch.End() then spriteBatch.Begin() (with shader stuff), then shaded draw calls, then .End() and .Begin() again at the end so your draw calls after the enemy.Draw still have an active SpriteBatch (that does not have the shader applied).

That said, you don’t need a custom shader just for a simple color overlay. You can simply pass a color (multiplied by a float for transparency) to an overload of SpriteBatch.Draw() and its default shader will handle it.

Do you mean like Color.white * 0.5f? Multiplying it by 0.5f for example makes it transparent and multiplying by 5 makes no difference.

Ah, sorry, I use that method a lot but generally to “tint” a sprite or color a white shape to various colors (which work great because the color is multiplied heh). For a wholly-white “mask”, I believe you will actually need a custom shader. Though, it’ll be a very simple one: for example, just return white if the sample pixel has any alpha, else transparent.

I have a shader I just can’t get it to work for individual sprites, currently it turns the whole screen white.

Instead of having spritebatch begin and end all the way up in Game1 is it a good idea to move them to each classes draw function so?

public class Enemy : Ship
{
    public override void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, isHit ? allwhite : null);
        spriteBatch.Draw(sprite, new Vector2(position.X - width / 2, position.Y - height / 2), quads[direction], Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0.1f);
        spriteBatch.end();
    }
}

Here’s a barebones quick example I put together for this:

Game1.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


namespace Project1
{
	public class Game1 : Game
	{
		GraphicsDeviceManager graphics;
		public static SpriteBatch spriteBatch;
		static bool spriteBatchActive = false;
		public static Texture2D texture;
		public static Effect colorOverlay;
		Thing thing = new Thing();
		Thing2 thing2 = new Thing2();


		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";
		}


		protected override void LoadContent()
		{
			spriteBatch = new SpriteBatch(GraphicsDevice);

			texture = Content.Load<Texture2D>("texture");
			colorOverlay = Content.Load<Effect>("colorOverlay");
		}


		protected override void Draw(GameTime gameTime)
		{
			GraphicsDevice.Clear(Color.CornflowerBlue);

			RestartSpriteBatch();

			thing.Draw(new Vector2(0, 0));
			thing2.Draw(new Vector2(100, 100), Color.Red);
			thing.Draw(new Vector2(200, 200));
			thing2.Draw(new Vector2(300, 300), Color.White);

			EndSpriteBatch();

			base.Draw(gameTime);
		}


		public static void RestartSpriteBatch(Effect effect = null)
		{
			if (spriteBatchActive)
				EndSpriteBatch();

			spriteBatch.Begin(effect: effect);
			spriteBatchActive = true;
		}


		public static void EndSpriteBatch()
		{
			spriteBatch.End();
			spriteBatchActive = false;
		}
	}




	public class Thing
	{
		public void Draw(Vector2 drawPos)
		{
			Game1.spriteBatch.Draw(Game1.texture, drawPos, Color.White);
		}
	}




	public class Thing2
	{
		public void Draw(Vector2 drawPos, Color colorOverlay)
		{
			// switch spritebatch to overlayColor shader
			Game1.colorOverlay.Parameters["overlayColor"].SetValue(colorOverlay.ToVector4());
			Game1.RestartSpriteBatch(Game1.colorOverlay);

			Game1.spriteBatch.Draw(Game1.texture, drawPos, Color.White);

			// switch spritebatch off shader
			Game1.RestartSpriteBatch();
		}
	}
}

colorOverlay.fx

#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_3_0
	#define PS_SHADERMODEL ps_3_0
#else
	#define VS_SHADERMODEL vs_4_0 //_level_9_1
	#define PS_SHADERMODEL ps_4_0 //_level_9_1
#endif




Texture2D SpriteTexture;
sampler2D SpriteTextureSampler = sampler_state { Texture = <SpriteTexture>; };

float4 overlayColor;

float4 transparent = float4(0, 0, 0, 0);




struct ShaderInput
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
	float2 TextureCoordinates : TEXCOORD0;
};


float4 MainPS(ShaderInput input) : COLOR
{
	float4 color = tex2D(SpriteTextureSampler, input.TextureCoordinates);
	if (color.a > 0)
		return overlayColor;
	return transparent;
}


technique SpriteDrawing
{
	pass P0
	{
		PixelShader = compile PS_SHADERMODEL MainPS();
	}
}

Result

3 Likes

This line

colorOverlay = Content.Load<Effect>("colorOverlay");

Is giving me the error message.

SharpDX.SharpDXException: 'HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.

I think I broke something my old shader isn’t working anymore either.

Fixed it with this, forgot I needed it.
graphics.GraphicsProfile = GraphicsProfile.HiDef;

1 Like

It works great. Thank you so much for all the help.

1 Like