/* * CheetahFighter.cs * Authors: August Zinsser, Adam Nabinger * Copyright (c) 2007-2008 Cornell University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using TACParticleEngine.Particles; namespace MaritimeDefender { /// /// This class represents the player's ship in the meteor madness game. /// It can move according the rules of meteor madness, and also informs MM where to draw the ship and where to draw its projectiles /// public class CheetahFighter : Entity { #region Constants // Rate at which the firing delay decreases by. private const float SHOT_DELAY_DECREASE = .95f; // Amount of damage increase to fired torpedos every level private const float DAMAGE_MODIFIER = 1f; /// /// Rate at which the shield recharges. 1 = 100% /// public const float SHIELD_RECHARGE_RATE = .02f; /// /// Base damage of the fired torpedo /// public const int SHOT_DAMAGE = 10; /// /// How fast the shield recharges its recharge rate in seconds /// public const float HEALTH_TIME = 5f; #endregion #region Fields // Checks if engine has already been set after visibilty was changed private bool mSetChecker; // The number of weapon upgrades collected private static int mCollectedUpgrades = 1; // Degrees of a circle corresponding to the player's ship's position private float mArcPosition; // Speed at which the ship can change its arcposition private float mArcVelocity; // The current cooldown for the player's lasers in the shooter phase of meteor madness private static float mWeaponCooldown = .25f; // Distance from the center of the image to each firing point (in relation to width and height) private readonly List mWeaponOffsets; // An index of which of the 4 weapon locations to fire next private int mFireNext; // Visually roll the ship as it turns private float mRoll; // Speed at which the ship rolls private readonly float mRollVelocity; // Max amount to roll the ship private readonly float mRollMax; // Offset to draw the flare private Vector2 mEngineOffset; // Size of this entity in space3D coordinates private Vector3 mSpace3DSize; // Reference to the current Maritime Defender game screen private readonly MaritimeDefender m_Game; // Particle effect for the engine of the cheetah ship private ParticleEngine mCheetahEngine; // Particle effect for shield visualization for when the cheetah ship is hit private ParticleEngine mCheetahHit; // Particle effect for when the cheeth ship explodes at death private ParticleEngine mCheetahDeath; #endregion #region Properties /// /// Gets/Sets the number of weapon upgrades collected /// public static int CollectedUpgrades { get { return mCollectedUpgrades; } set { mCollectedUpgrades = value; } } /// /// Gets/Sets the degrees of a circle corresponding to the player's ship's position /// public float ArcPosition { get { return mArcPosition; } set { mArcPosition = value; } } /// /// Gets/Sets the speed at which the ship can change its arcposition /// public float ArcVelocity { get { return mArcVelocity; } set { mArcVelocity = value; } } /// /// Gets/Sets the current cooldown for the player's lasers in the shooter phase of meteor madness /// public float WeaponCooldown { get { return mWeaponCooldown; } set { mWeaponCooldown = value; } } /// /// Gets/Sets the width of the cheetah ship /// public override float Width { get { return mSpace3DSize.X; } set { mSpace3DSize.X = value; } } /// /// Gets/Sets the height of the cheetah ship /// public override float Height { get { return mSpace3DSize.Y; } set { mSpace3DSize.Y = value; } } /// /// Gets/Sets the depth of the cheetah ship /// public override float Depth { get { return mSpace3DSize.Z; } set { mSpace3DSize.Z = value; } } /// /// Gets the 3-dimensional size of the cheetah ship /// public override Vector3 Size { get { return mSpace3DSize; } } #endregion #region Creation /// /// Constructor /// /// The path name of the texture to use for the ship /// The width of the ship /// In height of the ship /// In depth of the ship /// Reference to the current Maritime Defender game screen public CheetahFighter(string spriteName, float width, float height, float depth, MaritimeDefender game) : base(spriteName) { mAlive = true; m_Game = game; mSpace3DSize = new Vector3(width, height, depth); mArcPosition = MathHelper.PiOver2; mArcVelocity = MathHelper.Pi * (5f/6f); mSize.Z = depth; mPos.Z = depth; mRollMax = MathHelper.PiOver4; mRollVelocity = mRollMax; mWeaponOffsets = new List(); mWeaponOffsets.Add(new Vector2(.5f, -.8f)); mWeaponOffsets.Add(new Vector2(-.9f, .1f)); mWeaponOffsets.Add(new Vector2(.9f, .1f)); mWeaponOffsets.Add(new Vector2(-.5f, -.8f)); mEngineOffset = new Vector2(0f, 100f * mSpace3DSize.Y); LoadContent(m_Game.Content); UpdatePosition(); } #endregion #region Management /// /// Loads in any necessary information for all content dependent objects /// /// Reference to the current content manager for loading content public override void LoadContent(Microsoft.Xna.Framework.Content.ContentManager content) { mCheetahHit = m_Game.MMParticleManager.Load("ParticleEffects/Shield"); mCheetahDeath = m_Game.MMParticleManager.Load("ParticleEffects/Explosion"); mCheetahEngine = m_Game.MMParticleManager.Load("ParticleEffects/Engine"); base.LoadContent(content); } /// /// Unloads and cleans up any objects left over /// public override void UnloadContent() { mCheetahHit.ToDestory = true; mCheetahDeath.ToDestory = true; mCheetahEngine.ToDestory = true; mCheetahEngine.SetActive(false); base.UnloadContent(); } #endregion #region Update /// /// Updates game logic /// /// Time that has passed in game public override void Update(GameTime gameTime) { float dT = (float)gameTime.ElapsedGameTime.TotalSeconds; UpdatePosition(); if (mVisible != mSetChecker) { mCheetahEngine.SetActive(mVisible); mSetChecker = mVisible; } base.Update(gameTime); // Return roll to neutral if (mRoll > 0) mRoll *= 0.8f; else if (mRoll < 0) mRoll *= 0.8f; if (Math.Abs(mRoll) < mRollMax * 0.1f) mRoll = 0f; } /// /// Updates the inherited Position properties based on the arcposition /// private void UpdatePosition() { if (!IsLerping) { // Get its position based its angle on the circle Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(mArcPosition), (float)Math.Sin(mArcPosition)); // Move the ship away from the edge of the screen for aesthetics mPos.X = .8F * PositionFromOrigin.X; mPos.Y = .8F * PositionFromOrigin.Y; // Cleanup variables mArcPosition %= MathHelper.TwoPi; mRot = mArcPosition - MathHelper.PiOver2; if (mRoll != 0f) { mRot += mRoll; } } mCheetahEngine.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos)); mCheetahHit.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos)); } /// /// Moves to the given arc position over the specified interval /// /// The new position to set the ship to /// The duration of time in which the ship will roll into place public void Lerp(float newArcPosition, float duration) { mArcPosition = newArcPosition; // Get the new position based its angle on the circle Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(mArcPosition), (float)Math.Sin(mArcPosition)); // Move the ship away from the edge of the screen for aesthetics Vector3 newPos = new Vector3( newPos.X = .8F * PositionFromOrigin.X, newPos.Y = .8F * PositionFromOrigin.Y, mPos.Z); Lerp(newPos, mSize, (float)(mRot - mRoll), duration); } #endregion #region Movement /// /// Moves the ship clockwise on the circle that it is allowed to move on /// /// Time that has passed since the last update public void MoveRight(float dt) { mArcPosition -= mArcVelocity * dt; mRoll = mRollMax; } /// /// Moves the ship counterclockwise on the circle /// /// Time that has passed since the last update public void MoveLeft(float dt) { mArcPosition += mArcVelocity * dt; mRoll = -mRollMax; } #endregion #region Getters /// /// Returns the x and y screen location of the next spawn point for a projectile /// /// The x and y screen location of the next spawn point for a projectile public Vector2 GetNextFiringLocation() { // Get the offset based on width, and then rotate it with the ship float offX = mWeaponOffsets[mFireNext].X * mSpace3DSize.X; float offY = mWeaponOffsets[mFireNext].Y * mSpace3DSize.Y; float retX = mPos.X + (float)Math.Cos(mRot) * offX - (float)Math.Sin(mRot) * offY; float retY = mPos.Y + (float)Math.Sin(mRot) * offX + (float)Math.Cos(mRot) * offY; if (++mFireNext >= mWeaponOffsets.Count) { mFireNext = 0; } return new Vector2(retX, retY); } #endregion #region Effect Deactivation /// /// Removes the engine flare from the particle engine /// public void KillEngineFlare() { mCheetahEngine.SetActive(false); } /// /// Activates the engine flare from the particle engine /// public void ActivateEngineFlare() { mCheetahEngine.SetActive(true); } #endregion #region Player State Modifier /// /// Fires a photon torpedo from one of the 4 lasers on the player's ship /// /// Reference to the fired torpedo public PhotonTorpedo FireTorpedo() { PhotonTorpedo retTorpedo = new PhotonTorpedo( true, true, mCollectedUpgrades, new Vector3(GetNextFiringLocation(), 0f), Width * .5f, Width * .5f, Width * .5f, 5f, .01f, 15f, m_Game); retTorpedo.Friendly = true; retTorpedo.Damage = SHOT_DAMAGE + (int)(DAMAGE_MODIFIER * mCollectedUpgrades); return retTorpedo; } /// /// Upgrades the player's weapon after collecting a weapon upgrade /// public void UpgradeWeapon() { mCollectedUpgrades++; mWeaponCooldown *= SHOT_DELAY_DECREASE; } /// /// Displays the appropriate particle effects /// public void GetHit() { // Indicate the strength of the remaining shields through color and opacity of a particle effect float percentLeft = m_Game.DotShields; if (percentLeft >= 0) { SoundManager.SoundManager.PlayEffect("Zzt"); mCheetahHit.SetEngineColor(new Vector4(1 - percentLeft, 0, percentLeft, 0.5f), false); mCheetahHit.SetActive(true); } } /// /// Updates appropriate variables and spawns an explosion at the player's previous location /// public void DestroyPlayer() { SoundManager.SoundManager.PlayEffect("Smash"); mCheetahHit.SetActive(false); mCheetahEngine.SetActive(false); mCheetahDeath.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos)); mCheetahDeath.SetActive(true); mCheetahDeath.ToDestory = true; mCheetahEngine.ToDestory = true; mCheetahHit.ToDestory = true; mAlive = false; } #endregion } }