Game1.cs 18 KB

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