Browse Source

FloodControl: Update to SDK project and MG 3.8.*

CartBlanche 3 weeks ago
parent
commit
754ffb29e0
31 changed files with 1582 additions and 0 deletions
  1. 50 0
      XNAGameDevelopmentbyExample/FloodControl/.vscode/launch.json
  2. 90 0
      XNAGameDevelopmentbyExample/FloodControl/.vscode/tasks.json
  3. BIN
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/Fonts/Pericles36.xnb
  4. BIN
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/Game.ico
  5. BIN
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/GameThumbnail.png
  6. BIN
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/Textures/Background.xnb
  7. BIN
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/Textures/Tile_Sheet.xnb
  8. BIN
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/Textures/TitleScreen.xnb
  9. 15 0
      XNAGameDevelopmentbyExample/FloodControl/Core/Content/app.manifest
  10. 28 0
      XNAGameDevelopmentbyExample/FloodControl/Core/FadingPiece.cs
  11. 28 0
      XNAGameDevelopmentbyExample/FloodControl/Core/FallingPiece.cs
  12. 15 0
      XNAGameDevelopmentbyExample/FloodControl/Core/FloodControl.Core.csproj
  13. 492 0
      XNAGameDevelopmentbyExample/FloodControl/Core/Game1.cs
  14. 261 0
      XNAGameDevelopmentbyExample/FloodControl/Core/GameBoard.cs
  15. 153 0
      XNAGameDevelopmentbyExample/FloodControl/Core/GamePiece.cs
  16. 43 0
      XNAGameDevelopmentbyExample/FloodControl/Core/RotatingPiece.cs
  17. 44 0
      XNAGameDevelopmentbyExample/FloodControl/Core/ScoreZooms.cs
  18. 102 0
      XNAGameDevelopmentbyExample/FloodControl/FloodControl.sln
  19. 18 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/AndroidManifest.xml
  20. 24 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/FloodControl.Android.csproj
  21. 30 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/MainActivity.cs
  22. 4 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/Resources/values/strings.xml
  23. 5 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/Resources/values/styles.xml
  24. 23 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Desktop/FloodControl.DesktopGL.csproj
  25. 15 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Desktop/Program.cs
  26. 23 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Windows/FloodControl.Windows.csproj
  27. 16 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/Windows/Program.cs
  28. 26 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/iOS/AppDelegate.cs
  29. 23 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/iOS/FloodControl.iOS.csproj
  30. 16 0
      XNAGameDevelopmentbyExample/FloodControl/Platforms/iOS/Info.plist
  31. 38 0
      XNAGameDevelopmentbyExample/FloodControl/README.md

+ 50 - 0
XNAGameDevelopmentbyExample/FloodControl/.vscode/launch.json

@@ -0,0 +1,50 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Run DesktopGL",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-desktopgl",
+            "program": "${workspaceFolder}/bin/Debug/net8.0/FloodControl.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Desktop",
+            "console": "internalConsole",
+            "stopAtEntry": false,
+            "justMyCode": true
+        },
+        {
+            "name": "Run Windows",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-windows",
+            "program": "${workspaceFolder}/bin/Debug/net8.0-windows/FloodControl.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Windows",
+            "console": "internalConsole",
+            "stopAtEntry": false,
+            "justMyCode": true,
+            "requireExactSource": false
+        },
+        {
+            "name": "Debug Android",
+            "type": "mono",
+            "request": "attach",
+            "address": "localhost",
+            "port": 10000,
+			"preLaunchTask": "build-deploy-android"
+        },
+        {
+            "name": "Run iOS (simulator)",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-ios",
+            "program": "${workspaceFolder}/bin/Debug/net8.0-ios/iossimulator-x64/FloodControl.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/iOS",
+            "console": "internalConsole",
+            "stopAtEntry": false,
+            "justMyCode": true
+        }
+    ]
+}

+ 90 - 0
XNAGameDevelopmentbyExample/FloodControl/.vscode/tasks.json

@@ -0,0 +1,90 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "build-desktopgl",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Desktop/FloodControl.DesktopGL.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary;ForceNoAlign"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "build-windows",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Windows/FloodControl.Windows.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary;ForceNoAlign"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "build-deploy-android",
+            "type": "shell",
+            "command": "dotnet build -p:Configuration=Debug ${workspaceFolder}/Platforms/Android/FloodControl.Android.csproj \"/t:Install\" /p:AndroidAttachDebugger=true /p:AndroidSdbHostPort=10000"
+        },
+        {
+            "label": "build-ios",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/iOS/FloodControl.iOS.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary;ForceNoAlign"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "publish",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "publish",
+                "${workspaceFolder}/Platforms/Desktop/FloodControl.DesktopGL.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary;ForceNoAlign"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "watch",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "watch",
+                "run",
+                "--project",
+                "${workspaceFolder}/Platforms/Desktop/FloodControl.DesktopGL.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "always"
+            },
+            "problemMatcher": "$msCompile"
+        }
+    ]
+}

BIN
XNAGameDevelopmentbyExample/FloodControl/Core/Content/Fonts/Pericles36.xnb


BIN
XNAGameDevelopmentbyExample/FloodControl/Core/Content/Game.ico


BIN
XNAGameDevelopmentbyExample/FloodControl/Core/Content/GameThumbnail.png


BIN
XNAGameDevelopmentbyExample/FloodControl/Core/Content/Textures/Background.xnb


BIN
XNAGameDevelopmentbyExample/FloodControl/Core/Content/Textures/Tile_Sheet.xnb


BIN
XNAGameDevelopmentbyExample/FloodControl/Core/Content/Textures/TitleScreen.xnb


+ 15 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/Content/app.manifest

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
+    </windowsSettings>
+  </application>
+</assembly>

+ 28 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/FadingPiece.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    class FadingPiece : GamePiece 
+    {
+        public float alphaLevel = 1.0f;
+        public static float alphaChangeRate = 0.02f;
+
+        public FadingPiece(string pieceType, string suffix)
+            : base(pieceType, suffix)
+        {
+
+        }
+
+        public void UpdatePiece()
+        {
+            alphaLevel = MathHelper.Max(
+                0,
+                alphaLevel - alphaChangeRate);
+        }
+
+    }
+}

+ 28 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/FallingPiece.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    class FallingPiece : GamePiece 
+    {
+        public int VerticalOffset;
+        public static int fallRate = 5;
+
+        public FallingPiece(string pieceType, int verticalOffset)
+            : base(pieceType)
+        {
+            VerticalOffset = verticalOffset;
+        }
+
+        public void UpdatePiece()
+        {
+            VerticalOffset = (int)MathHelper.Max(
+                0,
+                VerticalOffset - fallRate);
+        }
+
+    }
+}

+ 15 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/FloodControl.Core.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <RootNamespace>Flood_Control</RootNamespace>
+    <AssemblyName>FloodControl.Core</AssemblyName>
+    <LangVersion>latest</LangVersion>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+  </ItemGroup>
+
+</Project>

+ 492 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/Game1.cs

@@ -0,0 +1,492 @@
+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.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Media;
+
+namespace Flood_Control
+{
+    /// <summary>
+    /// This is the main type for your game
+    /// </summary>
+    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<ScoreZoom> ScoreZooms = new Queue<ScoreZoom>();
+
+        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";
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        protected override void Initialize()
+        {
+            // TODO: Add your initialization logic here
+#if !___MOBILE___
+            this.IsMouseVisible = true;
+#else
+            this.IsFullScreen = true;
+#endif
+            graphics.PreferredBackBufferWidth = 800;
+            graphics.PreferredBackBufferHeight = 600;
+            graphics.ApplyChanges();
+            gameBoard = new GameBoard();
+            base.Initialize();
+        }
+
+        /// <summary>
+        /// LoadContent will be called once per game and is the place to load
+        /// all of your content.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            // Create a new SpriteBatch, which can be used to draw textures.
+            spriteBatch = new SpriteBatch(GraphicsDevice);
+
+            playingPieces = Content.Load<Texture2D>(@"Textures\Tile_Sheet");
+            backgroundScreen = Content.Load<Texture2D>(@"Textures\Background");
+            titleScreen = Content.Load<Texture2D>(@"Textures\TitleScreen");
+            pericles36Font = Content.Load<SpriteFont>(@"Fonts\Pericles36");
+
+            // TODO: use this.Content to load your game content here
+        }
+
+        /// <summary>
+        /// UnloadContent will be called once per game and is the place to unload
+        /// all content.
+        /// </summary>
+        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<Vector2> 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);
+        }
+
+        /// <summary>
+        /// Allows the game to run logic such as updating the world,
+        /// checking for collisions, gathering input, and playing audio.
+        /// </summary>
+        /// <param name="gameTime">Provides a snapshot of timing values.</param>
+        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);
+        }
+
+        /// <summary>
+        /// This is called when the game should draw itself.
+        /// </summary>
+        /// <param name="gameTime">Provides a snapshot of timing values.</param>
+        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);
+        }
+
+
+    }
+}

+ 261 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/GameBoard.cs

@@ -0,0 +1,261 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    class GameBoard
+    {
+        Random rand = new Random();
+
+        public const int GameBoardWidth = 8;
+        public const int GameBoardHeight = 10;
+
+        private GamePiece[,] boardSquares =
+          new GamePiece[GameBoardWidth, GameBoardHeight];
+
+        private List<Vector2> WaterTracker = new List<Vector2>();
+
+        public Dictionary<string, FallingPiece> fallingPieces =
+            new Dictionary<string, FallingPiece>();
+        public Dictionary<string, RotatingPiece> rotatingPieces =
+            new Dictionary<string, RotatingPiece>();
+        public Dictionary<string, FadingPiece> fadingPieces =
+            new Dictionary<string, FadingPiece>();
+
+        public GameBoard()
+        {
+            ClearBoard();
+        }
+
+        public void ClearBoard()
+        {
+            for (int x = 0; x < GameBoardWidth; x++)
+                for (int y = 0; y < GameBoardHeight; y++)
+                    boardSquares[x, y] = new GamePiece("Empty");
+        }
+
+        public void RotatePiece(int x, int y, bool clockwise)
+        {
+            boardSquares[x, y].RotatePiece(clockwise);
+        }
+
+        public Rectangle GetSourceRect(int x, int y)
+        {
+            return boardSquares[x, y].GetSourceRect();
+        }
+
+        public string GetSquare(int x, int y)
+        {
+            return boardSquares[x, y].PieceType;
+        }
+
+        public void SetSquare(int x, int y, string pieceName)
+        {
+            boardSquares[x, y].SetPiece(pieceName);
+        }
+
+        public bool HasConnector(int x, int y, string direction)
+        {
+            return boardSquares[x, y].HasConnector(direction);
+        }
+
+        public void RandomPiece(int x, int y)
+        {
+            boardSquares[x, y].SetPiece(GamePiece.PieceTypes[rand.Next(0,
+               GamePiece.MaxPlayablePieceIndex + 1)]);
+        }
+
+        public void FillFromAbove(int x, int y)
+        {
+            int rowLookup = y - 1;
+
+            while (rowLookup >= 0)
+            {
+                if (GetSquare(x, rowLookup) != "Empty")
+                {
+                    SetSquare(x, y,
+                      GetSquare(x, rowLookup));
+                    SetSquare(x, rowLookup, "Empty");
+                    AddFallingPiece(x, y, GetSquare(x, y),
+                        GamePiece.PieceHeight * (y - rowLookup));
+                    rowLookup = -1;
+                }
+                rowLookup--;
+            }
+        }
+
+        public void GenerateNewPieces(bool dropSquares)
+        {
+
+            if (dropSquares)
+            {
+                for (int x = 0; x < GameBoard.GameBoardWidth; x++)
+                {
+                    for (int y = GameBoard.GameBoardHeight - 1; y >= 0; y--)
+                    {
+                        if (GetSquare(x, y) == "Empty")
+                        {
+                            FillFromAbove(x, y);
+                        }
+                    }
+                }
+            }
+
+            for (int y = 0; y < GameBoard.GameBoardHeight; y++)
+                for (int x = 0; x < GameBoard.GameBoardWidth; x++)
+                {
+                    if (GetSquare(x, y) == "Empty")
+                    {
+                        RandomPiece(x, y);
+                        AddFallingPiece(x, y, GetSquare(x, y),
+                            GamePiece.PieceHeight * GameBoardHeight);
+
+                    }
+                }
+        }
+
+        public void ResetWater()
+        {
+            for (int y = 0; y < GameBoardHeight; y++)
+                for (int x = 0; x < GameBoardWidth; x++)
+                    boardSquares[x, y].RemoveSuffix("W");
+        }
+
+        public void FillPiece(int X, int Y)
+        {
+            boardSquares[X, Y].AddSuffix("W");
+        }
+
+        public void PropagateWater(int x, int y, string fromDirection)
+        {
+            if ((y >= 0) && (y < GameBoardHeight) &&
+                (x >= 0) && (x < GameBoardWidth))
+            {
+                if (boardSquares[x, y].HasConnector(fromDirection) &&
+                    !boardSquares[x, y].Suffix.Contains("W"))
+                {
+                    FillPiece(x, y);
+                    WaterTracker.Add(new Vector2(x, y));
+                    foreach (string end in
+                             boardSquares[x, y].GetOtherEnds(fromDirection))
+                        switch (end)
+                        {
+                            case "Left": PropagateWater(x - 1, y, "Right");
+                                break;
+                            case "Right": PropagateWater(x + 1, y, "Left");
+                                break;
+                            case "Top": PropagateWater(x, y - 1, "Bottom");
+                                break;
+                            case "Bottom": PropagateWater(x, y + 1, "Top");
+                                break;
+                        }
+                }
+            }
+        }
+
+        public List<Vector2> GetWaterChain(int y)
+        {
+            WaterTracker.Clear();
+            PropagateWater(0, y, "Left");
+            return WaterTracker;
+        }
+
+        public void AddFallingPiece(int X, int Y,
+            string PieceName, int VerticalOffset)
+        {
+            fallingPieces[X.ToString() + "_" + Y.ToString()] = new
+                FallingPiece(PieceName, VerticalOffset);
+        }
+
+        public void AddRotatingPiece(int X, int Y,
+            string PieceName, bool Clockwise)
+        {
+            rotatingPieces[X.ToString() + "_" + Y.ToString()] = new
+                RotatingPiece(PieceName, Clockwise);
+        }
+
+        public void AddFadingPiece(int X, int Y, string PieceName)
+        {
+            fadingPieces[X.ToString() + "_" + Y.ToString()] = new
+                FadingPiece(PieceName, "W");
+        }
+
+        public bool ArePiecesAnimating()
+        {
+            if ((fallingPieces.Count == 0) &&
+                (rotatingPieces.Count == 0) &&
+                (fadingPieces.Count == 0))
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        private void UpdateFadingPieces()
+        {
+            Queue<string> RemoveKeys = new Queue<string>();
+
+            foreach (string thisKey in fadingPieces.Keys)
+            {
+                fadingPieces[thisKey].UpdatePiece();
+
+                if (fadingPieces[thisKey].alphaLevel == 0.0f)
+                    RemoveKeys.Enqueue(thisKey.ToString());
+            }
+
+            while (RemoveKeys.Count > 0)
+                fadingPieces.Remove(RemoveKeys.Dequeue());
+        }
+
+        private void UpdateFallingPieces()
+        {
+            Queue<string> RemoveKeys = new Queue<string>();
+
+            foreach (string thisKey in fallingPieces.Keys)
+            {
+                fallingPieces[thisKey].UpdatePiece();
+
+                if (fallingPieces[thisKey].VerticalOffset == 0)
+                    RemoveKeys.Enqueue(thisKey.ToString());
+            }
+
+            while (RemoveKeys.Count > 0)
+                fallingPieces.Remove(RemoveKeys.Dequeue());
+        }
+
+        private void UpdateRotatingPieces()
+        {
+            Queue<string> RemoveKeys = new Queue<string>();
+
+            foreach (string thisKey in rotatingPieces.Keys)
+            {
+                rotatingPieces[thisKey].UpdatePiece();
+
+                if (rotatingPieces[thisKey].rotationTicksRemaining == 0)
+                    RemoveKeys.Enqueue(thisKey.ToString());
+            }
+
+            while (RemoveKeys.Count > 0)
+                rotatingPieces.Remove(RemoveKeys.Dequeue());
+        }
+
+        public void UpdateAnimatedPieces()
+        {
+            if (fadingPieces.Count == 0)
+            {
+                UpdateFallingPieces();
+                UpdateRotatingPieces();
+            }
+            else
+            {
+                UpdateFadingPieces();
+            }
+        }
+    }
+}

+ 153 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/GamePiece.cs

@@ -0,0 +1,153 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    class GamePiece
+    {
+        public static string[] PieceTypes = 
+        { 
+            "Left,Right", 
+            "Top,Bottom", 
+            "Left,Top", 
+            "Top,Right",
+            "Right,Bottom", 
+            "Bottom,Left",
+            "Empty"
+         };
+
+        public const int PieceHeight = 40;
+        public const int PieceWidth = 40;
+
+        public const int MaxPlayablePieceIndex = 5;
+        public const int EmptyPieceIndex = 6;
+
+        private const int textureOffsetX = 1;
+        private const int textureOffsetY = 1;
+        private const int texturePaddingX = 1;
+        private const int texturePaddingY = 1;
+
+        private string pieceType = "";
+        private string pieceSuffix = "";
+
+        public string PieceType
+        {
+            get { return pieceType; }
+        }
+
+        public string Suffix
+        {
+            get { return pieceSuffix; }
+        }
+
+        public GamePiece(string type, string suffix)
+        {
+            pieceType = type;
+            pieceSuffix = suffix;
+        }
+
+        public GamePiece(string type)
+        {
+            pieceType = type;
+            pieceSuffix = "";
+        }
+
+        public void SetPiece(string type, string suffix)
+        {
+            pieceType = type;
+            pieceSuffix = suffix;
+        }
+
+        public void SetPiece(string type)
+        {
+            SetPiece(type, "");
+        }
+
+        public void AddSuffix(string suffix)
+        {
+            if (!pieceSuffix.Contains(suffix))
+                pieceSuffix += suffix;
+        }
+
+        public void RemoveSuffix(string suffix)
+        {
+            pieceSuffix = pieceSuffix.Replace(suffix, "");
+        }
+
+        public void RotatePiece(bool Clockwise)
+        {
+            switch (pieceType)
+            {
+                case "Left,Right":
+                    pieceType = "Top,Bottom";
+                    break;
+                case "Top,Bottom":
+                    pieceType = "Left,Right";
+                    break;
+                case "Left,Top":
+                    if (Clockwise)
+                        pieceType = "Top,Right";
+                    else
+                        pieceType = "Bottom,Left";
+                    break;
+                case "Top,Right":
+                    if (Clockwise)
+                        pieceType = "Right,Bottom";
+                    else
+                        pieceType = "Left,Top";
+                    break;
+                case "Right,Bottom":
+                    if (Clockwise)
+                        pieceType = "Bottom,Left";
+                    else
+                        pieceType = "Top,Right";
+                    break;
+                case "Bottom,Left":
+                    if (Clockwise)
+                        pieceType = "Left,Top";
+                    else
+                        pieceType = "Right,Bottom";
+                    break;
+                case "Empty":
+                    break;
+            }
+        }
+
+        public string[] GetOtherEnds(string startingEnd)
+        {
+            List<string> opposites = new List<string>();
+
+            foreach (string end in pieceType.Split(','))
+            {
+                if (end != startingEnd)
+                    opposites.Add(end);
+            }
+            return opposites.ToArray();
+        }
+
+        public bool HasConnector(string direction)
+        {
+            return pieceType.Contains(direction);
+        }
+
+        public Rectangle GetSourceRect()
+        {
+            int x = textureOffsetX;
+            int y = textureOffsetY;
+
+            if (pieceSuffix.Contains("W"))
+                x += PieceWidth + texturePaddingX;
+
+            y += (Array.IndexOf(PieceTypes, pieceType) *
+                 (PieceHeight + texturePaddingY));
+
+
+            return new Rectangle(x, y, PieceWidth, PieceHeight);
+        }
+
+    }
+}

+ 43 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/RotatingPiece.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    class RotatingPiece : GamePiece
+    {
+        public bool clockwise;
+
+        public static float rotationRate = (MathHelper.PiOver2 / 10);
+        private float rotationAmount = 0;
+        public int rotationTicksRemaining = 10;
+
+        public float RotationAmount
+        {
+            get
+            {
+                if (clockwise)
+                    return rotationAmount;
+                else
+                    return (MathHelper.Pi * 2) - rotationAmount;
+            }
+        }
+
+        public RotatingPiece(string pieceType, bool clockwise)
+            : base(pieceType)
+        {
+            this.clockwise = clockwise;
+        }
+
+        public void UpdatePiece()
+        {
+            rotationAmount += rotationRate;
+            rotationTicksRemaining = (int)MathHelper.Max(
+                0,
+                rotationTicksRemaining - 1);
+        }
+
+    }
+}

+ 44 - 0
XNAGameDevelopmentbyExample/FloodControl/Core/ScoreZooms.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    class ScoreZoom
+    {
+        public string Text;
+        public Color DrawColor;
+        public int displayCounter;
+        public int MaxDisplayCount = 30;
+        private float scale = 0.4f;
+        private float lastScaleAmount = 0.0f;
+        private float scaleAmount = 0.4f;
+
+        public float Scale
+        {
+            get { return scaleAmount * displayCounter; }
+        }
+
+        public bool IsCompleted
+        {
+            get { return (displayCounter > MaxDisplayCount); }
+        }
+
+        public ScoreZoom(string displayText, Color fontColor)
+        {
+            Text = displayText;
+            DrawColor = fontColor;
+            displayCounter = 0;
+        }
+
+        public void Update()
+        {
+            scale += lastScaleAmount + scaleAmount;
+            lastScaleAmount += scaleAmount;
+            displayCounter++;
+        }
+    }
+}

+ 102 - 0
XNAGameDevelopmentbyExample/FloodControl/FloodControl.sln

@@ -0,0 +1,102 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FloodControl.Core", "Core\FloodControl.Core.csproj", "{11111111-1111-1111-1111-111111111111}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FloodControl.Windows", "Platforms\Windows\FloodControl.Windows.csproj", "{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FloodControl.DesktopGL", "Platforms\Desktop\FloodControl.DesktopGL.csproj", "{96867CF2-321E-481B-83C2-D3AFBB377150}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FloodControl.Android", "Platforms\Android\FloodControl.Android.csproj", "{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FloodControl.iOS", "Platforms\iOS\FloodControl.iOS.csproj", "{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Debug|x64.Build.0 = Debug|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Debug|x86.Build.0 = Debug|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Release|x64.ActiveCfg = Release|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Release|x64.Build.0 = Release|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Release|x86.ActiveCfg = Release|Any CPU
+		{87BB531C-2DB3-4A2F-ABE5-4966AE21ABE3}.Release|x86.Build.0 = Release|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Debug|x64.Build.0 = Debug|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Debug|x86.Build.0 = Debug|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Release|Any CPU.Build.0 = Release|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Release|x64.ActiveCfg = Release|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Release|x64.Build.0 = Release|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Release|x86.ActiveCfg = Release|Any CPU
+		{96867CF2-321E-481B-83C2-D3AFBB377150}.Release|x86.Build.0 = Release|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Debug|x64.Build.0 = Debug|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Debug|x86.Build.0 = Debug|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Release|x64.ActiveCfg = Release|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Release|x64.Build.0 = Release|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Release|x86.ActiveCfg = Release|Any CPU
+		{4479A4F7-13A2-48D9-9F92-7A8784C245CE}.Release|x86.Build.0 = Release|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Debug|x64.Build.0 = Debug|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Debug|x86.Build.0 = Debug|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Release|x64.ActiveCfg = Release|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Release|x64.Build.0 = Release|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Release|x86.ActiveCfg = Release|Any CPU
+		{CEA416F2-5043-4994-9127-8E011F12DEB0}.Release|x86.Build.0 = Release|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Debug|x64.Build.0 = Debug|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Debug|x86.Build.0 = Debug|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Release|x64.ActiveCfg = Release|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Release|x64.Build.0 = Release|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Release|x86.ActiveCfg = Release|Any CPU
+		{D5DAEA98-64D1-4BC9-B29B-5514530D80F3}.Release|x86.Build.0 = Release|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Debug|x64.Build.0 = Debug|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Debug|x86.Build.0 = Debug|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Release|x64.ActiveCfg = Release|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Release|x64.Build.0 = Release|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Release|x86.ActiveCfg = Release|Any CPU
+		{2E01FB05-52F1-4E3C-AA3E-D9827F82D560}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 18 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/AndroidManifest.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.asteroidbeltassault">
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="34" />
+    
+    <application android:allowBackup="true" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
+        <activity android:name="microsoft.xna.framework.AndroidGameActivity" 
+                  android:label="@string/app_name" 
+                  android:launchMode="singleInstance" 
+                  android:screenOrientation="sensorLandscape" 
+                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>

+ 24 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/FloodControl.Android.csproj

@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-android</TargetFramework>
+    <AssemblyName>FloodControl</AssemblyName>
+    <RootNamespace>Flood_Control</RootNamespace>
+    <Nullable>disable</Nullable>
+    <ApplicationId>com.floodcontrol.game</ApplicationId>
+    <ApplicationVersion>1</ApplicationVersion>
+    <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
+    <SupportedOSPlatformVersion>28.0</SupportedOSPlatformVersion>
+    <AndroidManifest>AndroidManifest.xml</AndroidManifest>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.Android" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+    <ProjectReference Include="..\..\Core\FloodControl.Core.csproj" />
+  </ItemGroup>
+  
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" CopyToOutputDirectory="PreserveNewest" />
+  </ItemGroup>
+</Project>

+ 30 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/MainActivity.cs

@@ -0,0 +1,30 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    [Activity(
+        Label = "@string/app_name",
+        MainLauncher = true,
+        AlwaysRetainTaskState = true,
+        LaunchMode = LaunchMode.SingleInstance,
+        ScreenOrientation = ScreenOrientation.SensorLandscape,
+        ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
+    )]
+
+    public class MainActivity : AndroidGameActivity
+    {
+        private Game1 _game;
+
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+
+            _game = new Game1();
+            SetContentView((View)_game.Services.GetService(typeof(View)));
+            _game.Run();
+        }
+    }
+}

+ 4 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/Resources/values/strings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Flood Control</string>
+</resources>

+ 5 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Android/Resources/values/styles.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="AppTheme" parent="@android:style/Theme.Holo.Light">
+    </style>
+</resources>

+ 23 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Desktop/FloodControl.DesktopGL.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <AssemblyName>FloodControl</AssemblyName>
+    <RootNamespace>Flood_Control</RootNamespace>
+    <UseWindowsForms>false</UseWindowsForms>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+    <ApplicationIcon>..\..\Core\Content\Game.ico</ApplicationIcon>
+    <ApplicationManifest>..\..\Core\Content\app.manifest</ApplicationManifest>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+    <ProjectReference Include="..\..\Core\FloodControl.Core.csproj" />
+  </ItemGroup>
+  
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" CopyToOutputDirectory="PreserveNewest" />
+  </ItemGroup>
+</Project>

+ 15 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Desktop/Program.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace Flood_Control
+{
+    static class Program
+    {
+        static void Main(string[] args)
+        {
+            using (var game = new Game1())
+            {
+                game.Run();
+            }
+        }
+    }
+}

+ 23 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Windows/FloodControl.Windows.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>net8.0-windows</TargetFramework>
+    <AssemblyName>FloodControl</AssemblyName>
+    <RootNamespace>Flood_Control</RootNamespace>
+    <UseWindowsForms>false</UseWindowsForms>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+    <ApplicationManifest>..\..\Core\Content\app.manifest</ApplicationManifest>
+    <ApplicationIcon>..\..\Core\Content\Game.ico</ApplicationIcon>
+  </PropertyGroup>  
+  
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+    <ProjectReference Include="..\..\Core\FloodControl.Core.csproj" />
+  </ItemGroup>
+  
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" CopyToOutputDirectory="PreserveNewest" />
+  </ItemGroup>
+</Project>

+ 16 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/Windows/Program.cs

@@ -0,0 +1,16 @@
+using System;
+
+namespace Flood_Control
+{
+    static class Program
+    {
+        [STAThread]
+        static void Main(string[] args)
+        {
+            using (var game = new Game1())
+            {
+                game.Run();
+            }
+        }
+    }
+}

+ 26 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/iOS/AppDelegate.cs

@@ -0,0 +1,26 @@
+using Foundation;
+using UIKit;
+using Microsoft.Xna.Framework;
+
+namespace Flood_Control
+{
+    [Register("AppDelegate")]
+    public class AppDelegate : UIApplicationDelegate
+    {
+        Game1 game;
+        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
+        {
+            game = new Game1();
+            game.Run();
+            return true;
+        }
+    }
+
+    public class Application
+    {
+        static void Main(string[] args)
+        {
+            UIApplication.Main(args, null, "AppDelegate");
+        }
+    }
+}

+ 23 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/iOS/FloodControl.iOS.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-ios</TargetFramework>
+    <AssemblyName>FloodControl</AssemblyName>
+    <RootNamespace>Flood_Control</RootNamespace>
+    <Nullable>disable</Nullable>
+    <ApplicationId>com.floodcontrol.game</ApplicationId>
+    <ApplicationVersion>1</ApplicationVersion>
+    <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
+    <SupportedOSPlatformVersion>11.0</SupportedOSPlatformVersion>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.iOS" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+    <ProjectReference Include="..\..\Core\FloodControl.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" CopyToOutputDirectory="PreserveNewest" />
+  </ItemGroup>
+</Project>

+ 16 - 0
XNAGameDevelopmentbyExample/FloodControl/Platforms/iOS/Info.plist

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleIdentifier</key>
+	<string>com.floodcontrol.game</string>
+	<key>CFBundleName</key>
+	<string>FloodControl</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>MinimumOSVersion</key>
+	<string>11.0</string>
+</dict>
+</plist>

+ 38 - 0
XNAGameDevelopmentbyExample/FloodControl/README.md

@@ -0,0 +1,38 @@
+Flood Control
+=============
+
+
+This project contains the Flood Control game, modernized for MonoGame 3.8.* and .NET 8, with a clean cross-platform structure.
+
+## Directory Structure
+
+- `Core/` — Shared game logic and code
+- `Platforms/Windows/` — Windows-specific project and entry point
+- `Platforms/Desktop/` — DesktopGL (cross-platform desktop) project and entry point
+- `Platforms/Android/` — Android project and entry point
+- `Platforms/iOS/` — iOS project and entry point
+- `Content/` — Pre-built .xnb content files used directly by all platforms
+
+## Building and Running
+
+### Prerequisites
+- .NET 8 SDK
+- MonoGame 3.8.* (NuGet packages are referenced automatically)
+- Visual Studio 2022+ or VSCode (with C# Dev Kit recommended)
+
+### With Visual Studio
+Open `FloodControl.sln` and build/run the desired platform project (Windows, DesktopGL, Android, or iOS).
+
+### With VSCode
+Use the built-in tasks and launch configurations:
+- Press `Ctrl+Shift+B` to build (choose the platform-specific build task)
+- Press `F5` to run (choose the platform-specific launch config: Windows, DesktopGL, Android, or iOS)
+
+### Notes
+- No Content.mgcb file is used; the game loads .xnb files directly from the Content folder.
+- Platform-specific code is separated into platform folders; shared logic is in Core.
+- Android and iOS require appropriate emulators or devices and platform SDKs.
+
+---
+This project was originally from the book XNA 4.0 Game Development by Example: Beginner's Guide by Kurt Jaegers (PACKT Publishing).
+See: http://www.packtpub.com/xna-4-0-game-development-by-example-beginners-guide/book