#region File Description //----------------------------------------------------------------------------- // Ship.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.Input; using System.Diagnostics; using Microsoft.Xna.Framework.Audio; #endregion namespace Spacewar { /// /// SpacewarGame ship /// public class Ship : SpacewarSceneItem { private Projectiles bullets; private Particles particles; private double thrustFrame; private bool showThrust; private bool evolved; private const float ninetyDegrees = (float)(Math.PI / 2.0); private PlayerIndex player; private bool playingThrustSound; private Cue cue; private const float shotOffset = 20.0f; private const float shotSpeed = 150.0f; private bool inHyperspace; private bool inRecovery; private double exitHyperspaceTime; private double exitRecoveryTime; private const double hyperspaceTime = 1.5; private bool playedReturn; private bool invulnerable; private static Random random = new Random(); private Vector3 direction; private SpriteBatch batch; private Vector3[] extendedExtent; #region Properties public bool Invulnerable { get { return invulnerable; } set { invulnerable = value; } } public bool Uncollidable { get { return inHyperspace || inRecovery; } } public Vector3[] ExtendedExtent { get { return extendedExtent; } } #endregion #region Data for bullet and engine locations private static Vector3[,] bulletOffsets = new Vector3[,] { { new Vector3(0, 0, -2134f), new Vector3(0,0, -782), new Vector3(0, 0, -1068), }, { new Vector3(0, 0f, -2134f), new Vector3(0, 0, -859), new Vector3(0, 0, -866), } }; private static Vector4[,][] engineOffsets = new Vector4[,][] { { //Player 1 - 3 ships new Vector4[] { new Vector4(0, 640, 1146, 1), new Vector4(-526, -262, 1146, 1), new Vector4(526, -262, 1146, 1), }, new Vector4[] { new Vector4(-1125, 135, 432, 1), new Vector4(1125, 135, 432, 1), new Vector4(0, 0, 1020, 1), }, new Vector4[] { new Vector4(0, 500, 1140, 1), }, }, { //Player 2 - 3 ships new Vector4[] { new Vector4(-390, 100, 2013, 1), new Vector4(390, 100, 2013, 1), new Vector4(0, -240, 1915, 1), }, new Vector4[] { new Vector4(0, 270, 1013, 1), new Vector4(-380, 635, 628, 1), new Vector4(380, 635, 628, 1), }, new Vector4[] { new Vector4(-270, 150, 656, 1), new Vector4(270, 150, 656, 1), new Vector4(0, 0, 740, 1), }, } }; #endregion public Ship(Game game, PlayerIndex player, ShipClass shipNumber, int shipSkin, Vector3 initialPosition, Projectiles bullets, Particles particles) : base(game, new EvolvedShape(game, EvolvedShapes.Ship, player, (int)shipNumber, shipSkin, LightingType.InGame), initialPosition) { this.player = player; this.bullets = bullets; this.particles = particles; this.evolved = true; //Evolved needs scaling scale = new Vector3(SpacewarGame.Settings.ShipScale, SpacewarGame.Settings.ShipScale, SpacewarGame.Settings.ShipScale); rotation = new Vector3(MathHelper.ToRadians(90), 0, 0); direction = new Vector3((float)(-Math.Sin(Rotation.Z)), (float)(Math.Cos(Rotation.Z)), 0); if (game != null) { IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)game.Services.GetService(typeof(IGraphicsDeviceService)); batch = new SpriteBatch(graphicsService.GraphicsDevice); } if (shipNumber == ShipClass.Pencil) extendedExtent = new Vector3[2]; } public Ship(Game game, PlayerIndex player, Vector3 initialPosition, Projectiles bullets) : base(game, new RetroShip(game), initialPosition) { this.player = player; this.bullets = bullets; this.evolved = false; //Scale the ship to match the screen scale = new Vector3(8, 8, 8); } public PlayerIndex Player { get { return player; } } public override void Update(TimeSpan time, TimeSpan elapsedTime) { acceleration = Vector3.Zero; if (!Paused) { if (!inHyperspace && !inRecovery) { //HyperSpace if (XInputHelper.GamePads[player].LeftTriggerPressed || XInputHelper.GamePads[player].BPressed) { inHyperspace = true; playedReturn = false; exitHyperspaceTime = time.TotalSeconds + hyperspaceTime; Sound.PlayCue(Sounds.HyperspaceActivate); } //Fire if (XInputHelper.GamePads[player].RightTriggerPressed || XInputHelper.GamePads[player].APressed) { direction.X = (float)(-Math.Sin(Rotation.Z)); direction.Y = (float)(Math.Cos(Rotation.Z)); direction.Z = 0.0f; direction.Normalize(); if (evolved) { //Special case for rockets if (SpacewarGame.Players[(int)player].ProjectileType == ProjectileType.Rocket) { //Don;t take ship velocity into account cos it looks odd //rockets accelerte so little chance of rear ending bullets.Add(player, Vector3.Transform(bulletOffsets[(int)player, (int)SpacewarGame.Players[(int)player].ShipClass], ShapeItem.World), Vector3.Multiply(direction, shotSpeed), Rotation.Z, time, particles); } else { bullets.Add(player, Vector3.Transform(bulletOffsets[(int)player, (int)SpacewarGame.Players[(int)player].ShipClass], ShapeItem.World), Velocity + Vector3.Multiply(direction, shotSpeed), Rotation.Z, time, particles); } } else { bullets.Add(player, Vector3.Transform(new Vector3(0, 1.1f, 0), ShapeItem.World), Velocity + Vector3.Multiply(direction, shotSpeed), Rotation.Z, time, null); } } } //Move ship based on controller and gravity if (inHyperspace) { //Play return sound 1.3s before if (time.TotalSeconds > exitHyperspaceTime - 1.3 && !playedReturn) { playedReturn = true; Sound.PlayCue(Sounds.HyperspaceReturn); } //Wait until the time is up then reappear in a random position if (time.TotalSeconds > exitHyperspaceTime) { inHyperspace = false; // Asteroids are not allowed to collide with us when we first emerge from Hyperspace // When no asteroids are colliding with us, this reverts to false! Invulnerable = true; position = new Vector3((float)(random.NextDouble() * 800.0 - 400.0), (float)(random.NextDouble() * 500.0 - 250.0), 0); } } else if (inRecovery) { //Wait until the time is up then reappear if (time.TotalSeconds > exitRecoveryTime) { inRecovery = false; // Asteroids are not allowed to collide with us when we first emerge from Recovery // When no asteroids are colliding with us, this reverts to false! Invulnerable = true; } } else { //Only move ship if we are out of hyperspace and recovery from destruction rotation.Z -= (float)((double)XInputHelper.GamePads[player].ThumbStickLeftX * elapsedTime.TotalSeconds * 3.0); if (XInputHelper.GamePads[player].ThumbStickLeftY != 0) { if (!playingThrustSound) { GamePad.SetVibration(player, .8f, .2f); if (player == PlayerIndex.One) { cue = Sound.Play(Sounds.ThrustPlayer1); } else { cue = Sound.Play(Sounds.ThrustPlayer2); } playingThrustSound = true; } //animate the thrust showThrust = true; thrustFrame = (thrustFrame + (elapsedTime.TotalSeconds * 12)); if (thrustFrame > 12) thrustFrame = 12; float factor = XInputHelper.GamePads[player].ThumbStickLeftY; Vector2 thrustDirection = new Vector2((float)(-SpacewarGame.Settings.ThrustPower * factor * Math.Sin(Rotation.Z)), (float)(SpacewarGame.Settings.ThrustPower * factor * Math.Cos(Rotation.Z))); acceleration += new Vector3(thrustDirection.X, thrustDirection.Y, 0); } else { //Shrink the thrust thrustFrame += (elapsedTime.TotalSeconds * 12); if (thrustFrame > 29) { showThrust = false; thrustFrame = 0; } if (playingThrustSound) { GamePad.SetVibration(player, 0, 0); Sound.Stop(cue); playingThrustSound = false; } } //Friction is a function of current velocity if (evolved) acceleration -= Velocity * SpacewarGame.Settings.FrictionFactor; } } //Calculate new positions, speeds and other base class stuff base.Update(time, elapsedTime); //Limit the speed if (velocity.Length() > SpacewarGame.Settings.MaxSpeed) { velocity = Vector3.Normalize(Velocity) * SpacewarGame.Settings.MaxSpeed; } } /// /// Moves the ship back to its starting position /// /// Position to move the ship back to public void ResetShip(TimeSpan gameTime, Vector3 newPosition) { position = newPosition; rotation.Z = 0f; velocity = Vector3.Zero; inRecovery = true; Invulnerable = true; inHyperspace = false; exitRecoveryTime = gameTime.TotalSeconds + SpacewarGame.Settings.ShipRecoveryTime; } /// /// Silence will shut down any looping sounds that are playing /// public void Silence() { if (playingThrustSound) { Sound.Stop(cue); playingThrustSound = false; GamePad.SetVibration(player, 0, 0); } } public override void OnCreateDevice() { IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService)); batch = new SpriteBatch(graphicsService.GraphicsDevice); } public override void Render() { //If we are in hyperspace render nothing if (!inHyperspace && !inRecovery) { base.Render(); //Render engine thrust IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService)); GraphicsDevice device = graphicsService.GraphicsDevice; if (showThrust && evolved) { Texture2D engine = SpacewarGame.ContentManager.Load(SpacewarGame.Settings.MediaPath + @"textures\thrust_stripSmall"); batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend); foreach (Vector4 engineOffset in engineOffsets[(int)player, (int)SpacewarGame.Players[(int)player].ShipClass]) { //Move into screen space Vector4 source = Vector4.Transform(engineOffset, ShapeItem.World * SpacewarGame.Camera.View * SpacewarGame.Camera.Projection); //and into pixels Vector2 source2D = new Vector2((int)((source.X / source.W + 1f) / 2f * 1280), (int)((-source.Y / source.W + 1f) / 2f * 720)); batch.Draw(engine, source2D, new Rectangle(((int)thrustFrame) * 64, 0, 64, 16), Color.White, -Rotation.Z + ninetyDegrees, new Vector2(2, 8), 1f, SpriteEffects.None, 0.1f); } batch.End(); } } } } }