using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace Flood_Control { /// /// This is the main type for your game /// public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D playingPieces; Texture2D backgroundScreen; Texture2D titleScreen; GameBoard gameBoard; SpriteFont pericles36Font; Vector2 scorePosition = new Vector2(605, 215); Vector2 gameBoardDisplayOrigin = new Vector2(70, 89); int playerScore = 0; enum GameStates { TitleScreen, Playing, GameOver }; GameStates gameState = GameStates.TitleScreen; Rectangle EmptyPiece = new Rectangle(1, 247, 40, 40); const float MinTimeSinceLastInput = 0.25f; float timeSinceLastInput = 0.0f; Queue ScoreZooms = new Queue(); Vector2 gameOverLocation = new Vector2(200, 260); float gameOverTimer; const float MaxFloodCounter = 100.0f; float floodCount = 0.0f; float timeSinceLastFloodIncrease = 0.0f; float timeBetweenFloodIncreases = 1.0f; float floodIncreaseAmount = 0.5f; const int MaxWaterHeight = 244; const int WaterWidth = 297; Vector2 waterOverlayStart = new Vector2(85, 245); Vector2 waterPosition = new Vector2(478, 338); int currentLevel = 0; int linesCompletedThisLevel = 0; const float floodAccelerationPerLevel = 0.5f; Vector2 levelTextPosition = new Vector2(512, 215); public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// protected override void Initialize() { // TODO: Add your initialization logic here this.IsMouseVisible = true; graphics.PreferredBackBufferWidth = 800; graphics.PreferredBackBufferHeight = 600; graphics.ApplyChanges(); gameBoard = new GameBoard(); base.Initialize(); } /// /// LoadContent will be called once per game and is the place to load /// all of your content. /// protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); playingPieces = Content.Load(@"Textures\Tile_Sheet"); backgroundScreen = Content.Load(@"Textures\Background"); titleScreen = Content.Load(@"Textures\TitleScreen"); pericles36Font = Content.Load(@"Fonts\Pericles36"); // TODO: use this.Content to load your game content here } /// /// UnloadContent will be called once per game and is the place to unload /// all content. /// protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } private int DetermineScore(int SquareCount) { return (int)((Math.Pow((SquareCount / 5), 2) + SquareCount) * 10); } private void CheckScoringChain(List WaterChain) { if (WaterChain.Count > 0) { Vector2 LastPipe = WaterChain[WaterChain.Count - 1]; if (LastPipe.X == GameBoard.GameBoardWidth - 1) { if (gameBoard.HasConnector( (int)LastPipe.X, (int)LastPipe.Y, "Right")) { playerScore += DetermineScore(WaterChain.Count); linesCompletedThisLevel++; floodCount = MathHelper.Clamp(floodCount - (DetermineScore(WaterChain.Count) / 10), 0.0f, 100.0f); ScoreZooms.Enqueue(new ScoreZoom("+" + DetermineScore(WaterChain.Count).ToString(), new Color(1.0f, 0.0f, 0.0f, 0.4f))); foreach (Vector2 ScoringSquare in WaterChain) { gameBoard.AddFadingPiece( (int)ScoringSquare.X, (int)ScoringSquare.Y, gameBoard.GetSquare( (int)ScoringSquare.X, (int)ScoringSquare.Y)); gameBoard.SetSquare((int)ScoringSquare.X, (int)ScoringSquare.Y, "Empty"); } if (linesCompletedThisLevel >= 10) { StartNewLevel(); } } } } } private void HandleMouseInput(MouseState mouseState) { int x = ((mouseState.X - (int)gameBoardDisplayOrigin.X) / GamePiece.PieceWidth); int y = ((mouseState.Y - (int)gameBoardDisplayOrigin.Y) / GamePiece.PieceHeight); if ((x >= 0) && (x < GameBoard.GameBoardWidth) && (y >= 0) && (y < GameBoard.GameBoardHeight)) { if (mouseState.LeftButton == ButtonState.Pressed) { gameBoard.AddRotatingPiece(x, y, gameBoard.GetSquare(x, y), false); gameBoard.RotatePiece(x, y, false); timeSinceLastInput = 0.0f; } if (mouseState.RightButton == ButtonState.Pressed) { gameBoard.AddRotatingPiece(x, y, gameBoard.GetSquare(x, y), true); gameBoard.RotatePiece(x, y, true); timeSinceLastInput = 0.0f; } } } private void UpdateScoreZooms() { int dequeueCounter = 0; foreach (ScoreZoom zoom in ScoreZooms) { zoom.Update(); if (zoom.IsCompleted) dequeueCounter++; } for (int d = 0; d < dequeueCounter; d++) ScoreZooms.Dequeue(); } private void StartNewLevel() { currentLevel++; floodCount = 0.0f; linesCompletedThisLevel = 0; floodIncreaseAmount += floodAccelerationPerLevel; gameBoard.ClearBoard(); gameBoard.GenerateNewPieces(false); } /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// /// Provides a snapshot of timing values. protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // TODO: Add your update logic here switch (gameState) { case GameStates.TitleScreen: if (Keyboard.GetState().IsKeyDown(Keys.Space)) { gameBoard.ClearBoard(); gameBoard.GenerateNewPieces(false); playerScore = 0; currentLevel = 0; floodIncreaseAmount = 0.0f; StartNewLevel(); gameState = GameStates.Playing; } break; case GameStates.Playing: timeSinceLastInput += (float)gameTime.ElapsedGameTime.TotalSeconds; timeSinceLastFloodIncrease += (float)gameTime.ElapsedGameTime.TotalSeconds; if (timeSinceLastFloodIncrease >= timeBetweenFloodIncreases) { floodCount += floodIncreaseAmount; timeSinceLastFloodIncrease = 0.0f; if (floodCount >= MaxFloodCounter) { gameOverTimer = 8.0f; gameState = GameStates.GameOver; } } if (gameBoard.ArePiecesAnimating()) { gameBoard.UpdateAnimatedPieces(); } else { gameBoard.ResetWater(); for (int y = 0; y < GameBoard.GameBoardHeight; y++) { CheckScoringChain(gameBoard.GetWaterChain(y)); } gameBoard.GenerateNewPieces(true); if (timeSinceLastInput >= MinTimeSinceLastInput) { HandleMouseInput(Mouse.GetState()); } } UpdateScoreZooms(); break; case GameStates.GameOver: gameOverTimer -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (gameOverTimer <= 0) { gameState = GameStates.TitleScreen; } break; } base.Update(gameTime); } private void DrawEmptyPiece(int pixelX, int pixelY) { spriteBatch.Draw( playingPieces, new Rectangle(pixelX, pixelY, GamePiece.PieceWidth, GamePiece.PieceHeight), EmptyPiece, Color.White); } private void DrawStandardPiece(int x, int y, int pixelX, int pixelY) { spriteBatch.Draw( playingPieces, new Rectangle(pixelX, pixelY, GamePiece.PieceWidth, GamePiece.PieceHeight), gameBoard.GetSourceRect(x, y), Color.White); } private void DrawFallingPiece(int pixelX, int pixelY, string positionName) { spriteBatch.Draw( playingPieces, new Rectangle(pixelX, pixelY - gameBoard.fallingPieces[positionName].VerticalOffset, GamePiece.PieceWidth, GamePiece.PieceHeight), gameBoard.fallingPieces[positionName].GetSourceRect(), Color.White); } private void DrawFadingPiece(int pixelX, int pixelY, string positionName) { spriteBatch.Draw( playingPieces, new Rectangle(pixelX, pixelY, GamePiece.PieceWidth, GamePiece.PieceHeight), gameBoard.fadingPieces[positionName].GetSourceRect(), Color.White * gameBoard.fadingPieces[positionName].alphaLevel); } private void DrawRotatingPiece(int pixelX, int pixelY, string positionName) { spriteBatch.Draw( playingPieces, new Rectangle(pixelX + (GamePiece.PieceWidth / 2), pixelY + (GamePiece.PieceHeight / 2), GamePiece.PieceWidth, GamePiece.PieceHeight), gameBoard.rotatingPieces[positionName].GetSourceRect(), Color.White, gameBoard.rotatingPieces[positionName].RotationAmount, new Vector2(GamePiece.PieceWidth / 2, GamePiece.PieceHeight / 2), SpriteEffects.None, 0.0f); } /// /// This is called when the game should draw itself. /// /// Provides a snapshot of timing values. protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here if (gameState == GameStates.TitleScreen) { spriteBatch.Begin(); spriteBatch.Draw(titleScreen, new Rectangle(0, 0, this.Window.ClientBounds.Width, this.Window.ClientBounds.Height), Color.White); spriteBatch.End(); } if ((gameState == GameStates.Playing) || (gameState == GameStates.GameOver)) { spriteBatch.Begin(); spriteBatch.Draw(backgroundScreen, new Rectangle(0, 0, this.Window.ClientBounds.Width, this.Window.ClientBounds.Height), Color.White); for (int x = 0; x < GameBoard.GameBoardWidth; x++) for (int y = 0; y < GameBoard.GameBoardHeight; y++) { int pixelX = (int)gameBoardDisplayOrigin.X + (x * GamePiece.PieceWidth); int pixelY = (int)gameBoardDisplayOrigin.Y + (y * GamePiece.PieceHeight); DrawEmptyPiece(pixelX, pixelY); bool pieceDrawn = false; string positionName = x.ToString() + "_" + y.ToString(); if (gameBoard.rotatingPieces.ContainsKey(positionName)) { DrawRotatingPiece(pixelX, pixelY, positionName); pieceDrawn = true; } if (gameBoard.fadingPieces.ContainsKey(positionName)) { DrawFadingPiece(pixelX, pixelY, positionName); pieceDrawn = true; } if (gameBoard.fallingPieces.ContainsKey(positionName)) { DrawFallingPiece(pixelX, pixelY, positionName); pieceDrawn = true; } if (!pieceDrawn) { DrawStandardPiece(x, y, pixelX, pixelY); } } foreach (ScoreZoom zoom in ScoreZooms) { spriteBatch.DrawString(pericles36Font, zoom.Text, new Vector2(this.Window.ClientBounds.Width / 2, this.Window.ClientBounds.Height / 2), zoom.DrawColor, 0.0f, new Vector2(pericles36Font.MeasureString(zoom.Text).X / 2, pericles36Font.MeasureString(zoom.Text).Y / 2), zoom.Scale, SpriteEffects.None, 0.0f); } spriteBatch.DrawString(pericles36Font, playerScore.ToString(), scorePosition, Color.Black); spriteBatch.DrawString(pericles36Font, currentLevel.ToString(), levelTextPosition, Color.Black); int waterHeight = (int)(MaxWaterHeight * (floodCount / 100)); spriteBatch.Draw(backgroundScreen, new Rectangle( (int)waterPosition.X, (int)waterPosition.Y + (MaxWaterHeight - waterHeight), WaterWidth, waterHeight), new Rectangle( (int)waterOverlayStart.X, (int)waterOverlayStart.Y + (MaxWaterHeight - waterHeight), WaterWidth, waterHeight), new Color(255, 255, 255, 180)); spriteBatch.End(); } if (gameState == GameStates.GameOver) { spriteBatch.Begin(); spriteBatch.DrawString(pericles36Font, "G A M E O V E R!", gameOverLocation, Color.Yellow); spriteBatch.End(); } base.Draw(gameTime); } } }