#region File Description
//-----------------------------------------------------------------------------
// Asteroid.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;
using Microsoft.Xna.Framework.Content;
#endregion
namespace NetRumble
{
///
/// Asteroids that fill the game world, blocking the player's shots and movements.
///
public class Asteroid : GameplayObject
{
#region Constants
///
/// The ratio of the mass of an asteroid to its radius.
///
const float massRadiusRatio = 0.5f;
///
/// The amount of drag applied to velocity per second,
/// as a percentage of velocity.
///
const float dragPerSecond = 0.15f;
///
/// Scalar to convert the velocity / mass ratio into a "nice" rotational value.
///
const float velocityMassRatioToRotationScalar = 0.0017f;
///
/// Scalar for calculated damage values that asteroids apply to players.
///
const float momentumToDamageScalar = 0.007f;
///
/// The number of variations in textures for asteroids.
///
const int variations = 3;
///
/// The minimum possible initial speed for asteroids.
///
const float initialSpeedMinimum = 32f;
///
/// The minimum possible initial speed for asteroids.
///
const float initialSpeedMaximum = 96f;
#endregion
#region Static Graphics Data
///
/// The asteroid textures.
///
private static Texture2D[] textures = new Texture2D[variations];
#endregion
#region Graphics Data
///
/// The variation of this particular asteroid.
///
private int variation = 0;
public int Variation
{
get { return variation; }
set
{
if ((value < 0) || (value >= variations))
{
throw new ArgumentOutOfRangeException("value");
}
variation = value;
}
}
#endregion
#region Initialization Methods
///
/// Construct a new asteroid.
///
/// The world that this asteroid belongs to.
/// The size of the asteroid.
public Asteroid(float radius)
: base()
{
// safety-check the parameters
if (radius <= 0f)
{
throw new ArgumentOutOfRangeException("radius");
}
// set the collision data
this.radius = radius;
this.mass = this.radius * massRadiusRatio;
this.Velocity = RandomMath.RandomDirection() *
RandomMath.RandomBetween(initialSpeedMinimum, initialSpeedMaximum);
}
#endregion
#region Updating Methods
///
/// Update the asteroid.
///
/// The amount of elapsed time, in seconds.
public override void Update(float elapsedTime)
{
// spin the asteroid based on the radius and velocity
float velocityMassRatio = (Velocity.LengthSquared() / Mass);
rotation += velocityMassRatio * velocityMassRatioToRotationScalar *
elapsedTime;
// apply some drag so the asteroids settle down
Velocity -= Velocity * (elapsedTime * dragPerSecond);
base.Update(elapsedTime);
}
#endregion
#region Drawing Methods
///
/// Draw the asteroid.
///
/// The amount of elapsed time, in seconds.
/// The SpriteBatch object used to draw.
public void Draw(float elapsedTime, SpriteBatch spriteBatch)
{
base.Draw(elapsedTime, spriteBatch, textures[variation], null,
Color.White);
}
#endregion
#region Interaction Methods
///
/// Defines the interaction between the asteroid and a target GameplayObject
/// when they touch.
///
/// The GameplayObject that is touching this one.
/// True if the objects meaningfully interacted.
public override bool Touch(GameplayObject target)
{
// if the asteroid has touched a player, then damage it
Ship player = target as Ship;
if (player != null)
{
// calculate damage as a function of how much the two GameplayObject's
// velocities were going towards one another
Vector2 playerAsteroidVector = Position - player.Position;
if (playerAsteroidVector.LengthSquared() > 0)
{
playerAsteroidVector.Normalize();
float rammingSpeed =
Vector2.Dot(playerAsteroidVector, player.Velocity) -
Vector2.Dot(playerAsteroidVector, Velocity);
float momentum = Mass * rammingSpeed;
player.Damage(this, momentum * momentumToDamageScalar);
}
}
// if the asteroid didn't hit a projectile, play the asteroid-touch sound effect
if ((target is Projectile) == false)
{
AudioManager.PlaySoundEffect("asteroid_touch");
}
return true;
}
#endregion
#region Static Graphics Methods
///
/// The number of variations in asteroids.
///
public static int Variations
{
get { return variations; }
}
///
/// Load all of the static graphics content for this class.
///
/// The content manager to load with.
public static void LoadContent(ContentManager contentManager)
{
// safety-check the parameters
if (contentManager == null)
{
throw new ArgumentNullException("contentManager");
}
// load each asteroid's texture
for (int i = 0; i < variations; i++)
{
textures[i] = contentManager.Load(
"Textures/asteroid" + i.ToString());
}
}
///
/// Unload all of the static graphics content for this class.
///
public static void UnloadContent()
{
for (int i = 0; i < variations; i++)
{
textures[i] = null;
}
}
#endregion
}
}