Making your own WP7 Angry Birds – Part 7 – Explosions in the sky

Today is a cosmetic update for the previous post: we will add a animated puff of smoke when one of our boxes is destroyed.

See the video for the effect we want to achieve:

.

1. Smoke animation

We will introduce a class that will draw the explosion. The class will be responsible for the animation as well. What exactly will we animate?
The puff of smoke will be visible for 400 milliseconds. During that time it will go from a solidly rendered sprite to a fully transparent sprite. At the same time, it will scale from 75% up to 175% of its size.

Here’s the smoke sprite we will use in the example. Save it as ‘smoke.png’ and add it to the spritesheet as usual.

2. Framerate-independent animations

The following line of code is a common way of implementing animations, independent from the framerate. If in the future our game runs at 60fps instead of 30, we don’t want the animation to speed up. Rather than that, it will animate is smaller steps, resulting in a smoother animation.

transition += (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
			TimeSpan.FromSeconds(0.4).TotalMilliseconds);

The line above can be called from either a Draw or an Update method and will make the transition variable go from 0.0f to 1.0f in 400 milliseconds. It does so by dividing GameTime.ElapsedGameTime by the desired timespan (0.4s in this case).

GameTime.ElapsedGameTime returns a timespan from since the last Update. By creating the sum of these timespan slices over a period of frames, we eventually reach a total of 1 second. The division slows down the rate at which we achieve 1 second: divide by 2 and it will take 2 seconds instead of 1.

Now you can use the transition variable as a seed for your animations. Need to animate a movement from position X to position X + 200? Simply draw the animation using X + (transition * 200.0f).

You can apply this logic to all instances where you need to have time-dependent, but framerate-independent animations.

3. ExplosionAnimation implementation

Our animated smoke puff will be implemented in an ExplosionAnimation class which has an Activate and a Draw method. Activate will signal that the animation can start, while the Draw method obviously renders the animation on screen.

/// <summary>
/// Component to display an explosion
/// </summary>
public class ExplosionAnimation
{
	private bool _isActive;
	private Vector2 _position;
	private float _rotation;

	private float _transitionValue; // goes from 0 (start explosion) to 1 (end)

	private TimeSpan _timeToLive = TimeSpan.FromSeconds(0.4); //how long the explosion lives

	private readonly string _spritename;

	public ExplosionAnimation(string spritename)
	{
		_spritename = spritename;
	}

	/// <summary>
	/// Start an explosion
	/// </summary>
	/// <param name="body">exploded body</param>
	public void Activate(Body body)
	{
		_position = body.Position * Constants.Scale;
		_rotation = body.Rotation;

		_transitionValue = 0f;
		_isActive = true;
	}

	public void Draw(SpriteBatch sb, SpriteSheet spritesheet, GameTime elapsedGameTime)
	{
		if (_isActive)
		{
			UpdateTransition(elapsedGameTime);

			int colorChannel = 255 - (int)(_transitionValue * 255);
			int alphaCannel = 160 - (int)(_transitionValue * 160);
			Color color = new Color(colorChannel, colorChannel, colorChannel, alphaCannel);
			float scale = 0.75f + _transitionValue;

			Rectangle sourceRect = spritesheet.SourceRectangle(_spritename);
			Vector2 origin = new Vector2(sourceRect.Width / 2.0f, sourceRect.Height / 2.0f);

			sb.Draw(
				spritesheet.Texture,
				_position,
				sourceRect,
				color,
				_rotation,
				origin,
				scale,
				SpriteEffects.None,
				0);
		}
	}

	private void UpdateTransition(GameTime elapsedGameTime)
	{
		// How much should we move by?
		float transitionDelta = (float)(elapsedGameTime.ElapsedGameTime.TotalMilliseconds /
										_timeToLive.TotalMilliseconds);

		// Update the transition position.
		_transitionValue += transitionDelta;

		// Did we reach the end of the transition?
		if (_transitionValue >= 1)
		{
			_transitionValue = 1f;
			_isActive = false;
		}
	}
}

Last time we refactored our drawing code in order to have a Body draw itself through its PrefabUserData instance. We will now extend it so it can Draw an animated explosion.

Add the following property and constructor to PrefabUserData so that it has an instance of ExplosionAnimation available:

public ExplosionAnimation ExplosionAnimation { get; set; }

public PrefabUserData()
{
	ExplosionAnimation = new ExplosionAnimation("smoke");
}

Next, add the Destroy method, which will set the Status to Destroyed and activates the animation.

public void Destroy(Body body)
{
	Status = BodyStatus.Destroyed;
	ExplosionAnimation.Activate(body);
}

Finally, add the following case to PrefabUserData.Draw:

case BodyStatus.Destroyed:
	ExplosionAnimation.Draw(spriteBatch, sheet, gameTime);
	break;

The last step is to update our Game class. Look for the following line within the ProcessContact method:

userData.Status = BodyStatus.ToBeDestroyed

Replace it with:

userData.Destroy(body);

All done!

Advertisements

6 Responses to Making your own WP7 Angry Birds – Part 7 – Explosions in the sky

  1. Ian Ormesher says:

    The last bit about replacing bodyInfo.Status is wrong. The line to replace is in Game1.cs – the ProcessContact method. The old line is:

    userData.Status = BodyStatus.ToBeDestroyed;

    Replace this with:

    userData.Destroy(body);

    This is a great series and I’ve been following it step by step. Thanks Jo.

    Ian

  2. Pingback: Anonymous

  3. jodegreef says:

    Thanks for the comment, I have updated the post accordingly.

  4. Guy Gervais says:

    Just wanted to say “thank you” for taking the time to do such a great tutorial. I’ve just managed to get my appHub account and I’ve been having a going thru each step.

    Looking forward to the next installment.

  5. Ciro says:

    Thanks for this great serie.

  6. Ali says:

    I want to know the solution of these 2 errors. I get them when I run the project.
    Please reply…

    Warning 1 The primary reference “SpriteSheetPipeline” could not be resolved because it has an indirect dependency on the framework assembly “mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” which could not be resolved in the currently targeted framework. “.NETFramework,Version=v4.0,Profile=Client”. To resolve this problem, either remove the reference “SpriteSheetPipeline” or retarget your application to a framework version which contains “mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”.

    Error 2 Installation of the application failed. Run time error has occurred. Fix the Capabilities in WMAppManifest.xml file. 0 0

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: