/*
* MeteorWidgets.cs
* Authors: August Zinsser
*
* Copyright Matthew Belmonte 2007
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using tAC_Engine;
namespace Astropolis
{
// A collection of widgets for use in the Meteor Madness HUD
///
/// A mock cockpit of the fighter in Meteor Madness. Used by the dot trial phase.
/// Also generates a HUD element for shields ("the pilot's HUD") which is tied to a component in the cockpit
///
public class Cockpit : Widget2D
{
protected StaticSprite mBase; // The main body of the ship and its console
protected float mBufferPercentage = .3f; // How far the HUD extends past the edge of the screen
protected StaticSprite mShieldScreenShip; // Console element
protected StaticSprite mShieldScreenShield; // ''
protected Texture2D mWarningFlashersOn; // ''
protected Texture2D mButtonsOn; // ''
protected Texture2D mButtonsOff; // ''
protected Texture2D mFlash1On; // ''
protected Texture2D mFlash2On; // ''
protected Texture2D mFlash3On; // ''
protected Texture2D[] mProgressModule; // ''
protected Rectangle[] mProgressModuleLocs; // ''
protected Entity mJoystick; // The joystick with a hand attached to it
protected Vector2 mJoystickOrigOffset; // The initial position of the joystick relative to the center of the screen, in screen pixels
protected float mJoystickOrigTheta; // What rotation it would take to put the joystick straight down and then rotate it into place
protected Entity mLeftHand; // The pilot's left hand
protected Vector2 mLeftHandOrigOffset; // Initial position
protected Vector2 mLeftHandButtonOffset; // The offset of the hand when it pushes the glowing button
protected Vector2 mLeftHandCurrentOffset; // The hand moves, so track it
protected float mLeftHandOrigTheta; // Same as joystick, but for left hand
protected float mLeftHandButtonTheta; // ''
protected float mLeftHandCurrentTheta; // ''
protected Vector2 mShieldOrigOffset; // '' (shield console)
protected float mShieldOrigTheta; // ''
protected Vector2[] mProgressModuleOrigOffset; // '' (progess bar)
protected float[] mProgressModuleOrigTheta; // ''
protected byte[] mProgressModuleOpacity; // ''
protected float mLeftHandSpeed = 1f; // In percentage from orig to button per second
protected float mRoll = 0f; // Roll of the entire ship (in radians)
protected float mMaxRollOffset = .2f; // How far in either direction to allow the ship to roll
protected float mTurnLeftTimer = 0f; // Turn left if > 0
protected float mTurnRightTimer = 0f; // '' right
protected float mTurnTime = .5f; // How long to keep turning
protected float mTurnSpeed = .03f; // Angular velocity during a turn
protected float mReturnSpeed = .005f; // Angular velocity when a turn is completed, going towards a roll of 0
protected float mHitTimer = 0f; // Inidicate that the ship is being hit if > 0
protected float mHitTime = 1f; // The amount of time the ship indicates that it was hit
protected float mWarningThreshold = .4f; // Warning lights stay on if shields drop below this
protected float mWarningBlinkTimer = 0f; // Warning Lights flash if > 0
protected float mIdleFlash1Timer = 0f; // Persistent low-frequency flash
protected float mIdleFlash2Timer = 0f; // Persistent low-frequency flash
protected float mIdleFlash3Timer = 0f; // Persistent low-frequency flash
protected float mIdleFlash1Period = 3f; // ''
protected float mIdleFlash2Period = 4f; // ''
protected float mIdleFlash3Period = 5f; // ''
protected float mButtonPressChance = .4f; // How often the pilot will push a button when hit
protected bool mPushingButton = false; // True when the pilot's hand is reaching towards the button
protected bool mPushedButton = false; // True when the pilot's hand is going back out of frame
protected float mHoldButtonTimer = 0f; // Hold the left hand on the button for a brief time
protected float mHoldButtonTime = .2f; // ''
protected Vector2 mShake; // Offsets for the cockpit shake when it gets hit
protected float mShakeFrequency = 50f; // The frequency of the shake speed (arbitray units).
protected float mShakeMagnitude = 1f; // How far to shake the cockpit when it gets hit (in screen %)
protected float mShieldHudThreshold = .9f; // When shields drop below this, show the pilot's HUD shields
protected ShieldWarning mShieldOverlay; // The pilot's HUD of the shields
protected WindshieldNavInfo mNavInfo; // Nav stuff on the pilot's HUD
///
/// Load images and set parameters
///
public Cockpit()
{
int screenWidth = GenericBaseApplication.GameManager.ScreenWidth;
int screenHeight = GenericBaseApplication.GameManager.ScreenHeight;
Rectangle baseSize = new Rectangle(screenWidth / 2, screenHeight / 2, (int)(screenWidth * (1f + (mBufferPercentage * 2))), (int)(screenHeight * (1f + (mBufferPercentage * 2))));
mBase = new StaticSprite(baseSize, .90f, TextureManager.Load(@"Content\MiniGames\Cockpit"));
mShieldOrigOffset = new Vector2(screenWidth * .28f, screenHeight * .42f);
mShieldOrigTheta = (float)Math.Atan(mShieldOrigOffset.X / mShieldOrigOffset.Y);
Texture2D shipTex = TextureManager.Load(@"Content\MiniGames\ShieldDisplayShip");
Texture2D shieldTex = TextureManager.Load(@"Content\MiniGames\ShieldDisplayShield");
float displayWidth = screenWidth * .20f;
float displayHeight = shipTex.Height * displayWidth / shipTex.Width;
mShieldScreenShip = new StaticSprite(new Rectangle(0, 0, (int)displayWidth, (int)displayHeight), .69f, shipTex);
mShieldScreenShield = new StaticSprite(new Rectangle(0, 0, (int)displayWidth, (int)displayHeight), .70f, shieldTex);
mJoystickOrigOffset = new Vector2(0, screenHeight * .62f);
mJoystickOrigTheta = (float)Math.Atan(mJoystickOrigOffset.X / mJoystickOrigOffset.Y);
Texture2D joystickTex = TextureManager.Load(@"Content\MiniGames\CockpitJoystick");
displayWidth = baseSize.Width * .4f;
displayHeight = joystickTex.Height * displayWidth / joystickTex.Width;
mJoystick = new Entity(joystickTex, displayWidth, displayHeight);
mLeftHandOrigOffset = new Vector2(screenWidth * -.45f, screenHeight * 2f);
mLeftHandButtonOffset = new Vector2(screenWidth * -.38f, screenHeight * .87f);
mLeftHandOrigTheta = (float)Math.Atan(mLeftHandOrigOffset.X / mLeftHandOrigOffset.Y);
mLeftHandButtonTheta = (float)Math.Atan(mLeftHandButtonOffset.X / mLeftHandButtonOffset.Y);
mLeftHandCurrentOffset = mLeftHandOrigOffset;
Texture2D handTex = TextureManager.Load(@"Content\MiniGames\CockpitLeftHand");
displayWidth = baseSize.Width * .2f;
displayHeight = handTex.Height * displayWidth / handTex.Width;
mLeftHand = new Entity(handTex, displayWidth, displayHeight);
mWarningFlashersOn = TextureManager.Load(@"Content\Minigames\CockpitWarningLightsOn");
mButtonsOn = TextureManager.Load(@"Content\Minigames\CockpitButtonsOn");
mButtonsOff = TextureManager.Load(@"Content\Minigames\CockpitButtons");
mFlash1On = TextureManager.Load(@"Content\Minigames\CockpitFlashBut1On");
mFlash2On = TextureManager.Load(@"Content\Minigames\CockpitFlashBut2On");
mFlash3On = TextureManager.Load(@"Content\Minigames\CockpitFlashBut3On");
mProgressModule = new Texture2D[2];
mProgressModule[0] = TextureManager.Load(@"Content\MiniGames\CockpitProgressModule");
mProgressModule[1] = TextureManager.Load(@"Content\MiniGames\CockpitProgressModule2");
mProgressModuleLocs = new Rectangle[10];
mProgressModuleOrigOffset = new Vector2[10];
mProgressModuleOrigTheta = new float[10];
mProgressModuleOpacity = new byte[10];
displayWidth = baseSize.Width * .019f;
displayHeight = mProgressModule[0].Height * displayWidth / mProgressModule[0].Width;
displayWidth += baseSize.Width * .007f; // Stretch them width-wise
float startX = screenWidth * -.184f;
float endX = screenWidth * .109f;
for (int i = 0; i < 10; i++)
{
mProgressModuleLocs[i] = new Rectangle(0, 0, (int)displayWidth, (int)displayHeight);
mProgressModuleOrigOffset[i] = new Vector2(endX * (i / 9f) + startX * ((9 - i) / 9f), screenHeight * .204f);
mProgressModuleOrigTheta[i] = (float)Math.Atan(mProgressModuleOrigOffset[i].X / mProgressModuleOrigOffset[i].Y);
}
mShieldOverlay = new ShieldWarning();
mNavInfo = new WindshieldNavInfo();
mShieldOverlay.Visible = false;
mNavInfo.Visible = false;
HUD.Add(mShieldOverlay);
HUD.Add(mNavInfo);
}
///
/// Turns the entire ship to the left. Additionally moves the joystick.
///
public void TurnLeft()
{
mTurnLeftTimer = mTurnTime;
}
///
/// Turns the entire ship to the right. Additionally moves the joystick.
///
public void TurnRight()
{
mTurnRightTimer = mTurnTime;
}
///
/// Inform the user that ship is taking damage
///
public void TakeDamage()
{
mHitTimer = mHitTime;
mWarningBlinkTimer = mHitTime * 2;
if (GenericBaseApplication.GameManager.RandomNumber() < mButtonPressChance)
mPushingButton = true;
if (AstroBaseApplication.GameManager.DotShields < mShieldHudThreshold)
mShieldOverlay.Show();
}
///
/// True if the cockpit isn't doing anything that would distract the user and taint the dot experiment.
/// "Anything distracting" includes rotation, shaking, and some blinking
///
///
public bool IsStable()
{
return (mRoll == 0 && mShake == Vector2.Zero)
&& mWarningBlinkTimer <= 0f
&& !mPushingButton && !mPushedButton
&& mShieldOverlay.IsStable()
&& mNavInfo.IsStable();
}
///
/// Stays relatively calm unless the ship was just hit (ie fail a trial)
///
public override void Update()
{
float dt = GenericBaseApplication.GameManager.ElapsedSeconds;
int screenCenterX = GenericBaseApplication.GameManager.ScreenWidth / 2;
int screenCenterY = GenericBaseApplication.GameManager.ScreenHeight / 2;
if (mHitTimer > 0)
{
// Get shake offsets
mShake.X = mShakeMagnitude * GenericBaseApplication.GameManager.ScreenWidth * (float)Math.Cos(mHitTimer * mShakeFrequency) * .01f * mHitTimer / mHitTime;
mShake.Y = mShakeMagnitude * GenericBaseApplication.GameManager.ScreenHeight * (float)Math.Sin(mHitTimer * mShakeFrequency * .5f) * .01f * mHitTimer / mHitTime;
}
else
{
mShake = Vector2.Zero;
}
// Roll according to the current turning state
if (mTurnLeftTimer > 0 && mRoll > -mMaxRollOffset)
mRoll -= mTurnSpeed;
if (mTurnRightTimer > 0 && mRoll < mMaxRollOffset)
mRoll += mTurnSpeed;
if (mTurnLeftTimer < 0 && mTurnRightTimer < 0)
{
if (mRoll < -mReturnSpeed)
mRoll += mReturnSpeed;
else if (mRoll > mReturnSpeed)
mRoll -= mReturnSpeed;
else
mRoll = 0f;
}
// Shake the base
mBase.Location.X = screenCenterX + (int)mShake.X;
mBase.Location.Y = screenCenterY + (int)mShake.Y;
// Move the hands
mJoystick.X = screenCenterX + mShake.X + mJoystickOrigOffset.Length() * (float)Math.Sin(mJoystickOrigTheta - mRoll);
mJoystick.Y = screenCenterY + mShake.Y + mJoystickOrigOffset.Length() * (float)Math.Cos(mJoystickOrigTheta - mRoll);
mJoystick.Rotation = mRoll * 4 + (mShake.X * .005f);
if (mPushingButton)
{
Vector2 distanceToMove = mLeftHandButtonOffset - mLeftHandOrigOffset;
distanceToMove *= mLeftHandSpeed * dt;
mLeftHandCurrentOffset += distanceToMove;
mLeftHandCurrentTheta = (float)Math.Atan(mLeftHandCurrentOffset.X / mLeftHandCurrentOffset.Y);
}
if (mPushedButton && mHoldButtonTimer <= 0)
{
Vector2 distanceToMove = mLeftHandOrigOffset - mLeftHandButtonOffset;
distanceToMove *= mLeftHandSpeed * dt;
mLeftHandCurrentOffset += distanceToMove;
mLeftHandCurrentTheta = (float)Math.Atan(mLeftHandCurrentOffset.X / mLeftHandCurrentOffset.Y);
}
if (mLeftHandCurrentOffset.Y < mLeftHandButtonOffset.Y)
{
mLeftHandCurrentOffset = mLeftHandButtonOffset;
mPushingButton = false;
mPushedButton = true;
mHoldButtonTimer = mHoldButtonTime;
}
if (mLeftHandCurrentOffset.Y >= mLeftHandOrigOffset.Y)
{
mLeftHandCurrentOffset = mLeftHandOrigOffset;
mPushedButton = false;
}
mLeftHand.X = screenCenterX + mShake.X * .5f + mLeftHandCurrentOffset.Length() * (float)Math.Sin(mLeftHandCurrentTheta - mRoll);
mLeftHand.Y = screenCenterY + mShake.Y * .5f + mLeftHandCurrentOffset.Length() * (float)Math.Cos(mLeftHandCurrentTheta - mRoll);
mLeftHand.Rotation = mRoll;
// Move the shield console
mShieldScreenShip.Location.X = (int)(screenCenterX + (int)mShake.X + mShieldOrigOffset.Length() * (float)Math.Sin(mShieldOrigTheta - mRoll));
mShieldScreenShip.Location.Y = (int)(screenCenterY + (int)mShake.Y + mShieldOrigOffset.Length() * (float)Math.Cos(mShieldOrigTheta - mRoll));
mShieldScreenShield.Location = mShieldScreenShip.Location;
// Update the shield progress bar
for (int i = 0; i < 10; i++)
{
if (AstroBaseApplication.GameManager.DotShields > (float)(i + 1) / 10f)
mProgressModuleOpacity[i] = 255;
else if (AstroBaseApplication.GameManager.DotShields > (float)(i) / 10f)
mProgressModuleOpacity[i] = (byte)(255 * 10 * (AstroBaseApplication.GameManager.DotShields % .1f));
else
mProgressModuleOpacity[i] = 0;
mProgressModuleLocs[i].X = (int)(screenCenterX + (int)mShake.X + mProgressModuleOrigOffset[i].Length() * (float)Math.Sin(mProgressModuleOrigTheta[i] - mRoll));
mProgressModuleLocs[i].Y = (int)(screenCenterY + (int)mShake.Y + mProgressModuleOrigOffset[i].Length() * (float)Math.Cos(mProgressModuleOrigTheta[i] - mRoll));
}
// Recycle flashes (slightly randomized to prevent brain signal harmonics)
if (mIdleFlash1Timer < -mIdleFlash1Period)
mIdleFlash1Timer += mIdleFlash1Period * 2 - GenericBaseApplication.GameManager.RandomNumber(0f, mIdleFlash1Period * .05f);
if (mIdleFlash2Timer < -mIdleFlash2Period)
mIdleFlash2Timer += mIdleFlash2Period * 2 - GenericBaseApplication.GameManager.RandomNumber(0f, mIdleFlash2Period * .05f);
if (mIdleFlash3Timer < -mIdleFlash3Period)
mIdleFlash3Timer += mIdleFlash3Period * 2 - GenericBaseApplication.GameManager.RandomNumber(0f, mIdleFlash3Period * .05f);
// Update timers
mTurnLeftTimer -= dt;
mTurnRightTimer -= dt;
mHitTimer -= dt;
mWarningBlinkTimer -= dt;
mIdleFlash1Timer -= dt;
mIdleFlash2Timer -= dt;
mIdleFlash3Timer -= dt;
mHoldButtonTimer -= dt;
// Sync windshield HUD
mShieldOverlay.Visible = this.Visible;
mNavInfo.Visible = this.Visible;
mNavInfo.Roll = mRoll;
mNavInfo.Shake = mShake;
base.Update();
}
///
/// Draw each component
///
///
public override void Draw(SpriteBatch spriteBatch)
{
// Draw the cockpit
spriteBatch.Draw(
mBase.Texture,
mBase.Location,
null,
Color.White,
mRoll,
new Vector2((float)mBase.Texture.Width / 2f, (float)mBase.Texture.Height / 2f),
SpriteEffects.None,
mBase.ZDepth);
// Draw the components
spriteBatch.Draw(
mShieldScreenShield.Texture,
mShieldScreenShield.Location,
null,
new Color(
(byte)(255),
(byte)(255 * AstroBaseApplication.GameManager.DotShields),
(byte)(255 * AstroBaseApplication.GameManager.DotShields),
(byte)(255 * .50 * AstroBaseApplication.GameManager.DotShields)),
mRoll,
new Vector2((float)mShieldScreenShield.Texture.Width / 2f, (float)mShieldScreenShield.Texture.Height / 2f),
SpriteEffects.None,
mShieldScreenShield.ZDepth);
spriteBatch.Draw(
mShieldScreenShip.Texture,
mShieldScreenShip.Location,
null,
new Color(255,255,255,(byte)(255.0 * .50)),
mRoll,
new Vector2((float)mShieldScreenShip.Texture.Width / 2f, (float)mShieldScreenShip.Texture.Height / 2f),
SpriteEffects.None,
mShieldScreenShip.ZDepth);
for (int i = 0; i < 10; i++)
{
spriteBatch.Draw(
mProgressModule[i % 2],
mProgressModuleLocs[i],
null,
new Color(255, 255, 255, mProgressModuleOpacity[i]),
mRoll,
new Vector2((float)mProgressModule[i % 2].Width / 2f, (float)mProgressModule[i % 2].Height / 2f),
SpriteEffects.None,
mBase.ZDepth - .01f * i);
}
if (mWarningBlinkTimer > 0 || AstroBaseApplication.GameManager.DotShields < mWarningThreshold)
{
spriteBatch.Draw(
mWarningFlashersOn,
mBase.Location,
null,
Color.White,
mRoll,
new Vector2((float)mWarningFlashersOn.Width / 2f, (float)mWarningFlashersOn.Height / 2f),
SpriteEffects.None,
mBase.ZDepth - .01f);
}
spriteBatch.Draw(
mPushingButton ? mButtonsOn : mButtonsOff,
mBase.Location,
null,
Color.White,
mRoll,
new Vector2((float)mBase.Texture.Width / 2f, (float)mBase.Texture.Height / 2f),
SpriteEffects.None,
mBase.ZDepth - .01f);
spriteBatch.Draw(
mFlash1On,
mBase.Location,
null,
new Color(255, 255, 255, (byte)MathHelper.Clamp(Math.Abs(255 * mIdleFlash1Timer / mIdleFlash1Period), 0, 255)),
mRoll,
new Vector2((float)mFlash1On.Width / 2f, (float)mFlash1On.Height / 2f),
SpriteEffects.None,
mBase.ZDepth - .02f);
spriteBatch.Draw(
mFlash2On,
mBase.Location,
null,
new Color(255, 255, 255, (byte)MathHelper.Clamp(Math.Abs(255 * mIdleFlash2Timer / mIdleFlash2Period), 0, 255)),
mRoll,
new Vector2((float)mFlash2On.Width / 2f, (float)mFlash2On.Height / 2f),
SpriteEffects.None,
mBase.ZDepth - .02f);
spriteBatch.Draw(
mFlash3On,
mBase.Location,
null,
new Color(255, 255, 255, (byte)MathHelper.Clamp(Math.Abs(255 * mIdleFlash3Timer / mIdleFlash3Period), 0, 255)),
mRoll,
new Vector2((float)mFlash3On.Width / 2f, (float)mFlash3On.Height / 2f),
SpriteEffects.None,
mBase.ZDepth - .02f);
// Draw the hands
mJoystick.Draw(spriteBatch);
mLeftHand.Draw(spriteBatch);
base.Draw(spriteBatch);
}
}
///
/// Displays a cross, circle, and other pilot-lookin stuff on the window of the cockpit
///
public class WindshieldNavInfo : Widget2D
{
public float Roll; // Set by the cockpit
public Vector2 Shake; // ''
protected StaticSprite mCircle; // A HUD element
protected StaticSprite mCross; // ''
//protected Entity mTicks; // ''
protected Vector2 mOrigCircleOffset; // Original position of this element
protected Vector2 mOrigCrossOffset; // ''
//protected Vector2 mOrigTickOffset; // ''
protected float mOrigCircleTheta; // Original angle between this the ray from the screen center to this element and a vertical ray
protected float mOrigCrossTheta; // ''
//protected Vector2 mOrigTickTheta; // ''
protected float mOveralOpacity = .8f; // Tone down the HUD element
protected float[] mLagRolls; // Use to make the cross + "down" line lag behind the cockpit roll
protected float mLagRoll; // Average of LagRolls
protected int mLagCount = 50; // Frames to average over for lag roll
protected int mLagIndex = 0; // Last lag roll record
protected bool mLagRollStable; // True if all entries in LagRoll are 0
///
/// Create a new HUD Nav element
///
public WindshieldNavInfo()
{
mHeightPercentage = .4f;
mCircle = new StaticSprite(
Rectangle.Empty,
0f,
TextureManager.Load(@"Content\MiniGames\NavCircle"));
mCross = new StaticSprite(
Rectangle.Empty,
0f,
TextureManager.Load(@"Content\MiniGames\NavCross"));
ChangeResolution();
mLagRolls = new float[mLagCount];
}
///
/// True if the widget is not moving
///
///
public bool IsStable()
{
return mLagRollStable;
}
///
/// Change dimensions
///
public override void ChangeResolution()
{
int screenCenterX = GenericBaseApplication.GameManager.ScreenWidth / 2;
int screenCenterY = GenericBaseApplication.GameManager.ScreenHeight / 2;
int screenWidth = GenericBaseApplication.GameManager.ScreenWidth;
int screenHeight = GenericBaseApplication.GameManager.ScreenHeight;
float heightCircle = screenHeight * mHeightPercentage;
float widthCircle = heightCircle * ((float)mCircle.Texture.Width / (float)mCircle.Texture.Height);
float heightCross = heightCircle * .5f;
float widthCross = heightCross * ((float)mCross.Texture.Width / (float)mCross.Texture.Height);
mCircle.Location.Width = (int)widthCircle;
mCircle.Location.Height = (int)heightCircle;
mCross.Location.Width = (int)widthCross;
mCross.Location.Height = (int)heightCross;
mOrigCircleOffset = new Vector2(screenWidth * .015f, -screenHeight * .18f);
mOrigCrossOffset = new Vector2(0, -screenHeight * .1f);
mOrigCircleTheta = (float)Math.Atan(mOrigCircleOffset.X / mOrigCircleOffset.Y);
mOrigCrossTheta = (float)Math.Atan(mOrigCrossOffset.X / mOrigCrossOffset.Y);
UpdatePositions();
base.ChangeResolution();
}
///
/// Updates the widget
///
public override void Update()
{
float dt = GenericBaseApplication.GameManager.ElapsedSeconds;
mLagRolls[mLagIndex++] = Roll;
if (mLagIndex >= mLagCount)
mLagIndex = 0;
mLagRoll = 0;
for (int i = 0; i < mLagCount; i++)
mLagRoll += mLagRolls[i] * (1 + Shake.Length() * .25f);
mLagRoll /= mLagCount;
mLagRollStable = mLagRoll == 0;
UpdatePositions();
base.Update();
}
///
/// Updates all items to their new position
///
public void UpdatePositions()
{
int screenCenterX = GenericBaseApplication.GameManager.ScreenWidth / 2;
int screenCenterY = GenericBaseApplication.GameManager.ScreenHeight / 2;
// Move with cockpit
mCircle.Location.X = (int)(screenCenterX + Shake.X + (mOrigCircleOffset.Y < 0 ? -1f : 1f) * mOrigCircleOffset.Length() * (float)Math.Sin(mOrigCircleTheta - Roll));
mCircle.Location.Y = (int)(screenCenterY + Shake.Y + (mOrigCircleOffset.Y < 0 ? -1f : 1f) * mOrigCircleOffset.Length() * (float)Math.Cos(mOrigCircleTheta - Roll));
mCross.Location.X = (int)(screenCenterX - mLagRoll * 200f + Shake.X + (mOrigCrossOffset.Y < 0 ? -1f : 1f) * mOrigCrossOffset.Length() * (float)Math.Sin(mOrigCrossTheta - Roll));
mCross.Location.Y = (int)(screenCenterY + Math.Abs(mLagRoll) * 100f + Shake.Y + (mOrigCrossOffset.Y < 0 ? -1f : 1f) * mOrigCrossOffset.Length() * (float)Math.Cos(mOrigCrossTheta - Roll));
}
///
/// Draws the component to the spritebatch
///
///
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(
mCircle.Texture,
mCircle.Location,
null,
new Color(255,255,255,(byte)(255 * mOveralOpacity * .3f)),
Roll,
new Vector2(mCircle.Texture.Width / 2, mCircle.Texture.Height / 2),
SpriteEffects.None,
0f);
spriteBatch.Draw(
mCross.Texture,
mCross.Location,
null,
new Color(255,255,255,(byte)(255 * mOveralOpacity)),
mLagRoll,
new Vector2(mCross.Texture.Width / 2, mCross.Texture.Height / 2),
SpriteEffects.None,
0f);
base.Draw(spriteBatch);
}
}
///
/// Displays a warning on the cockpit windshield when shields are low
///
public class ShieldWarning : Widget2D
{
protected StaticSprite mIcon; // The icon
protected StaticSprite mWarning; // WARNING
protected float mDisplayTimer = 0f; // Displays stuff if > 0
protected float mDisplayTime = 2f; // Seconds to show the shields
protected float mFadeTime = .2f; // How long it takes to fade out
protected float mOveralOpacity = .7f; // Tone down the HUD element
protected float mFadeOpacity = 1f; // Fade out if FadeTime is left
protected Color mIconColor; // Based on shield percentage
protected Color mWarningColor; // ''
protected float mBlinkThreshold = .30f; // When shields drop below this, start blinking
protected float mBlinkTimer = 0f; // Used for blinking
protected float mBlinkHalfPeriod = .4f; // ''
///
/// Load components
///
public ShieldWarning()
{
mHeightPercentage = .075f;
mIcon = new StaticSprite(
Rectangle.Empty,
0f,
TextureManager.Load(@"Content\MiniGames\ShieldWarningIcon"));
mWarning = new StaticSprite(
Rectangle.Empty,
0f,
TextureManager.Load(@"Content\MiniGames\ShieldWarning"));
ChangeResolution();
}
///
/// True if the widget is completely invisible
///
///
public bool IsStable()
{
return mDisplayTimer <= 0;
}
///
/// Displays the shield indicator and then fades out
///
public void Show()
{
mDisplayTimer = mDisplayTime;
}
///
/// Change dimensions
///
public override void ChangeResolution()
{
float height = GenericBaseApplication.GameManager.ScreenHeight * mHeightPercentage;
float widthIcon = height * ((float)mIcon.Texture.Width / (float)mIcon.Texture.Height);
float widthWarning = height * ((float)mWarning.Texture.Width / (float)mWarning.Texture.Height);
int xIcon = (int)(GenericBaseApplication.GameManager.ScreenWidth * .3f);
int yIcon = (int)(GenericBaseApplication.GameManager.ScreenHeight * .3f);
int xWarning = GenericBaseApplication.GameManager.ScreenWidth / 2;
int yWarning = (int)(GenericBaseApplication.GameManager.ScreenHeight * .4f);
mIcon.Location = new Rectangle(xIcon, yIcon, (int)widthIcon, (int)height);
mWarning.Location = new Rectangle(xWarning, yWarning, (int)widthWarning, (int)height);
base.ChangeResolution();
}
///
/// Updates the widget
///
public override void Update()
{
float dt = GenericBaseApplication.GameManager.ElapsedSeconds;
// Blink?
if (AstroBaseApplication.GameManager.DotShields < mBlinkThreshold && mBlinkTimer < -mBlinkHalfPeriod)
{
// Slightly randomize the blink to prevent resonance with the brain
mBlinkTimer = mBlinkHalfPeriod + GenericBaseApplication.GameManager.RandomNumber(0f, mBlinkHalfPeriod * .1f);
}
mBlinkTimer -= dt;
mDisplayTimer -= dt;
base.Update();
}
///
/// Draws the component to the spritebatch
///
///
public override void Draw(SpriteBatch spriteBatch)
{
if (mDisplayTimer > 0)
{
// Shield color
mIconColor = new Color(
255,
(byte)(255 - (255 * (1 - AstroBaseApplication.GameManager.DotShields))),
(byte)(255 - (255 * (1 - AstroBaseApplication.GameManager.DotShields))),
(byte)(255 * mOveralOpacity * mFadeOpacity));
mWarningColor = new Color(
(byte)(0 + (255 * (1 - AstroBaseApplication.GameManager.DotShields))),
0,
(byte)(255 - (255 * (1 - AstroBaseApplication.GameManager.DotShields))),
(byte)(255 * mOveralOpacity * mFadeOpacity));
// Fade
if (mDisplayTimer < mFadeTime)
mFadeOpacity = mDisplayTimer / mFadeTime;
else
mFadeOpacity = 1f;
spriteBatch.Draw(
mIcon.Texture,
mIcon.Location,
null,
mIconColor,
0f,
new Vector2(mIcon.Texture.Width / 2, mIcon.Texture.Height / 2),
SpriteEffects.None,
mIcon.ZDepth);
if (mBlinkTimer > 0)
{
spriteBatch.Draw(
mWarning.Texture,
mWarning.Location,
null,
mWarningColor,
0f,
new Vector2(mWarning.Texture.Width / 2, mWarning.Texture.Height / 2),
SpriteEffects.None,
mWarning.ZDepth);
}
}
base.Draw(spriteBatch);
}
}
}