Ship.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // Ship.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using Microsoft.Xna.Framework;
  12. using Microsoft.Xna.Framework.Graphics;
  13. using Microsoft.Xna.Framework.Input;
  14. using System.Diagnostics;
  15. using Microsoft.Xna.Framework.Audio;
  16. #endregion
  17. namespace Spacewar
  18. {
  19. /// <summary>
  20. /// SpacewarGame ship
  21. /// </summary>
  22. public class Ship : SpacewarSceneItem
  23. {
  24. private Projectiles bullets;
  25. private Particles particles;
  26. private double thrustFrame;
  27. private bool showThrust;
  28. private bool evolved;
  29. private const float ninetyDegrees = (float)(Math.PI / 2.0);
  30. private PlayerIndex player;
  31. private bool playingThrustSound;
  32. private Cue cue;
  33. private const float shotOffset = 20.0f;
  34. private const float shotSpeed = 150.0f;
  35. private bool inHyperspace;
  36. private bool inRecovery;
  37. private double exitHyperspaceTime;
  38. private double exitRecoveryTime;
  39. private const double hyperspaceTime = 1.5;
  40. private bool playedReturn;
  41. private bool invulnerable;
  42. private static Random random = new Random();
  43. private Vector3 direction;
  44. private SpriteBatch batch;
  45. private Vector3[] extendedExtent;
  46. #region Properties
  47. public bool Invulnerable
  48. {
  49. get
  50. {
  51. return invulnerable;
  52. }
  53. set
  54. {
  55. invulnerable = value;
  56. }
  57. }
  58. public bool Uncollidable
  59. {
  60. get
  61. {
  62. return inHyperspace || inRecovery;
  63. }
  64. }
  65. public Vector3[] ExtendedExtent
  66. {
  67. get
  68. {
  69. return extendedExtent;
  70. }
  71. }
  72. #endregion
  73. #region Data for bullet and engine locations
  74. private static Vector3[,] bulletOffsets = new Vector3[,]
  75. {
  76. {
  77. new Vector3(0, 0, -2134f),
  78. new Vector3(0,0, -782),
  79. new Vector3(0, 0, -1068),
  80. },
  81. {
  82. new Vector3(0, 0f, -2134f),
  83. new Vector3(0, 0, -859),
  84. new Vector3(0, 0, -866),
  85. }
  86. };
  87. private static Vector4[,][] engineOffsets = new Vector4[,][]
  88. {
  89. {
  90. //Player 1 - 3 ships
  91. new Vector4[]
  92. {
  93. new Vector4(0, 640, 1146, 1),
  94. new Vector4(-526, -262, 1146, 1),
  95. new Vector4(526, -262, 1146, 1),
  96. },
  97. new Vector4[]
  98. {
  99. new Vector4(-1125, 135, 432, 1),
  100. new Vector4(1125, 135, 432, 1),
  101. new Vector4(0, 0, 1020, 1),
  102. },
  103. new Vector4[]
  104. {
  105. new Vector4(0, 500, 1140, 1),
  106. },
  107. },
  108. {
  109. //Player 2 - 3 ships
  110. new Vector4[]
  111. {
  112. new Vector4(-390, 100, 2013, 1),
  113. new Vector4(390, 100, 2013, 1),
  114. new Vector4(0, -240, 1915, 1),
  115. },
  116. new Vector4[]
  117. {
  118. new Vector4(0, 270, 1013, 1),
  119. new Vector4(-380, 635, 628, 1),
  120. new Vector4(380, 635, 628, 1),
  121. },
  122. new Vector4[]
  123. {
  124. new Vector4(-270, 150, 656, 1),
  125. new Vector4(270, 150, 656, 1),
  126. new Vector4(0, 0, 740, 1),
  127. },
  128. }
  129. };
  130. #endregion
  131. public Ship(Game game, PlayerIndex player, ShipClass shipNumber, int shipSkin, Vector3 initialPosition, Projectiles bullets, Particles particles)
  132. : base(game, new EvolvedShape(game, EvolvedShapes.Ship, player, (int)shipNumber, shipSkin, LightingType.InGame), initialPosition)
  133. {
  134. this.player = player;
  135. this.bullets = bullets;
  136. this.particles = particles;
  137. this.evolved = true;
  138. //Evolved needs scaling
  139. scale = new Vector3(SpacewarGame.Settings.ShipScale, SpacewarGame.Settings.ShipScale, SpacewarGame.Settings.ShipScale);
  140. rotation = new Vector3(MathHelper.ToRadians(90), 0, 0);
  141. direction = new Vector3((float)(-Math.Sin(Rotation.Z)), (float)(Math.Cos(Rotation.Z)), 0);
  142. if (game != null)
  143. {
  144. IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)game.Services.GetService(typeof(IGraphicsDeviceService));
  145. batch = new SpriteBatch(graphicsService.GraphicsDevice);
  146. }
  147. if (shipNumber == ShipClass.Pencil)
  148. extendedExtent = new Vector3[2];
  149. }
  150. public Ship(Game game, PlayerIndex player, Vector3 initialPosition, Projectiles bullets)
  151. : base(game, new RetroShip(game), initialPosition)
  152. {
  153. this.player = player;
  154. this.bullets = bullets;
  155. this.evolved = false;
  156. //Scale the ship to match the screen
  157. scale = new Vector3(8, 8, 8);
  158. }
  159. public PlayerIndex Player
  160. {
  161. get
  162. {
  163. return player;
  164. }
  165. }
  166. public override void Update(TimeSpan time, TimeSpan elapsedTime)
  167. {
  168. acceleration = Vector3.Zero;
  169. if (!Paused)
  170. {
  171. if (!inHyperspace && !inRecovery)
  172. {
  173. //HyperSpace
  174. if (XInputHelper.GamePads[player].LeftTriggerPressed || XInputHelper.GamePads[player].BPressed)
  175. {
  176. inHyperspace = true;
  177. playedReturn = false;
  178. exitHyperspaceTime = time.TotalSeconds + hyperspaceTime;
  179. Sound.PlayCue(Sounds.HyperspaceActivate);
  180. }
  181. //Fire
  182. if (XInputHelper.GamePads[player].RightTriggerPressed || XInputHelper.GamePads[player].APressed)
  183. {
  184. direction.X = (float)(-Math.Sin(Rotation.Z));
  185. direction.Y = (float)(Math.Cos(Rotation.Z));
  186. direction.Z = 0.0f;
  187. direction.Normalize();
  188. if (evolved)
  189. {
  190. //Special case for rockets
  191. if (SpacewarGame.Players[(int)player].ProjectileType == ProjectileType.Rocket)
  192. {
  193. //Don;t take ship velocity into account cos it looks odd
  194. //rockets accelerte so little chance of rear ending
  195. bullets.Add(player,
  196. Vector3.Transform(bulletOffsets[(int)player, (int)SpacewarGame.Players[(int)player].ShipClass], ShapeItem.World),
  197. Vector3.Multiply(direction, shotSpeed),
  198. Rotation.Z,
  199. time, particles);
  200. }
  201. else
  202. {
  203. bullets.Add(player,
  204. Vector3.Transform(bulletOffsets[(int)player, (int)SpacewarGame.Players[(int)player].ShipClass], ShapeItem.World),
  205. Velocity + Vector3.Multiply(direction, shotSpeed),
  206. Rotation.Z,
  207. time, particles);
  208. }
  209. }
  210. else
  211. {
  212. bullets.Add(player,
  213. Vector3.Transform(new Vector3(0, 1.1f, 0), ShapeItem.World),
  214. Velocity + Vector3.Multiply(direction, shotSpeed),
  215. Rotation.Z,
  216. time, null);
  217. }
  218. }
  219. }
  220. //Move ship based on controller and gravity
  221. if (inHyperspace)
  222. {
  223. //Play return sound 1.3s before
  224. if (time.TotalSeconds > exitHyperspaceTime - 1.3 && !playedReturn)
  225. {
  226. playedReturn = true;
  227. Sound.PlayCue(Sounds.HyperspaceReturn);
  228. }
  229. //Wait until the time is up then reappear in a random position
  230. if (time.TotalSeconds > exitHyperspaceTime)
  231. {
  232. inHyperspace = false;
  233. // Asteroids are not allowed to collide with us when we first emerge from Hyperspace
  234. // When no asteroids are colliding with us, this reverts to false!
  235. Invulnerable = true;
  236. position = new Vector3((float)(random.NextDouble() * 800.0 - 400.0), (float)(random.NextDouble() * 500.0 - 250.0), 0);
  237. }
  238. }
  239. else if (inRecovery)
  240. {
  241. //Wait until the time is up then reappear
  242. if (time.TotalSeconds > exitRecoveryTime)
  243. {
  244. inRecovery = false;
  245. // Asteroids are not allowed to collide with us when we first emerge from Recovery
  246. // When no asteroids are colliding with us, this reverts to false!
  247. Invulnerable = true;
  248. }
  249. }
  250. else
  251. {
  252. //Only move ship if we are out of hyperspace and recovery from destruction
  253. rotation.Z -= (float)((double)XInputHelper.GamePads[player].ThumbStickLeftX * elapsedTime.TotalSeconds * 3.0);
  254. if (XInputHelper.GamePads[player].ThumbStickLeftY != 0)
  255. {
  256. if (!playingThrustSound)
  257. {
  258. GamePad.SetVibration(player, .8f, .2f);
  259. if (player == PlayerIndex.One)
  260. {
  261. cue = Sound.Play(Sounds.ThrustPlayer1);
  262. }
  263. else
  264. {
  265. cue = Sound.Play(Sounds.ThrustPlayer2);
  266. }
  267. playingThrustSound = true;
  268. }
  269. //animate the thrust
  270. showThrust = true;
  271. thrustFrame = (thrustFrame + (elapsedTime.TotalSeconds * 12));
  272. if (thrustFrame > 12)
  273. thrustFrame = 12;
  274. float factor = XInputHelper.GamePads[player].ThumbStickLeftY;
  275. Vector2 thrustDirection = new Vector2((float)(-SpacewarGame.Settings.ThrustPower * factor * Math.Sin(Rotation.Z)), (float)(SpacewarGame.Settings.ThrustPower * factor * Math.Cos(Rotation.Z)));
  276. acceleration += new Vector3(thrustDirection.X, thrustDirection.Y, 0);
  277. }
  278. else
  279. {
  280. //Shrink the thrust
  281. thrustFrame += (elapsedTime.TotalSeconds * 12);
  282. if (thrustFrame > 29)
  283. {
  284. showThrust = false;
  285. thrustFrame = 0;
  286. }
  287. if (playingThrustSound)
  288. {
  289. GamePad.SetVibration(player, 0, 0);
  290. Sound.Stop(cue);
  291. playingThrustSound = false;
  292. }
  293. }
  294. //Friction is a function of current velocity
  295. if (evolved)
  296. acceleration -= Velocity * SpacewarGame.Settings.FrictionFactor;
  297. }
  298. }
  299. //Calculate new positions, speeds and other base class stuff
  300. base.Update(time, elapsedTime);
  301. //Limit the speed
  302. if (velocity.Length() > SpacewarGame.Settings.MaxSpeed)
  303. {
  304. velocity = Vector3.Normalize(Velocity) * SpacewarGame.Settings.MaxSpeed;
  305. }
  306. }
  307. /// <summary>
  308. /// Moves the ship back to its starting position
  309. /// </summary>
  310. /// <param name="newPosition">Position to move the ship back to</param>
  311. public void ResetShip(TimeSpan gameTime, Vector3 newPosition)
  312. {
  313. position = newPosition;
  314. rotation.Z = 0f;
  315. velocity = Vector3.Zero;
  316. inRecovery = true;
  317. Invulnerable = true;
  318. inHyperspace = false;
  319. exitRecoveryTime = gameTime.TotalSeconds + SpacewarGame.Settings.ShipRecoveryTime;
  320. }
  321. /// <summary>
  322. /// Silence will shut down any looping sounds that are playing
  323. /// </summary>
  324. public void Silence()
  325. {
  326. if (playingThrustSound)
  327. {
  328. Sound.Stop(cue);
  329. playingThrustSound = false;
  330. GamePad.SetVibration(player, 0, 0);
  331. }
  332. }
  333. public override void OnCreateDevice()
  334. {
  335. IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
  336. batch = new SpriteBatch(graphicsService.GraphicsDevice);
  337. }
  338. public override void Render()
  339. {
  340. //If we are in hyperspace render nothing
  341. if (!inHyperspace && !inRecovery)
  342. {
  343. base.Render();
  344. //Render engine thrust
  345. IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
  346. GraphicsDevice device = graphicsService.GraphicsDevice;
  347. if (showThrust && evolved)
  348. {
  349. Texture2D engine = SpacewarGame.ContentManager.Load<Texture2D>(SpacewarGame.Settings.MediaPath + @"textures\thrust_stripSmall");
  350. batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  351. foreach (Vector4 engineOffset in engineOffsets[(int)player, (int)SpacewarGame.Players[(int)player].ShipClass])
  352. {
  353. //Move into screen space
  354. Vector4 source = Vector4.Transform(engineOffset, ShapeItem.World * SpacewarGame.Camera.View * SpacewarGame.Camera.Projection);
  355. //and into pixels
  356. Vector2 source2D = new Vector2((int)((source.X / source.W + 1f) / 2f * 1280), (int)((-source.Y / source.W + 1f) / 2f * 720));
  357. 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);
  358. }
  359. batch.End();
  360. }
  361. }
  362. }
  363. }
  364. }