#region File Description
//-----------------------------------------------------------------------------
// Bee.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion
namespace HoneycombRush
{
///
/// Repesents the base bee component.
///
public abstract class Bee : TexturedDrawableGameComponent
{
#region Fields/Properties
protected static Random random = new Random();
protected Beehive relatedBeehive;
protected Vector2 velocity;
protected float rotation;
protected bool isHitBySmoke;
protected bool isGotHit;
protected string AnimationKey { get; set; }
TimeSpan velocityChangeTimer = TimeSpan.Zero;
///
/// Timespan used to regenerate the be after it is chased away by smoke
///
TimeSpan timeToRegenerate;
///
/// Time at which the bee was hit by smoke
///
TimeSpan timeHit;
public bool IsBeeHit
{
get
{
return isHitBySmoke;
}
}
public Beehive Beehive
{
get
{
return relatedBeehive;
}
}
protected virtual TimeSpan VelocityChangeInterval
{
get
{
return TimeSpan.FromMilliseconds(500);
}
}
public override Rectangle Bounds
{
get
{
if (texture == null)
{
return default(Rectangle);
}
else
{
// The bee's texture is an animation strip, so we must devide the texture's width by three
// to get the bee's actual width
return new Rectangle((int)position.X, (int)position.Y,
(int)(texture.Width / 3 * scaledSpriteBatch.ScaleVector.X),
(int)(texture.Height * scaledSpriteBatch.ScaleVector.Y));
}
}
}
#endregion
#region Abstract Properties
abstract protected int MaxVelocity { get; }
abstract protected float AccelerationFactor { get; }
#endregion
#region Initialization
///
/// Creates a new bee instance.
///
/// The game object.
/// The gameplay screen.
/// The related beehive.
public Bee(Game game, GameplayScreen gamePlayScreen, Beehive beehive)
: base(game, gamePlayScreen)
{
this.relatedBeehive = beehive;
DrawOrder = Int32.MaxValue - 20;
}
///
/// Initialize the bee's location and animation.
///
public override void Initialize()
{
// Start up position
SetStartupPosition();
if (!string.IsNullOrEmpty(AnimationKey))
{
AnimationDefinitions[AnimationKey].PlayFromFrameIndex(0);
}
base.Initialize();
}
#endregion
#region Update
///
/// Updates the bee's status.
///
/// Game time information.
public override void Update(GameTime gameTime)
{
if (!(gamePlayScreen.IsActive && gamePlayScreen.IsStarted))
{
base.Update(gameTime);
return;
}
// This method will handle the regeneration of bees that were hit by
// smoke
if (!HandleRegeneration(gameTime))
{
return;
}
if (!string.IsNullOrEmpty(AnimationKey))
{
AnimationDefinitions[AnimationKey].Update(gameTime, true);
}
// If a bee is hit by smoke, it doesn't have random movement until
// regeneration
if (!isHitBySmoke)
{
SetRandomMovement(gameTime);
}
// Moving the bee according to its velocity
position += velocity * scaledSpriteBatch.ScaleVector;
// If the bee is hit by smoke make it bee move faster
if (isHitBySmoke)
{
position += velocity * scaledSpriteBatch.ScaleVector;
}
// If the bee is out of screen
if (position.X < 0 || position.X > Game.GraphicsDevice.Viewport.Width - Bounds.Width ||
position.Y < 0 || position.Y > Game.GraphicsDevice.Viewport.Height - Bounds.Height)
{
if (isHitBySmoke)
{
// Reset the bee's position
SetStartupPositionWithTimer();
}
else
{
// When hit by the screen bounds, we want the bee to move
// longer than usual before picking a new direction
velocityChangeTimer = TimeSpan.FromMilliseconds(-160);
if (position.X < Bounds.Width || position.X > Game.GraphicsDevice.Viewport.Width - Bounds.Width)
{
velocity = new Vector2(velocity.X *= -1, velocity.Y);
}
else
{
velocity = new Vector2(velocity.X, velocity.Y *= -1);
}
}
}
base.Update(gameTime);
}
#endregion
#region Render
///
/// Renders the bee.
///
/// Game time information.
public override void Draw(GameTime gameTime)
{
if (gamePlayScreen.IsActive && gamePlayScreen.IsStarted)
{
scaledSpriteBatch.Begin();
// If the bee has an animation, draw it
if (!string.IsNullOrEmpty(AnimationKey))
{
AnimationDefinitions[AnimationKey].Draw(scaledSpriteBatch, position, SpriteEffects.None);
}
else
{
scaledSpriteBatch.Draw(texture, position, null, Color.White, 0, Vector2.Zero, 1f,
SpriteEffects.None, 0);
}
scaledSpriteBatch.End();
}
base.Draw(gameTime);
}
#endregion
#region Public Methods
///
/// Denotes that the bee has been hit by smoke.
///
/// The smoke puff which the be was hit by.
public void HitBySmoke(SmokePuff smokePuff)
{
if (!isHitBySmoke)
{
// Causes the bee to fly away from the smoke puff
Vector2 escapeVector = Bounds.Center.GetVector() - smokePuff.Bounds.Center.GetVector();
escapeVector.Normalize();
escapeVector *= random.Next(3, 6);
velocity = escapeVector;
isHitBySmoke = true;
}
}
///
/// Sets the startup position for the bee.
///
public virtual void SetStartupPosition()
{
if (relatedBeehive.AllowBeesToGenerate)
{
Rectangle rect = relatedBeehive.Bounds;
position = new Vector2(rect.Center.X, rect.Center.Y);
velocity = new Vector2(random.Next(-MaxVelocity * 100, MaxVelocity * 100) / 100,
random.Next(-MaxVelocity * 100, MaxVelocity * 100) / 100);
isHitBySmoke = false;
timeToRegenerate = TimeSpan.Zero;
timeHit = TimeSpan.Zero;
}
}
///
/// Checks collision with a specified rectangle.
///
/// Rectabgke with which to check for collisions.
public void Collide(Rectangle bounds)
{
// Check if this collision is new
if (!isGotHit)
{
// Moves to new dircetion calculted by the "wall" that the bee collided
// with.
velocityChangeTimer = TimeSpan.FromMilliseconds(-300);
if (position.X < bounds.X || position.X > bounds.X + bounds.Width)
{
velocity = new Vector2(velocity.X *= -1, velocity.Y);
}
else
{
velocity = new Vector2(velocity.X, velocity.Y *= -1);
}
isGotHit = true;
}
}
#endregion
#region Private Methods
///
/// Set a timer which will cause the be to regenerate when it expires.
///
private void SetStartupPositionWithTimer()
{
timeToRegenerate = TimeSpan.FromMilliseconds(random.Next(3000, 5000));
}
///
/// This method handles a bee's regeneration.
///
/// Game time information.
/// True if the bee has regenerated or no regeneration was necessary,
/// false otherwise.
private bool HandleRegeneration(GameTime gameTime)
{
// Checks if regeneration is needed
if (timeToRegenerate != TimeSpan.Zero)
{
// Saves the time the bee was hit
if (timeHit == TimeSpan.Zero)
{
timeHit = gameTime.TotalGameTime;
}
// If enough time has pass, regenerate the bee
if (timeToRegenerate + timeHit < gameTime.TotalGameTime)
{
SetStartupPosition();
}
else
{
position = new Vector2(-texture.Width, -texture.Height);
return false;
}
}
return true;
}
///
/// Alter the bee's movement randomly.
///
/// Game time information.
private void SetRandomMovement(GameTime gameTime)
{
velocityChangeTimer += gameTime.ElapsedGameTime;
if (velocityChangeTimer >= VelocityChangeInterval)
{
velocity = new Vector2(random.Next(-MaxVelocity * 100, MaxVelocity * 100) / 100,
random.Next(-MaxVelocity * 100, MaxVelocity * 100) / 100);
velocityChangeTimer = TimeSpan.Zero;
if (isGotHit)
{
isGotHit = false;
}
}
}
#endregion
}
}