#region File Description //----------------------------------------------------------------------------- // SmokePuff.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; #endregion namespace HoneycombRush { /// /// Represents a puff of smoke fired from the beekeeper's smoke gun. /// /// Smoke puffs add and remove themselves from the list of game components as appropriate. public class SmokePuff : TexturedDrawableGameComponent { #region Fields/Properties readonly TimeSpan growthTimeInterval = TimeSpan.FromMilliseconds(50); const float growthStep = 0.05f; TimeSpan lifeTime; TimeSpan growthTimeTrack; /// /// Used to scale the smoke puff /// float spreadFactor; Vector2 initialVelocity; Vector2 velocity; Vector2 acceleration; Vector2 drawOrigin; Random random = new Random(); public bool IsGone { get { return lifeTime <= TimeSpan.Zero; } } bool isInGameComponents; /// /// Represents an area used for collision calculations. /// public override Rectangle CentralCollisionArea { get { int boundsWidth = (int)(texture.Width * spreadFactor * 1.5f * scaledSpriteBatch.ScaleVector.X); int boundsHeight = (int)(texture.Height * spreadFactor * 1.5f * scaledSpriteBatch.ScaleVector.Y); return new Rectangle((int)position.X - boundsWidth / 4, (int)position.Y - boundsHeight / 4, boundsWidth, boundsHeight); } } #endregion #region Initialization /// /// Creates a new puff of smoke. /// /// Associated game object. /// The gameplay screen where the smoke puff will be displayed. /// The texture which represents the smoke puff. public SmokePuff(Game game, GameplayScreen gameplayScreen, Texture2D texture) : base(game, gameplayScreen) { this.texture = texture; drawOrigin = new Vector2(texture.Width / 2, texture.Height / 2); DrawOrder = Int32.MaxValue - 15; } /// /// Fires the smoke puff from a specified position and at a specified velocity. This also adds the smoke puff /// to the game component collection. /// /// The position where the smoke puff should first appear. /// A vector indicating the initial velocity for this new smoke puff. /// The smoke puff's acceleration is internaly derived from /// . /// This method is not thread safe and calling it from another thread while the smoke puff expires (via /// its method) might have undesired effects. public void Fire(Vector2 origin, Vector2 initialVelocity) { spreadFactor = 0.05f; lifeTime = TimeSpan.FromSeconds(5); growthTimeTrack = TimeSpan.Zero; position = origin; velocity = initialVelocity; this.initialVelocity = initialVelocity; initialVelocity.Normalize(); acceleration = -(initialVelocity) * 6; if (!isInGameComponents) { Game.Components.Add(this); isInGameComponents = true; } } #endregion #region Update /// /// Performs update logic for the smoke puff. The smoke puff slows down while growing and eventually /// evaporates. /// /// Game time information. public override void Update(GameTime gameTime) { if (!gamePlayScreen.IsActive) { base.Update(gameTime); return; } lifeTime -= gameTime.ElapsedGameTime; // The smoke puff needs to vanish if (lifeTime <= TimeSpan.Zero) { Game.Components.Remove(this); isInGameComponents = false; base.Update(gameTime); return; } growthTimeTrack += gameTime.ElapsedGameTime; // See if it is time for the smoke puff to grow if ((spreadFactor < 1) && (growthTimeTrack >= growthTimeInterval)) { growthTimeTrack = TimeSpan.Zero; spreadFactor += growthStep; } // Stop the smoke once it starts moving in the other direction if (Vector2.Dot(initialVelocity, velocity) > 0) { position += velocity; velocity += acceleration * (float)gameTime.ElapsedGameTime.TotalSeconds; } base.Update(gameTime); } #endregion #region Render /// /// Draws the smoke puff. /// /// Game time information. public override void Draw(GameTime gameTime) { if (!gamePlayScreen.IsActive) { base.Draw(gameTime); return; } scaledSpriteBatch.Begin(); Vector2 offset = GetRandomOffset(); scaledSpriteBatch.Draw(texture, position + offset, null, Color.White, 0, drawOrigin, spreadFactor, SpriteEffects.None, 0); scaledSpriteBatch.End(); base.Draw(gameTime); } /// /// Used to make the smoke puff shift randomly. /// /// An offset which should be added to the smoke puff's position. private Vector2 GetRandomOffset() { return new Vector2(random.Next(2) - 4, random.Next(2) - 4); } #endregion } }