CarSelection.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. //-----------------------------------------------------------------------------
  2. // CarSelection.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using Microsoft.Xna.Framework;
  8. using Microsoft.Xna.Framework.Graphics;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Text;
  12. using RacingGame.GameLogic;
  13. using RacingGame.Graphics;
  14. using RacingGame.Sounds;
  15. using Texture = RacingGame.Graphics.Texture;
  16. using RacingGame.Shaders;
  17. using RacingGame.Properties;
  18. namespace RacingGame.GameScreens
  19. {
  20. /// <summary>
  21. /// Car selection
  22. /// </summary>
  23. /// <returns>IGame screen</returns>
  24. class CarSelection : IGameScreen
  25. {
  26. /// <summary>
  27. /// Max speed for each car type
  28. /// </summary>
  29. private static float[] CarTypeMaxSpeed = new float[]
  30. {
  31. // Car 1 (orange stripes on top)
  32. CarPhysics.DefaultMaxSpeed * 1.05f, // 288 mph
  33. // Car 2 (blue stripes on side)
  34. CarPhysics.DefaultMaxSpeed, // 275 mph
  35. // Car 3 (Just white)
  36. CarPhysics.DefaultMaxSpeed * 0.88f, // 240 mph
  37. };
  38. /// <summary>
  39. /// Car mass for each car type
  40. /// </summary>
  41. private static float[] CarTypeMass = new float[]
  42. {
  43. // Car 1 (orange stripes on top)
  44. CarPhysics.DefaultCarMass * 1.015f, // 1015 kg
  45. // Car 2 (blue stripes on side)
  46. CarPhysics.DefaultCarMass * 1.175f, // 1175 kg
  47. // Car 3 (Just white)
  48. CarPhysics.DefaultCarMass * 0.875f, // 875 kg
  49. };
  50. /// <summary>
  51. /// Max acceleration for each car type
  52. /// </summary>
  53. private static float[] CarTypeMaxAcceleration = new float[]
  54. {
  55. // Car 1 (orange stripes on top)
  56. CarPhysics.DefaultMaxAccelerationPerSec * 0.85f, // 4 m/s^2
  57. // Car 2 (blue stripes on side)
  58. CarPhysics.DefaultMaxAccelerationPerSec * 1.2f, // 6 m/s^2
  59. // Car 3 (Just white)
  60. CarPhysics.DefaultMaxAccelerationPerSec, // 5 m/s^2
  61. };
  62. // Rest of car variables is automatically calculated below!
  63. /// <summary>
  64. /// Unimplemented
  65. /// </summary>
  66. /// <param name="gameTime"></param>
  67. public void Update(GameTime gameTime)
  68. {
  69. }
  70. /// <summary>
  71. /// Render
  72. /// </summary>
  73. /// <returns>Bool</returns>
  74. public bool Render()
  75. {
  76. if (BaseGame.AllowShadowMapping)
  77. {
  78. // Let camera point directly at the center, around 10 units away.
  79. BaseGame.ViewMatrix = Matrix.CreateLookAt(
  80. new Vector3(0, 10.45f, 2.75f),
  81. new Vector3(0, 0, -1),
  82. new Vector3(0, 0, 1));
  83. // Let the light come from the front!
  84. Vector3 lightDir = -LensFlare.DefaultLightPos;
  85. lightDir = new Vector3(lightDir.X, lightDir.Y, -lightDir.Z);
  86. // LightDirection will normalize
  87. BaseGame.LightDirection = lightDir;
  88. // Show 3d cars
  89. // Rotate all 3 cars depending on the current selection
  90. float perCarRot = MathHelper.Pi * 2.0f / 3.0f;
  91. float newCarSelectionRotationZ =
  92. RacingGameManager.currentCarNumber * perCarRot;
  93. carSelectionRotationZ = InterpolateRotation(
  94. carSelectionRotationZ, newCarSelectionRotationZ,
  95. BaseGame.MoveFactorPerSecond * 5.0f);
  96. // Prebuild all render matrices, we will use them for several times
  97. // here.
  98. Matrix[] renderMatrices = new Matrix[3];
  99. for (int carNum = 0; carNum < 3; carNum++)
  100. renderMatrices[carNum] =
  101. Matrix.CreateRotationZ(BaseGame.TotalTime / 3.9f) *
  102. Matrix.CreateTranslation(new Vector3(0, 5.0f, 0)) *
  103. Matrix.CreateRotationZ(-carSelectionRotationZ + carNum * perCarRot) *
  104. Matrix.CreateTranslation(new Vector3(1.5f, 0.0f, 1.0f));
  105. // Last translation translates the position of the cars in the UI;
  106. // For shadows make sure the car position is the origin
  107. RacingGameManager.Player.SetCarPosition(Vector3.Zero,
  108. new Vector3(0, 1, 0), new Vector3(0, 0, 1));
  109. // Generate shadows
  110. ShaderEffect.shadowMapping.GenerateShadows(
  111. delegate
  112. {
  113. for (int carNum = 0; carNum < 3; carNum++)
  114. // Only the car throws shadows
  115. RacingGameManager.CarModel.GenerateShadow(
  116. renderMatrices[carNum]);
  117. });
  118. // Render shadows
  119. ShaderEffect.shadowMapping.RenderShadows(
  120. delegate
  121. {
  122. for (int carNum = 0; carNum < 3; carNum++)
  123. {
  124. // Both the car and the selection plate receive shadows
  125. RacingGameManager.CarSelectionPlate.UseShadow(
  126. renderMatrices[carNum]);
  127. RacingGameManager.CarModel.UseShadow(renderMatrices[carNum]);
  128. }
  129. });
  130. }
  131. // This starts both menu and in game post screen shader!
  132. // It will render into the sceneMap texture which we will use
  133. // later then.
  134. if (BaseGame.UsePostScreenShaders)
  135. BaseGame.UI.PostScreenMenuShader.Start();
  136. // Render background and black bar
  137. BaseGame.UI.RenderMenuBackground();
  138. BaseGame.UI.RenderBlackBar(170, 390);
  139. // Immediately paint here, else post screen UI will
  140. // be drawn over!
  141. Texture.additiveSprite.End();
  142. Texture.alphaSprite.End();
  143. //SpriteHelper.DrawAllSprites();
  144. // Restart the sprites after the paint
  145. Texture.additiveSprite.Begin(SpriteSortMode.Deferred, BlendState.Additive);
  146. Texture.alphaSprite.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  147. // Cars header
  148. int posX = 10;
  149. int posY = 18;
  150. // UWP COMMENT OUT
  151. //if (Environment.OSVersion.Platform != PlatformID.Win32NT)
  152. //{
  153. // posX += 36;
  154. // posY += 26;
  155. //}
  156. BaseGame.UI.Headers.RenderOnScreenRelative1600(
  157. posX, posY, UIRenderer.HeaderChooseCarGfxRect);
  158. // Allow selecting the car color
  159. TextureFont.WriteText(BaseGame.XToRes(85), BaseGame.YToRes(512),
  160. "Car Color: ");
  161. for (int num = 0; num < RacingGameManager.CarColors.Count; num++)
  162. {
  163. Rectangle rect =
  164. RacingGameManager.currentCarColor == num ?
  165. BaseGame.CalcRectangle(250 + num * 50 - 6, 500 - 6, 46 + 12, 46 + 12) :
  166. BaseGame.CalcRectangle(250 + num * 50, 500, 46, 46);
  167. RacingGameManager.colorSelectionTexture.RenderOnScreen(
  168. rect, RacingGameManager.colorSelectionTexture.GfxRectangle,
  169. RacingGameManager.CarColors[num]);
  170. if (Input.MouseInBox(rect) &&
  171. Input.MouseLeftButtonPressed)
  172. {
  173. if (RacingGameManager.currentCarColor != num)
  174. Sound.Play(Sound.Sounds.Highlight);
  175. RacingGameManager.currentCarColor = num;
  176. }
  177. }
  178. // Show car maxSpeed, Acceleration and Mass values.
  179. // Also show braking, friction and engine values based on that.
  180. CarPhysics.SetCarVariablesForCarType(
  181. CarTypeMaxSpeed[RacingGameManager.currentCarNumber],
  182. CarTypeMass[RacingGameManager.currentCarNumber],
  183. CarTypeMaxAcceleration[RacingGameManager.currentCarNumber]);
  184. // Show info and helper texts
  185. //TextureFont.WriteText(30, BaseGame.YToRes(280),
  186. // "Car: Left/Right");
  187. //TextureFont.WriteText(30, BaseGame.YToRes(370),
  188. // "Color: Up/Down");
  189. // Calculate values
  190. float maxSpeed =
  191. -1.5f + 2.45f *
  192. (CarTypeMaxSpeed[RacingGameManager.currentCarNumber] /
  193. CarPhysics.DefaultMaxSpeed);
  194. float acceleration =
  195. -1.25f + 1.85f *
  196. (CarTypeMaxAcceleration[RacingGameManager.currentCarNumber] /
  197. CarPhysics.DefaultMaxAccelerationPerSec);
  198. float mass =
  199. -0.65f + 1.5f *
  200. (CarTypeMass[RacingGameManager.currentCarNumber] /
  201. CarPhysics.DefaultCarMass);
  202. float braking =
  203. -0.2f + acceleration - mass + maxSpeed;
  204. float friction =
  205. -1 + (1 / mass + maxSpeed / 5);
  206. float engine =
  207. -0.2f + 0.5f * (maxSpeed / mass + acceleration - maxSpeed * 5 + 5);
  208. if (engine > 0.95f)
  209. engine = 0.95f;
  210. ShowCarPropertyBar(
  211. BaseGame.XToRes(1024 - 258), BaseGame.YToRes(190),
  212. "Max Speed: " +
  213. (int)(CarTypeMaxSpeed[RacingGameManager.currentCarNumber] /
  214. CarPhysics.MphToMeterPerSec) + "mph",
  215. maxSpeed);
  216. ShowCarPropertyBar(
  217. BaseGame.XToRes(1024 - 258), BaseGame.YToRes(235),
  218. "Acceleration:", acceleration);
  219. ShowCarPropertyBar(
  220. BaseGame.XToRes(1024 - 258), BaseGame.YToRes(280),
  221. "Car Mass:",
  222. mass);
  223. ShowCarPropertyBar(
  224. BaseGame.XToRes(1024 - 258), BaseGame.YToRes(335),
  225. "Braking:", braking);
  226. ShowCarPropertyBar(
  227. BaseGame.XToRes(1024 - 258), BaseGame.YToRes(390),
  228. "Friction:", friction);
  229. ShowCarPropertyBar(
  230. BaseGame.XToRes(1024 - 258), BaseGame.YToRes(445),
  231. "Engine:", engine);
  232. // Also show bouncing arrow on top of car
  233. float arrowWave =
  234. (float)Math.Sin(BaseGame.TotalTime / 0.46f) *
  235. (float)Math.Cos(BaseGame.TotalTime / 0.285f);
  236. float arrowScale = 0.75f - 0.065f * arrowWave;
  237. Rectangle arrowRect = BaseGame.CalcRectangle(512, 120,
  238. (int)Math.Round(UIRenderer.BigArrowGfxRect.Width * arrowScale),
  239. (int)Math.Round(UIRenderer.BigArrowGfxRect.Width * arrowScale));
  240. arrowRect.X -= arrowRect.Width / 2;
  241. // Not displayed anymore ..
  242. // Show left/right arrows
  243. Rectangle selArrowGfxRect = UIRenderer.SelectionArrowGfxRect;
  244. Rectangle leftRect = BaseGame.CalcRectangle(35, 250,
  245. selArrowGfxRect.Width, selArrowGfxRect.Height);
  246. leftRect.Y = BaseGame.YToRes(300 + 60) + arrowRect.Y / 3;
  247. leftRect.X += (int)Math.Round(BaseGame.XToRes(12) * arrowWave);
  248. BaseGame.UI.Buttons.RenderOnScreen(
  249. leftRect, new Rectangle(selArrowGfxRect.X + selArrowGfxRect.Width,
  250. selArrowGfxRect.Y, -selArrowGfxRect.Width, selArrowGfxRect.Height));
  251. Rectangle rightRect = BaseGame.CalcRectangle(
  252. 1024 - 335 - selArrowGfxRect.Width, 250,
  253. selArrowGfxRect.Width, selArrowGfxRect.Height);
  254. rightRect.Y = BaseGame.YToRes(300 + 60) + arrowRect.Y / 3;
  255. rightRect.X -= (int)Math.Round(BaseGame.XToRes(12) * arrowWave);
  256. BaseGame.UI.Buttons.RenderOnScreen(
  257. rightRect, UIRenderer.SelectionArrowGfxRect);
  258. // Also handle xbox controller input
  259. if (Input.GamePadLeftJustPressed ||
  260. Input.KeyboardLeftJustPressed ||
  261. Input.MouseLeftButtonJustPressed &&
  262. Input.MouseInBoxRelative(new Rectangle(512 + 50, 170, 512 - 150, 135)))
  263. {
  264. Sound.Play(Sound.Sounds.Highlight);
  265. RacingGameManager.currentCarNumber =
  266. (RacingGameManager.currentCarNumber + 1) % 3;
  267. }
  268. else if (Input.GamePadRightJustPressed ||
  269. Input.KeyboardRightJustPressed ||
  270. Input.MouseLeftButtonJustPressed &&
  271. Input.MouseInBoxRelative(new Rectangle(100, 170, 512 - 200, 135)))
  272. {
  273. Sound.Play(Sound.Sounds.Highlight);
  274. RacingGameManager.currentCarNumber =
  275. (RacingGameManager.currentCarNumber + 2) % 3;
  276. }
  277. // Mouse input is handled in RacingGameManager.cs
  278. if (Input.GamePadUpJustPressed ||
  279. Input.KeyboardUpJustPressed)
  280. {
  281. Sound.Play(Sound.Sounds.Highlight);
  282. RacingGameManager.currentCarColor = (RacingGameManager.currentCarColor +
  283. RacingGameManager.NumberOfCarColors - 1) %
  284. RacingGameManager.NumberOfCarColors;
  285. }
  286. else if (Input.GamePadDownJustPressed ||
  287. Input.KeyboardDownJustPressed)
  288. {
  289. Sound.Play(Sound.Sounds.Highlight);
  290. RacingGameManager.currentCarColor =
  291. (RacingGameManager.currentCarColor + 1) %
  292. RacingGameManager.NumberOfCarColors;
  293. }
  294. bool aButtonPressed = BaseGame.UI.RenderBottomButtons(false);
  295. if (Input.GamePadAJustPressed ||
  296. Input.KeyboardSpaceJustPressed ||
  297. aButtonPressed)
  298. {
  299. RacingGameManager.AddGameScreen(new TrackSelection());
  300. return false;
  301. }
  302. if (Input.KeyboardEscapeJustPressed ||
  303. Input.GamePadBJustPressed ||
  304. Input.GamePadBackJustPressed ||
  305. BaseGame.UI.backButtonPressed)
  306. return true;
  307. return false;
  308. }
  309. /// <summary>
  310. /// Helper for rotating the 3 cars in the car selection screen.
  311. /// </summary>
  312. float carSelectionRotationZ = 0.0f;
  313. /// <summary>
  314. /// Helper function for RotateSlowly, max. distance between
  315. /// sourceRot and desiredRot is PI, this allows very easy checks.
  316. /// </summary>
  317. public static void AdjustRotRange(ref float desiredRot, float sourceRot)
  318. {
  319. if (desiredRot >= sourceRot + (float)Math.PI)
  320. desiredRot -= (float)Math.PI * 2.0f;
  321. if (desiredRot < sourceRot - (float)Math.PI)
  322. desiredRot += (float)Math.PI * 2.0f;
  323. }
  324. /// <summary>
  325. /// Adjust rotation to -PI - PI range
  326. /// </summary>
  327. public static void AdjustRotToPIRange(ref float desiredRot)
  328. {
  329. if (desiredRot <= -(float)Math.PI)
  330. desiredRot += (float)Math.PI * 2.0f;
  331. if (desiredRot > (float)Math.PI)
  332. desiredRot -= (float)Math.PI * 2.0f;
  333. }
  334. /// <summary>
  335. /// Interpolate rotation
  336. /// </summary>
  337. /// <param name="rot">Rot</param>
  338. /// <param name="targetRot">Target rot</param>
  339. /// <param name="nearlyEqualRot">Nearly equal rot</param>
  340. /// <returns>Float</returns>
  341. public static float InterpolateRotation(
  342. float rot, float targetRot, float nearlyEqualRot)
  343. {
  344. AdjustRotRange(ref targetRot, rot);
  345. if (rot > targetRot)
  346. {
  347. if (Math.Abs(rot - targetRot) < nearlyEqualRot)
  348. rot = targetRot;
  349. else
  350. rot -= nearlyEqualRot;
  351. }
  352. else if (rot < targetRot)
  353. {
  354. if (Math.Abs(rot - targetRot) < nearlyEqualRot)
  355. rot = targetRot;
  356. else
  357. rot += nearlyEqualRot;
  358. }
  359. // Check if rot is in -PI-PI range (for easier calculations!)
  360. AdjustRotToPIRange(ref rot);
  361. return rot;
  362. }
  363. Rectangle gfxBarFromOptionsScreen = new Rectangle(
  364. 372, 297, 472, 6);
  365. /// <summary>
  366. /// Show car property bar for car selection to differentiate
  367. /// the different cars.
  368. /// </summary>
  369. /// <param name="x"></param>
  370. /// <param name="y"></param>
  371. /// <param name="propertyName"></param>
  372. /// <param name="value"></param>
  373. private void ShowCarPropertyBar(int x, int y,
  374. string propertyName, float value)
  375. {
  376. TextureFont.WriteText(x, y, propertyName);
  377. RacingGameManager.UI.OptionsScreen.RenderOnScreen(
  378. //try1: new Rectangle(x + BaseGame.XToRes(150), y + BaseGame.YToRes(5),
  379. //BaseGame.XToRes((int)(145 * value)), BaseGame.YToRes(6)),
  380. new Rectangle(x, y + BaseGame.YToRes(29),
  381. BaseGame.XToRes((int)(192 * value)), BaseGame.YToRes(6)),
  382. gfxBarFromOptionsScreen);
  383. }
  384. /// <summary>
  385. /// Post user interface render
  386. /// </summary>
  387. public void PostUIRender()
  388. {
  389. // Let camera point directly at the center, around 10 units away.
  390. Matrix remViewMatrix = BaseGame.ViewMatrix;
  391. BaseGame.ViewMatrix = Matrix.CreateLookAt(
  392. new Vector3(0, 10.45f, 2.75f),
  393. new Vector3(0, 0, -1),
  394. new Vector3(0, 0, 1));
  395. // Let the light come from the front!
  396. Vector3 lightDir = -LensFlare.DefaultLightPos;
  397. lightDir = new Vector3(lightDir.X, lightDir.Y, -lightDir.Z);
  398. // LightDirection will normalize
  399. BaseGame.LightDirection = lightDir;
  400. // Show 3d cars
  401. // Rotate all 3 cars depending on the current selection
  402. float perCarRot = MathHelper.Pi * 2.0f / 3.0f;
  403. float newCarSelectionRotationZ =
  404. RacingGameManager.currentCarNumber * perCarRot;
  405. carSelectionRotationZ = InterpolateRotation(
  406. carSelectionRotationZ, newCarSelectionRotationZ,
  407. BaseGame.MoveFactorPerSecond * 5.0f);
  408. // Prebuild all render matrices, we will use them for several times
  409. // here.
  410. Matrix[] renderMatrices = new Matrix[3];
  411. for (int carNum = 0; carNum < 3; carNum++)
  412. renderMatrices[carNum] =
  413. Matrix.CreateRotationZ(BaseGame.TotalTime / 3.9f) *
  414. Matrix.CreateTranslation(new Vector3(0, 5.0f, 0)) *
  415. Matrix.CreateRotationZ(-carSelectionRotationZ + carNum * perCarRot) *
  416. Matrix.CreateTranslation(new Vector3(1.5f, 0.0f, 1.0f));
  417. // Last translation translates the position of the cars in the UI
  418. // For shadows make sure the car position is the origin
  419. RacingGameManager.Player.SetCarPosition(Vector3.Zero,
  420. new Vector3(0, 1, 0), new Vector3(0, 0, 1));
  421. // Now do the real rendering:
  422. for (int carNum = 0; carNum < 3; carNum++)
  423. {
  424. RacingGameManager.CarSelectionPlate.Render(renderMatrices[carNum]);
  425. RacingGameManager.CarModel.RenderCar(
  426. carNum,
  427. RacingGameManager.CarColor,
  428. false,
  429. renderMatrices[carNum]);
  430. }
  431. // Render all models we remembered this frame (we are in PostUIRender,
  432. // and we changed our view matrix, render directly here).
  433. BaseGame.MeshRenderManager.Render();
  434. // And finally add shadows to the scene
  435. if (BaseGame.AllowShadowMapping)
  436. {
  437. ShaderEffect.shadowMapping.ShowShadows();
  438. }
  439. // Reset stuff
  440. BaseGame.WorldMatrix = Matrix.Identity;
  441. BaseGame.ViewMatrix = remViewMatrix;
  442. }
  443. }
  444. }