Game1.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Audio;
  6. using Microsoft.Xna.Framework.Content;
  7. using Microsoft.Xna.Framework.Graphics;
  8. using Microsoft.Xna.Framework.Input;
  9. using Microsoft.Xna.Framework.Media;
  10. namespace Flood_Control
  11. {
  12. /// <summary>
  13. /// This is the main type for your game
  14. /// </summary>
  15. public class Game1 : Microsoft.Xna.Framework.Game
  16. {
  17. GraphicsDeviceManager graphics;
  18. SpriteBatch spriteBatch;
  19. Texture2D playingPieces;
  20. Texture2D backgroundScreen;
  21. Texture2D titleScreen;
  22. GameBoard gameBoard;
  23. SpriteFont pericles36Font;
  24. Vector2 scorePosition = new Vector2(605, 215);
  25. Vector2 gameBoardDisplayOrigin = new Vector2(70, 89);
  26. int playerScore = 0;
  27. enum GameStates { TitleScreen, Playing, GameOver };
  28. GameStates gameState = GameStates.TitleScreen;
  29. Rectangle EmptyPiece = new Rectangle(1, 247, 40, 40);
  30. const float MinTimeSinceLastInput = 0.25f;
  31. float timeSinceLastInput = 0.0f;
  32. Queue<ScoreZoom> ScoreZooms = new Queue<ScoreZoom>();
  33. Vector2 gameOverLocation = new Vector2(200, 260);
  34. float gameOverTimer;
  35. const float MaxFloodCounter = 100.0f;
  36. float floodCount = 0.0f;
  37. float timeSinceLastFloodIncrease = 0.0f;
  38. float timeBetweenFloodIncreases = 1.0f;
  39. float floodIncreaseAmount = 0.5f;
  40. const int MaxWaterHeight = 244;
  41. const int WaterWidth = 297;
  42. Vector2 waterOverlayStart = new Vector2(85, 245);
  43. Vector2 waterPosition = new Vector2(478, 338);
  44. int currentLevel = 0;
  45. int linesCompletedThisLevel = 0;
  46. const float floodAccelerationPerLevel = 0.5f;
  47. Vector2 levelTextPosition = new Vector2(512, 215);
  48. public Game1()
  49. {
  50. graphics = new GraphicsDeviceManager(this);
  51. Content.RootDirectory = "Content";
  52. }
  53. /// <summary>
  54. /// Allows the game to perform any initialization it needs to before starting to run.
  55. /// This is where it can query for any required services and load any non-graphic
  56. /// related content. Calling base.Initialize will enumerate through any components
  57. /// and initialize them as well.
  58. /// </summary>
  59. protected override void Initialize()
  60. {
  61. // TODO: Add your initialization logic here
  62. #if !___MOBILE___
  63. this.IsMouseVisible = true;
  64. #else
  65. this.IsFullScreen = true;
  66. #endif
  67. graphics.PreferredBackBufferWidth = 800;
  68. graphics.PreferredBackBufferHeight = 600;
  69. graphics.ApplyChanges();
  70. gameBoard = new GameBoard();
  71. base.Initialize();
  72. }
  73. /// <summary>
  74. /// LoadContent will be called once per game and is the place to load
  75. /// all of your content.
  76. /// </summary>
  77. protected override void LoadContent()
  78. {
  79. // Create a new SpriteBatch, which can be used to draw textures.
  80. spriteBatch = new SpriteBatch(GraphicsDevice);
  81. playingPieces = Content.Load<Texture2D>(@"Textures\Tile_Sheet");
  82. backgroundScreen = Content.Load<Texture2D>(@"Textures\Background");
  83. titleScreen = Content.Load<Texture2D>(@"Textures\TitleScreen");
  84. pericles36Font = Content.Load<SpriteFont>(@"Fonts\Pericles36");
  85. // TODO: use this.Content to load your game content here
  86. }
  87. /// <summary>
  88. /// UnloadContent will be called once per game and is the place to unload
  89. /// all content.
  90. /// </summary>
  91. protected override void UnloadContent()
  92. {
  93. // TODO: Unload any non ContentManager content here
  94. }
  95. private int DetermineScore(int SquareCount)
  96. {
  97. return (int)((Math.Pow((SquareCount / 5), 2) + SquareCount) * 10);
  98. }
  99. private void CheckScoringChain(List<Vector2> WaterChain)
  100. {
  101. if (WaterChain.Count > 0)
  102. {
  103. Vector2 LastPipe = WaterChain[WaterChain.Count - 1];
  104. if (LastPipe.X == GameBoard.GameBoardWidth - 1)
  105. {
  106. if (gameBoard.HasConnector(
  107. (int)LastPipe.X, (int)LastPipe.Y, "Right"))
  108. {
  109. playerScore += DetermineScore(WaterChain.Count);
  110. linesCompletedThisLevel++;
  111. floodCount = MathHelper.Clamp(floodCount -
  112. (DetermineScore(WaterChain.Count) / 10), 0.0f, 100.0f);
  113. ScoreZooms.Enqueue(new ScoreZoom("+" +
  114. DetermineScore(WaterChain.Count).ToString(),
  115. new Color(1.0f, 0.0f, 0.0f, 0.4f)));
  116. foreach (Vector2 ScoringSquare in WaterChain)
  117. {
  118. gameBoard.AddFadingPiece(
  119. (int)ScoringSquare.X,
  120. (int)ScoringSquare.Y,
  121. gameBoard.GetSquare(
  122. (int)ScoringSquare.X,
  123. (int)ScoringSquare.Y));
  124. gameBoard.SetSquare((int)ScoringSquare.X,
  125. (int)ScoringSquare.Y, "Empty");
  126. }
  127. if (linesCompletedThisLevel >= 10)
  128. {
  129. StartNewLevel();
  130. }
  131. }
  132. }
  133. }
  134. }
  135. private void HandleMouseInput(MouseState mouseState)
  136. {
  137. int x = ((mouseState.X -
  138. (int)gameBoardDisplayOrigin.X) / GamePiece.PieceWidth);
  139. int y = ((mouseState.Y -
  140. (int)gameBoardDisplayOrigin.Y) / GamePiece.PieceHeight);
  141. if ((x >= 0) && (x < GameBoard.GameBoardWidth) &&
  142. (y >= 0) && (y < GameBoard.GameBoardHeight))
  143. {
  144. if (mouseState.LeftButton == ButtonState.Pressed)
  145. {
  146. gameBoard.AddRotatingPiece(x, y,
  147. gameBoard.GetSquare(x, y), false);
  148. gameBoard.RotatePiece(x, y, false);
  149. timeSinceLastInput = 0.0f;
  150. }
  151. if (mouseState.RightButton == ButtonState.Pressed)
  152. {
  153. gameBoard.AddRotatingPiece(x, y,
  154. gameBoard.GetSquare(x, y), true);
  155. gameBoard.RotatePiece(x, y, true);
  156. timeSinceLastInput = 0.0f;
  157. }
  158. }
  159. }
  160. private void UpdateScoreZooms()
  161. {
  162. int dequeueCounter = 0;
  163. foreach (ScoreZoom zoom in ScoreZooms)
  164. {
  165. zoom.Update();
  166. if (zoom.IsCompleted)
  167. dequeueCounter++;
  168. }
  169. for (int d = 0; d < dequeueCounter; d++)
  170. ScoreZooms.Dequeue();
  171. }
  172. private void StartNewLevel()
  173. {
  174. currentLevel++;
  175. floodCount = 0.0f;
  176. linesCompletedThisLevel = 0;
  177. floodIncreaseAmount += floodAccelerationPerLevel;
  178. gameBoard.ClearBoard();
  179. gameBoard.GenerateNewPieces(false);
  180. }
  181. /// <summary>
  182. /// Allows the game to run logic such as updating the world,
  183. /// checking for collisions, gathering input, and playing audio.
  184. /// </summary>
  185. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  186. protected override void Update(GameTime gameTime)
  187. {
  188. // Allows the game to exit
  189. if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
  190. this.Exit();
  191. // TODO: Add your update logic here
  192. switch (gameState)
  193. {
  194. case GameStates.TitleScreen:
  195. if (Keyboard.GetState().IsKeyDown(Keys.Space))
  196. {
  197. gameBoard.ClearBoard();
  198. gameBoard.GenerateNewPieces(false);
  199. playerScore = 0;
  200. currentLevel = 0;
  201. floodIncreaseAmount = 0.0f;
  202. StartNewLevel();
  203. gameState = GameStates.Playing;
  204. }
  205. break;
  206. case GameStates.Playing:
  207. timeSinceLastInput +=
  208. (float)gameTime.ElapsedGameTime.TotalSeconds;
  209. timeSinceLastFloodIncrease +=
  210. (float)gameTime.ElapsedGameTime.TotalSeconds;
  211. if (timeSinceLastFloodIncrease >= timeBetweenFloodIncreases)
  212. {
  213. floodCount += floodIncreaseAmount;
  214. timeSinceLastFloodIncrease = 0.0f;
  215. if (floodCount >= MaxFloodCounter)
  216. {
  217. gameOverTimer = 8.0f;
  218. gameState = GameStates.GameOver;
  219. }
  220. }
  221. if (gameBoard.ArePiecesAnimating())
  222. {
  223. gameBoard.UpdateAnimatedPieces();
  224. }
  225. else
  226. {
  227. gameBoard.ResetWater();
  228. for (int y = 0; y < GameBoard.GameBoardHeight; y++)
  229. {
  230. CheckScoringChain(gameBoard.GetWaterChain(y));
  231. }
  232. gameBoard.GenerateNewPieces(true);
  233. if (timeSinceLastInput >= MinTimeSinceLastInput)
  234. {
  235. HandleMouseInput(Mouse.GetState());
  236. }
  237. }
  238. UpdateScoreZooms();
  239. break;
  240. case GameStates.GameOver:
  241. gameOverTimer -= (float)gameTime.ElapsedGameTime.TotalSeconds;
  242. if (gameOverTimer <= 0)
  243. {
  244. gameState = GameStates.TitleScreen;
  245. }
  246. break;
  247. }
  248. base.Update(gameTime);
  249. }
  250. private void DrawEmptyPiece(int pixelX, int pixelY)
  251. {
  252. spriteBatch.Draw(
  253. playingPieces,
  254. new Rectangle(pixelX, pixelY,
  255. GamePiece.PieceWidth, GamePiece.PieceHeight),
  256. EmptyPiece,
  257. Color.White);
  258. }
  259. private void DrawStandardPiece(int x, int y,
  260. int pixelX, int pixelY)
  261. {
  262. spriteBatch.Draw(
  263. playingPieces, new Rectangle(pixelX, pixelY,
  264. GamePiece.PieceWidth, GamePiece.PieceHeight),
  265. gameBoard.GetSourceRect(x, y),
  266. Color.White);
  267. }
  268. private void DrawFallingPiece(int pixelX, int pixelY,
  269. string positionName)
  270. {
  271. spriteBatch.Draw(
  272. playingPieces,
  273. new Rectangle(pixelX, pixelY -
  274. gameBoard.fallingPieces[positionName].VerticalOffset,
  275. GamePiece.PieceWidth, GamePiece.PieceHeight),
  276. gameBoard.fallingPieces[positionName].GetSourceRect(),
  277. Color.White);
  278. }
  279. private void DrawFadingPiece(int pixelX, int pixelY,
  280. string positionName)
  281. {
  282. spriteBatch.Draw(
  283. playingPieces,
  284. new Rectangle(pixelX, pixelY,
  285. GamePiece.PieceWidth, GamePiece.PieceHeight),
  286. gameBoard.fadingPieces[positionName].GetSourceRect(),
  287. Color.White *
  288. gameBoard.fadingPieces[positionName].alphaLevel);
  289. }
  290. private void DrawRotatingPiece(int pixelX, int pixelY,
  291. string positionName)
  292. {
  293. spriteBatch.Draw(
  294. playingPieces,
  295. new Rectangle(pixelX + (GamePiece.PieceWidth / 2),
  296. pixelY + (GamePiece.PieceHeight / 2),
  297. GamePiece.PieceWidth,
  298. GamePiece.PieceHeight),
  299. gameBoard.rotatingPieces[positionName].GetSourceRect(),
  300. Color.White,
  301. gameBoard.rotatingPieces[positionName].RotationAmount,
  302. new Vector2(GamePiece.PieceWidth / 2,
  303. GamePiece.PieceHeight / 2),
  304. SpriteEffects.None, 0.0f);
  305. }
  306. /// <summary>
  307. /// This is called when the game should draw itself.
  308. /// </summary>
  309. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  310. protected override void Draw(GameTime gameTime)
  311. {
  312. GraphicsDevice.Clear(Color.CornflowerBlue);
  313. // TODO: Add your drawing code here
  314. if (gameState == GameStates.TitleScreen)
  315. {
  316. spriteBatch.Begin();
  317. spriteBatch.Draw(titleScreen,
  318. new Rectangle(0, 0,
  319. this.Window.ClientBounds.Width,
  320. this.Window.ClientBounds.Height),
  321. Color.White);
  322. spriteBatch.End();
  323. }
  324. if ((gameState == GameStates.Playing) ||
  325. (gameState == GameStates.GameOver))
  326. {
  327. spriteBatch.Begin();
  328. spriteBatch.Draw(backgroundScreen,
  329. new Rectangle(0, 0,
  330. this.Window.ClientBounds.Width,
  331. this.Window.ClientBounds.Height),
  332. Color.White);
  333. for (int x = 0; x < GameBoard.GameBoardWidth; x++)
  334. for (int y = 0; y < GameBoard.GameBoardHeight; y++)
  335. {
  336. int pixelX = (int)gameBoardDisplayOrigin.X +
  337. (x * GamePiece.PieceWidth);
  338. int pixelY = (int)gameBoardDisplayOrigin.Y +
  339. (y * GamePiece.PieceHeight);
  340. DrawEmptyPiece(pixelX, pixelY);
  341. bool pieceDrawn = false;
  342. string positionName = x.ToString() + "_" + y.ToString();
  343. if (gameBoard.rotatingPieces.ContainsKey(positionName))
  344. {
  345. DrawRotatingPiece(pixelX, pixelY, positionName);
  346. pieceDrawn = true;
  347. }
  348. if (gameBoard.fadingPieces.ContainsKey(positionName))
  349. {
  350. DrawFadingPiece(pixelX, pixelY, positionName);
  351. pieceDrawn = true;
  352. }
  353. if (gameBoard.fallingPieces.ContainsKey(positionName))
  354. {
  355. DrawFallingPiece(pixelX, pixelY, positionName);
  356. pieceDrawn = true;
  357. }
  358. if (!pieceDrawn)
  359. {
  360. DrawStandardPiece(x, y, pixelX, pixelY);
  361. }
  362. }
  363. foreach (ScoreZoom zoom in ScoreZooms)
  364. {
  365. spriteBatch.DrawString(pericles36Font, zoom.Text,
  366. new Vector2(this.Window.ClientBounds.Width / 2,
  367. this.Window.ClientBounds.Height / 2),
  368. zoom.DrawColor, 0.0f,
  369. new Vector2(pericles36Font.MeasureString(zoom.Text).X / 2,
  370. pericles36Font.MeasureString(zoom.Text).Y / 2),
  371. zoom.Scale, SpriteEffects.None, 0.0f);
  372. }
  373. spriteBatch.DrawString(pericles36Font,
  374. playerScore.ToString(),
  375. scorePosition,
  376. Color.Black);
  377. spriteBatch.DrawString(pericles36Font,
  378. currentLevel.ToString(),
  379. levelTextPosition,
  380. Color.Black);
  381. int waterHeight = (int)(MaxWaterHeight * (floodCount / 100));
  382. spriteBatch.Draw(backgroundScreen,
  383. new Rectangle(
  384. (int)waterPosition.X,
  385. (int)waterPosition.Y + (MaxWaterHeight - waterHeight),
  386. WaterWidth,
  387. waterHeight),
  388. new Rectangle(
  389. (int)waterOverlayStart.X,
  390. (int)waterOverlayStart.Y + (MaxWaterHeight - waterHeight),
  391. WaterWidth,
  392. waterHeight),
  393. new Color(255, 255, 255, 180));
  394. spriteBatch.End();
  395. }
  396. if (gameState == GameStates.GameOver)
  397. {
  398. spriteBatch.Begin();
  399. spriteBatch.DrawString(pericles36Font,
  400. "G A M E O V E R!",
  401. gameOverLocation,
  402. Color.Yellow);
  403. spriteBatch.End();
  404. }
  405. base.Draw(gameTime);
  406. }
  407. }
  408. }