Pārlūkot izejas kodu

GameStateManagement Updated to SDK and 3.8.*

CartBlanche 1 nedēļu atpakaļ
vecāks
revīzija
c5d798bab3
70 mainītis faili ar 3713 papildinājumiem un 2895 dzēšanām
  1. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/CodeChunks.db
  2. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/SemanticSymbols.db
  3. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/SemanticSymbols.db-shm
  4. 0 0
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/SemanticSymbols.db-wal
  5. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/CodeChunks.db
  6. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/SemanticSymbols.db
  7. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/SemanticSymbols.db-shm
  8. BIN
      GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/SemanticSymbols.db-wal
  9. BIN
      GameStateManagement/.vs/GameStateManagement/DesignTimeBuild/.dtbcache.v2
  10. BIN
      GameStateManagement/.vs/GameStateManagement/FileContentIndex/18504972-7bdd-454a-bbc8-44232f5a06c9.vsidx
  11. BIN
      GameStateManagement/.vs/GameStateManagement/FileContentIndex/8c6340b5-3aad-4561-8930-c1695cf1028a.vsidx
  12. BIN
      GameStateManagement/.vs/GameStateManagement/FileContentIndex/9e49555d-1f7c-4add-bfb1-838b095b82ee.vsidx
  13. BIN
      GameStateManagement/.vs/GameStateManagement/FileContentIndex/aca62daf-87b1-4c63-a814-466c07c130ec.vsidx
  14. BIN
      GameStateManagement/.vs/GameStateManagement/FileContentIndex/d4624077-1199-44bb-bb1c-af282b8aea10.vsidx
  15. BIN
      GameStateManagement/.vs/GameStateManagement/v17/.futdcache.v2
  16. 393 0
      GameStateManagement/.vs/GameStateManagement/v17/DocumentLayout.backup.json
  17. 381 0
      GameStateManagement/.vs/GameStateManagement/v17/DocumentLayout.json
  18. BIN
      GameStateManagement/.vs/ProjectEvaluation/gamestatemanagement.metadata.v9.bin
  19. BIN
      GameStateManagement/.vs/ProjectEvaluation/gamestatemanagement.projects.v9.bin
  20. BIN
      GameStateManagement/.vs/ProjectEvaluation/gamestatemanagement.strings.v9.bin
  21. 28 0
      GameStateManagement/.vscode/launch.json
  22. 169 0
      GameStateManagement/.vscode/tasks.json
  23. BIN
      GameStateManagement/Background.png
  24. BIN
      GameStateManagement/Content/background.xnb
  25. BIN
      GameStateManagement/Content/blank.xnb
  26. BIN
      GameStateManagement/Content/gamefont.xnb
  27. BIN
      GameStateManagement/Content/gradient.xnb
  28. BIN
      GameStateManagement/Content/menufont.xnb
  29. 0 0
      GameStateManagement/Core/Content/Default.png
  30. 0 0
      GameStateManagement/Core/Content/Game.ico
  31. 0 0
      GameStateManagement/Core/Content/GameThumbnail.png
  32. 0 0
      GameStateManagement/Core/Content/background.png
  33. 0 0
      GameStateManagement/Core/Content/blank.png
  34. 14 14
      GameStateManagement/Core/Content/gamefont.spritefont
  35. 0 0
      GameStateManagement/Core/Content/gradient.png
  36. 14 14
      GameStateManagement/Core/Content/menufont.spritefont
  37. 77 87
      GameStateManagement/Core/Game.cs
  38. 22 0
      GameStateManagement/Core/GameStateManagement.Core.csproj
  39. 226 0
      GameStateManagement/Core/Inputs/InputState.cs
  40. 315 315
      GameStateManagement/Core/ScreenManager/ScreenManager.cs
  41. 100 110
      GameStateManagement/Core/Screens/BackgroundScreen.cs
  42. 343 0
      GameStateManagement/Core/Screens/GameScreen.cs
  43. 207 217
      GameStateManagement/Core/Screens/GameplayScreen.cs
  44. 152 162
      GameStateManagement/Core/Screens/LoadingScreen.cs
  45. 90 98
      GameStateManagement/Core/Screens/MainMenuScreen.cs
  46. 177 191
      GameStateManagement/Core/Screens/MenuEntry.cs
  47. 230 244
      GameStateManagement/Core/Screens/MenuScreen.cs
  48. 156 170
      GameStateManagement/Core/Screens/MessageBoxScreen.cs
  49. 139 149
      GameStateManagement/Core/Screens/OptionsMenuScreen.cs
  50. 71 79
      GameStateManagement/Core/Screens/PauseMenuScreen.cs
  51. 38 42
      GameStateManagement/Core/Screens/PlayerIndexEventArgs.cs
  52. 0 104
      GameStateManagement/GameStateManagement.MacOS.csproj
  53. 0 141
      GameStateManagement/GameStateManagement.iOS.csproj
  54. 37 17
      GameStateManagement/GameStateManagement.sln
  55. 15 0
      GameStateManagement/Platforms/Android/AndroidManifest.xml
  56. 48 0
      GameStateManagement/Platforms/Android/GameStateManagement.Android.csproj
  57. 19 0
      GameStateManagement/Platforms/Android/MainActivity.cs
  58. 48 0
      GameStateManagement/Platforms/Desktop/GameStateManagement.DesktopGL.csproj
  59. 14 0
      GameStateManagement/Platforms/Desktop/Program.cs
  60. 50 0
      GameStateManagement/Platforms/Windows/GameStateManagement.Windows.csproj
  61. 14 0
      GameStateManagement/Platforms/Windows/Program.cs
  62. 19 0
      GameStateManagement/Platforms/iOS/AppDelegate.cs
  63. 48 0
      GameStateManagement/Platforms/iOS/GameStateManagement.iOS.csproj
  64. 0 0
      GameStateManagement/Platforms/iOS/Info.plist
  65. 13 0
      GameStateManagement/Platforms/iOS/Program.cs
  66. 0 115
      GameStateManagement/Program.cs
  67. 0 33
      GameStateManagement/Properties/AssemblyInfo.cs
  68. 46 0
      GameStateManagement/README.md
  69. 0 356
      GameStateManagement/ScreenManager/GameScreen.cs
  70. 0 237
      GameStateManagement/ScreenManager/InputState.cs

BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/CodeChunks.db


BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/SemanticSymbols.db


BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/SemanticSymbols.db-shm


+ 0 - 0
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1648.49400/SemanticSymbols.db-wal


BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/CodeChunks.db


BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/SemanticSymbols.db


BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/SemanticSymbols.db-shm


BIN
GameStateManagement/.vs/GameStateManagement/CopilotIndices/0.2.1653.9816/SemanticSymbols.db-wal


BIN
GameStateManagement/.vs/GameStateManagement/DesignTimeBuild/.dtbcache.v2


BIN
GameStateManagement/.vs/GameStateManagement/FileContentIndex/18504972-7bdd-454a-bbc8-44232f5a06c9.vsidx


BIN
GameStateManagement/.vs/GameStateManagement/FileContentIndex/8c6340b5-3aad-4561-8930-c1695cf1028a.vsidx


BIN
GameStateManagement/.vs/GameStateManagement/FileContentIndex/9e49555d-1f7c-4add-bfb1-838b095b82ee.vsidx


BIN
GameStateManagement/.vs/GameStateManagement/FileContentIndex/aca62daf-87b1-4c63-a814-466c07c130ec.vsidx


BIN
GameStateManagement/.vs/GameStateManagement/FileContentIndex/d4624077-1199-44bb-bb1c-af282b8aea10.vsidx


BIN
GameStateManagement/.vs/GameStateManagement/v17/.futdcache.v2


+ 393 - 0
GameStateManagement/.vs/GameStateManagement/v17/DocumentLayout.backup.json

@@ -0,0 +1,393 @@
+{
+  "Version": 1,
+  "WorkspaceRootPath": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\",
+  "Documents": [
+    {
+      "AbsoluteMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.windowsdx\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|solutionrelative:gamestatemanagement.windowsdx\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.windowsdx\\gamestatemanagement.windowsdx.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|solutionrelative:gamestatemanagement.windowsdx\\gamestatemanagement.windowsdx.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.windowsdx\\app.manifest||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
+      "RelativeMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|solutionrelative:gamestatemanagement.windowsdx\\app.manifest||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.desktopgl\\gamestatemanagement.desktopgl.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|solutionrelative:gamestatemanagement.desktopgl\\gamestatemanagement.desktopgl.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screenmanager\\inputstate.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screenmanager\\inputstate.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\content\\fonts\\gamefont.spritefont||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\content\\fonts\\gamefont.spritefont||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\gameplayscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\gameplayscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screenmanager\\screenmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screenmanager\\screenmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\messageboxscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\messageboxscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\backgroundscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\backgroundscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\content\\gamestatemanagement.mgcb||{8B382828-6202-11D1-8870-0000F87579D2}",
+      "RelativeMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|solutionrelative:gamestatemanagement.core\\content\\gamestatemanagement.mgcb||{8B382828-6202-11D1-8870-0000F87579D2}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.android\\resources\\values\\strings.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|solutionrelative:gamestatemanagement.android\\resources\\values\\strings.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.android\\mainactivity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|solutionrelative:gamestatemanagement.android\\mainactivity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.android\\androidmanifest.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|solutionrelative:gamestatemanagement.android\\androidmanifest.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\playerindexeventargs.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\playerindexeventargs.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\pausemenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\pausemenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\optionsmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\optionsmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\menuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\menuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\menuentry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\menuentry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\mainmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\mainmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\loadingscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\loadingscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screenmanager\\gamescreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screenmanager\\gamescreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.desktopgl\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|solutionrelative:gamestatemanagement.desktopgl\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    }
+  ],
+  "DocumentGroupContainers": [
+    {
+      "Orientation": 0,
+      "VerticalTabListWidth": 256,
+      "DocumentGroups": [
+        {
+          "DockedWidth": 200,
+          "SelectedChildIndex": 1,
+          "Children": [
+            {
+              "$type": "Bookmark",
+              "Name": "ST:0:0:{e506b91c-c606-466a-90a9-123d1d1e12b3}"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 0,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\Program.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.WindowsDX\\Program.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\Program.cs",
+              "RelativeToolTip": "GameStateManagement.WindowsDX\\Program.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAABSAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-19T02:42:34.024Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 2,
+              "Title": "app.manifest",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\app.manifest",
+              "RelativeDocumentMoniker": "GameStateManagement.WindowsDX\\app.manifest",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\app.manifest",
+              "RelativeToolTip": "GameStateManagement.WindowsDX\\app.manifest",
+              "ViewState": "AgIAABsAAAAAAAAAAAAnwCMAAAA4AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001203|",
+              "WhenOpened": "2024-09-19T02:39:12.883Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 1,
+              "Title": "GameStateManagement.WindowsDX.csproj",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "RelativeDocumentMoniker": "GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "RelativeToolTip": "GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAARAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
+              "WhenOpened": "2024-09-19T02:18:14.882Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 3,
+              "Title": "GameStateManagement.DesktopGL.csproj",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "RelativeDocumentMoniker": "GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "RelativeToolTip": "GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "ViewState": "AgIAABUAAAAAAAAAAAAAACQAAAAKAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
+              "WhenOpened": "2024-09-18T15:47:41.697Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 4,
+              "Title": "InputState.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\InputState.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\ScreenManager\\InputState.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\InputState.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\ScreenManager\\InputState.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAE0AAAA7AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:49:42.61Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 6,
+              "Title": "GameplayScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAD4AAAA+AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:50:04.357Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 8,
+              "Title": "MessageBoxScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "ViewState": "AgIAAEkAAAAAAAAAAAD4v1EAAAA7AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:13.818Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 7,
+              "Title": "ScreenManager.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "ViewState": "AgIAAG8AAAAAAAAAAAD4v3YAAAAnAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:49:47.375Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 5,
+              "Title": "gamefont.spritefont",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "RelativeToolTip": "GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAMAAAARAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-09-19T01:16:39.44Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 9,
+              "Title": "BackgroundScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "ViewState": "AgIAAC8AAAAAAAAAAAAAADkAAAAzAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:49:57.495Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 10,
+              "Title": "GameStateManagement.mgcb",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "RelativeToolTip": "GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAdAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-09-18T15:56:23.624Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 11,
+              "Title": "Strings.xml",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "RelativeDocumentMoniker": "GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "RelativeToolTip": "GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAIAAAAtAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003576|",
+              "WhenOpened": "2024-09-18T15:54:37.411Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 12,
+              "Title": "MainActivity.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\MainActivity.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Android\\MainActivity.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\MainActivity.cs",
+              "RelativeToolTip": "GameStateManagement.Android\\MainActivity.cs",
+              "ViewState": "AgIAAB8AAAAAAAAAAAD4vycAAAAnAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:53:42.25Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 13,
+              "Title": "AndroidManifest.xml",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\AndroidManifest.xml",
+              "RelativeDocumentMoniker": "GameStateManagement.Android\\AndroidManifest.xml",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\AndroidManifest.xml",
+              "RelativeToolTip": "GameStateManagement.Android\\AndroidManifest.xml",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAAAwAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003576|",
+              "WhenOpened": "2024-09-18T15:53:21.733Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 14,
+              "Title": "PlayerIndexEventArgs.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA4AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:28.556Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 15,
+              "Title": "PauseMenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:23.915Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 16,
+              "Title": "OptionsMenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:19.079Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 17,
+              "Title": "MenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:07.412Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 18,
+              "Title": "MenuEntry.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:03.392Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 19,
+              "Title": "MainMenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:50:55.244Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 20,
+              "Title": "LoadingScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:50:49.596Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 21,
+              "Title": "GameScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\GameScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\ScreenManager\\GameScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\GameScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\ScreenManager\\GameScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAiAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:49:17.851Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 22,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\Program.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.DesktopGL\\Program.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\Program.cs",
+              "RelativeToolTip": "GameStateManagement.DesktopGL\\Program.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAMAAAAoAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:48:18.94Z"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 381 - 0
GameStateManagement/.vs/GameStateManagement/v17/DocumentLayout.json

@@ -0,0 +1,381 @@
+{
+  "Version": 1,
+  "WorkspaceRootPath": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\",
+  "Documents": [
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\gamestatemanagementgame.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\gamestatemanagementgame.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\mainmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\mainmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screenmanager\\screenmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screenmanager\\screenmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\backgroundscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\backgroundscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.windowsdx\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|solutionrelative:gamestatemanagement.windowsdx\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.windowsdx\\gamestatemanagement.windowsdx.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|solutionrelative:gamestatemanagement.windowsdx\\gamestatemanagement.windowsdx.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.windowsdx\\app.manifest||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
+      "RelativeMoniker": "D:0:0:{DC9D9B21-AD23-48E5-A248-4EBE90FEABF8}|GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj|solutionrelative:gamestatemanagement.windowsdx\\app.manifest||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.desktopgl\\gamestatemanagement.desktopgl.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|solutionrelative:gamestatemanagement.desktopgl\\gamestatemanagement.desktopgl.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\content\\fonts\\gamefont.spritefont||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\content\\fonts\\gamefont.spritefont||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\gameplayscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\gameplayscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\messageboxscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\messageboxscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\content\\gamestatemanagement.mgcb||{8B382828-6202-11D1-8870-0000F87579D2}",
+      "RelativeMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|solutionrelative:gamestatemanagement.core\\content\\gamestatemanagement.mgcb||{8B382828-6202-11D1-8870-0000F87579D2}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.android\\resources\\values\\strings.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|solutionrelative:gamestatemanagement.android\\resources\\values\\strings.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.android\\mainactivity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|solutionrelative:gamestatemanagement.android\\mainactivity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.android\\androidmanifest.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|",
+      "RelativeMoniker": "D:0:0:{A4F8DC31-360E-4AFA-A474-6D01EEBC0D19}|GameStateManagement.Android\\GameStateManagement.Android.csproj|solutionrelative:gamestatemanagement.android\\androidmanifest.xml||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\playerindexeventargs.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\playerindexeventargs.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\pausemenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\pausemenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\optionsmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\optionsmenuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\menuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\menuscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\menuentry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\menuentry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.core\\screens\\loadingscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{3AFC4E10-5EE4-473A-A7E2-8BF5415FD71F}|GameStateManagement.Core\\GameStateManagement.Core.csproj|solutionrelative:gamestatemanagement.core\\screens\\loadingscreen.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|c:\\users\\savag\\source\\repos\\cartblanche\\monogame\\monogame-samples\\gamestatemanagement\\gamestatemanagement.desktopgl\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{E44EFCD8-9817-400F-986E-3D6D1662C893}|GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj|solutionrelative:gamestatemanagement.desktopgl\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    }
+  ],
+  "DocumentGroupContainers": [
+    {
+      "Orientation": 0,
+      "VerticalTabListWidth": 256,
+      "DocumentGroups": [
+        {
+          "DockedWidth": 200,
+          "SelectedChildIndex": 0,
+          "Children": [
+            {
+              "$type": "Document",
+              "DocumentIndex": 0,
+              "Title": "GameStateManagementGame.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\GameStateManagementGame.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\GameStateManagementGame.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\GameStateManagementGame.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\GameStateManagementGame.cs",
+              "ViewState": "AgIAAB4AAAAAAAAAAAAAwCkAAAAqAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-20T06:36:26.736Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Bookmark",
+              "Name": "ST:0:0:{e506b91c-c606-466a-90a9-123d1d1e12b3}"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 4,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\Program.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.WindowsDX\\Program.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\Program.cs",
+              "RelativeToolTip": "GameStateManagement.WindowsDX\\Program.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAAAoAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-19T02:42:34.024Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 3,
+              "Title": "BackgroundScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\BackgroundScreen.cs",
+              "ViewState": "AgIAADoAAAAAAAAAAAAUwG0AAAAAAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:49:57.495Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 2,
+              "Title": "ScreenManager.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\ScreenManager\\ScreenManager.cs",
+              "ViewState": "AgIAACoBAAAAAAAAAAAUwDoBAAAAAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:49:47.375Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 1,
+              "Title": "MainMenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MainMenuScreen.cs",
+              "ViewState": "AgIAAFEAAAAAAAAAAAAUwF4AAAAAAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:50:55.244Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 7,
+              "Title": "GameStateManagement.DesktopGL.csproj",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "RelativeDocumentMoniker": "GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "RelativeToolTip": "GameStateManagement.DesktopGL\\GameStateManagement.DesktopGL.csproj",
+              "ViewState": "AgIAABUAAAAAAAAAAAAAACQAAAAKAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
+              "WhenOpened": "2024-09-18T15:47:41.697Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 5,
+              "Title": "GameStateManagement.WindowsDX.csproj",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "RelativeDocumentMoniker": "GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "RelativeToolTip": "GameStateManagement.WindowsDX\\GameStateManagement.WindowsDX.csproj",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAARAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
+              "WhenOpened": "2024-09-19T02:18:14.882Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 6,
+              "Title": "app.manifest",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\app.manifest",
+              "RelativeDocumentMoniker": "GameStateManagement.WindowsDX\\app.manifest",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.WindowsDX\\app.manifest",
+              "RelativeToolTip": "GameStateManagement.WindowsDX\\app.manifest",
+              "ViewState": "AgIAABsAAAAAAAAAAAAnwCMAAAA4AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001203|",
+              "WhenOpened": "2024-09-19T02:39:12.883Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 9,
+              "Title": "GameplayScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\GameplayScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAD4AAAA+AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:50:04.357Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 10,
+              "Title": "MessageBoxScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MessageBoxScreen.cs",
+              "ViewState": "AgIAAEkAAAAAAAAAAAD4v1EAAAA7AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:13.818Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 8,
+              "Title": "gamefont.spritefont",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "RelativeToolTip": "GameStateManagement.Core\\Content\\Fonts\\gamefont.spritefont",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAMAAAARAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-09-19T01:16:39.44Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 11,
+              "Title": "GameStateManagement.mgcb",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "RelativeToolTip": "GameStateManagement.Core\\Content\\GameStateManagement.mgcb",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAdAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-09-18T15:56:23.624Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 12,
+              "Title": "Strings.xml",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "RelativeDocumentMoniker": "GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "RelativeToolTip": "GameStateManagement.Android\\Resources\\Values\\Strings.xml",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAIAAAAtAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003576|",
+              "WhenOpened": "2024-09-18T15:54:37.411Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 13,
+              "Title": "MainActivity.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\MainActivity.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Android\\MainActivity.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\MainActivity.cs",
+              "RelativeToolTip": "GameStateManagement.Android\\MainActivity.cs",
+              "ViewState": "AgIAAB8AAAAAAAAAAAD4vycAAAAnAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:53:42.25Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 14,
+              "Title": "AndroidManifest.xml",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\AndroidManifest.xml",
+              "RelativeDocumentMoniker": "GameStateManagement.Android\\AndroidManifest.xml",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Android\\AndroidManifest.xml",
+              "RelativeToolTip": "GameStateManagement.Android\\AndroidManifest.xml",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAAAwAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003576|",
+              "WhenOpened": "2024-09-18T15:53:21.733Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 15,
+              "Title": "PlayerIndexEventArgs.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\PlayerIndexEventArgs.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA4AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:28.556Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 16,
+              "Title": "PauseMenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\PauseMenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:23.915Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 17,
+              "Title": "OptionsMenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\OptionsMenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:19.079Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 18,
+              "Title": "MenuScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MenuScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:07.412Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 19,
+              "Title": "MenuEntry.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\MenuEntry.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:51:03.392Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 20,
+              "Title": "LoadingScreen.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "RelativeToolTip": "GameStateManagement.Core\\Screens\\LoadingScreen.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAjAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:50:49.596Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 21,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\Program.cs",
+              "RelativeDocumentMoniker": "GameStateManagement.DesktopGL\\Program.cs",
+              "ToolTip": "C:\\Users\\savag\\source\\repos\\CartBlanche\\MonoGame\\MonoGame-Samples\\GameStateManagement\\GameStateManagement.DesktopGL\\Program.cs",
+              "RelativeToolTip": "GameStateManagement.DesktopGL\\Program.cs",
+              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAMAAAAoAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-09-18T15:48:18.94Z"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

BIN
GameStateManagement/.vs/ProjectEvaluation/gamestatemanagement.metadata.v9.bin


BIN
GameStateManagement/.vs/ProjectEvaluation/gamestatemanagement.projects.v9.bin


BIN
GameStateManagement/.vs/ProjectEvaluation/gamestatemanagement.strings.v9.bin


+ 28 - 0
GameStateManagement/.vscode/launch.json

@@ -0,0 +1,28 @@
+{
+    "version": "0.2.0",
+
+    "configurations": [
+        {
+            "name": "Launch DesktopGL",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-desktopgl",
+            "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net8.0/GameStateManagement.DesktopGL.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Desktop",
+            "console": "internalConsole",
+            "stopAtEntry": false
+        },
+        {
+            "name": "Launch Windows",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-windows",
+            "program": "${workspaceFolder}/Platforms/Windows/bin/Debug/net8.0-windows/GameStateManagement.Windows.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Windows",
+            "console": "internalConsole",
+            "stopAtEntry": false
+        }
+    ]
+}

+ 169 - 0
GameStateManagement/.vscode/tasks.json

@@ -0,0 +1,169 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "build-desktopgl",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Desktop/GameStateManagement.DesktopGL.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile",
+            "dependsOn": "build-core"
+        },
+        {
+            "label": "build-windows",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Windows/GameStateManagement.Windows.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile",
+            "dependsOn": "build-core"
+        },
+        {
+            "label": "build-android",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Android/GameStateManagement.Android.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile",
+            "dependsOn": "build-core"
+        },
+        {
+            "label": "run-desktopgl",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "run",
+                "--project",
+                "${workspaceFolder}/Platforms/Desktop/GameStateManagement.DesktopGL.csproj"
+            ],
+            "group": "test",
+            "presentation": {
+                "reveal": "always"
+            },
+            "dependsOn": "build-desktopgl"
+        },
+        {
+            "label": "run-windowsdx",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "run",
+                "--project",
+                "${workspaceFolder}/Platforms/Windows/GameStateManagement.Windows.csproj"
+            ],
+            "group": "test",
+            "presentation": {
+                "reveal": "always"
+            },
+            "dependsOn": "build-windowsdx"
+        },
+        {
+            "label": "build-core",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Core/GameStateManagement.Core.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "build-desktopgl",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Desktop/GameStateManagement.DesktopGL.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile",
+            "dependsOn": "build-core"
+        },
+        {
+            "label": "build-windowsdx",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Windows/GameStateManagement.WindowsDX.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile",
+            "dependsOn": "build-core"
+        },
+        {
+            "label": "build-android",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Android/GameStateManagement.Android.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "reveal": "silent"
+            },
+            "problemMatcher": "$msCompile",
+            "dependsOn": "build-core"
+        },
+        {
+            "label": "run-desktopgl",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "run",
+                "--project",
+                "${workspaceFolder}/Platforms/Desktop/GameStateManagement.DesktopGL.csproj"
+            ],
+            "group": "test",
+            "presentation": {
+                "reveal": "always"
+            },
+            "dependsOn": "build-desktopgl"
+        },
+        {
+            "label": "run-windowsdx",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "run",
+                "--project",
+                "${workspaceFolder}/Platforms/Windows/GameStateManagement.WindowsDX.csproj"
+            ],
+            "group": "test",
+            "presentation": {
+                "reveal": "always"
+            },
+            "dependsOn": "build-windowsdx"
+        }
+    ]
+}

BIN
GameStateManagement/Background.png


BIN
GameStateManagement/Content/background.xnb


BIN
GameStateManagement/Content/blank.xnb


BIN
GameStateManagement/Content/gamefont.xnb


BIN
GameStateManagement/Content/gradient.xnb


BIN
GameStateManagement/Content/menufont.xnb


+ 0 - 0
GameStateManagement/Default.png → GameStateManagement/Core/Content/Default.png


+ 0 - 0
GameStateManagement/Game.ico → GameStateManagement/Core/Content/Game.ico


+ 0 - 0
GameStateManagement/GameThumbnail.png → GameStateManagement/Core/Content/GameThumbnail.png


+ 0 - 0
GameStateManagement/Content/background.png → GameStateManagement/Core/Content/background.png


+ 0 - 0
GameStateManagement/Content/blank.png → GameStateManagement/Core/Content/blank.png


+ 14 - 14
GameStateManagement/Content/gamefont.spritefont → GameStateManagement/Core/Content/gamefont.spritefont

@@ -1,15 +1,15 @@
-<?xml version="1.0" encoding="utf-8"?>
-<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
-	<Asset Type="Graphics:FontDescription">
-		<FontName>Segoe UI Mono</FontName>
-		<Size>32</Size>
-		<Spacing>2</Spacing>
-		<Style>Bold</Style>
-		<CharacterRegions>
-			<CharacterRegion>
-				<Start>&#32;</Start>
-				<End>&#126;</End>
-			</CharacterRegion>
-		</CharacterRegions>
-	</Asset>
+<?xml version="1.0" encoding="utf-8"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+	<Asset Type="Graphics:FontDescription">
+		<FontName>Segoe UI Mono</FontName>
+		<Size>32</Size>
+		<Spacing>2</Spacing>
+		<Style>Bold</Style>
+		<CharacterRegions>
+			<CharacterRegion>
+				<Start>&#32;</Start>
+				<End>&#126;</End>
+			</CharacterRegion>
+		</CharacterRegions>
+	</Asset>
 </XnaContent>

+ 0 - 0
GameStateManagement/Content/gradient.png → GameStateManagement/Core/Content/gradient.png


+ 14 - 14
GameStateManagement/Content/menufont.spritefont → GameStateManagement/Core/Content/menufont.spritefont

@@ -1,15 +1,15 @@
-<?xml version="1.0" encoding="utf-8"?>
-<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
-	<Asset Type="Graphics:FontDescription">
-		<FontName>Segoe UI Mono</FontName>
-		<Size>23</Size>
-		<Spacing>2</Spacing>
-		<Style>Regular</Style>
-		<CharacterRegions>
-			<CharacterRegion>
-				<Start>&#32;</Start>
-				<End>&#126;</End>
-			</CharacterRegion>
-		</CharacterRegions>
-	</Asset>
+<?xml version="1.0" encoding="utf-8"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+	<Asset Type="Graphics:FontDescription">
+		<FontName>Segoe UI Mono</FontName>
+		<Size>23</Size>
+		<Spacing>2</Spacing>
+		<Style>Regular</Style>
+		<CharacterRegions>
+			<CharacterRegion>
+				<Start>&#32;</Start>
+				<End>&#126;</End>
+			</CharacterRegion>
+		</CharacterRegions>
+	</Asset>
 </XnaContent>

+ 77 - 87
GameStateManagement/Game.cs → GameStateManagement/Core/Game.cs

@@ -1,87 +1,77 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// Game.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// Sample showing how to manage different game states, with transitions
-    /// between menu screens, a loading screen, the game itself, and a pause
-    /// menu. This main game class is extremely simple: all the interesting
-    /// stuff happens in the ScreenManager component.
-    /// </summary>
-    public class GameStateManagementGame : Game
-    {
-        #region Fields
-
-        GraphicsDeviceManager graphics;
-        ScreenManager screenManager;
-
-#if ZUNE
-        int BufferWidth = 272;
-        int BufferHeight = 480;
-#elif IPHONE
-        int BufferWidth = 320;
-        int BufferHeight = 480;
-#else
-        int BufferWidth = 272;
-        int BufferHeight = 480;
-#endif
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// The main game constructor.
-        /// </summary>
-        public GameStateManagementGame()
-        {
-            Content.RootDirectory = "Content";
-
-            graphics = new GraphicsDeviceManager(this);
-
-            graphics.PreferredBackBufferWidth = BufferWidth;
-            graphics.PreferredBackBufferHeight = BufferHeight;
-
-            // Create the screen manager component.
-            screenManager = new ScreenManager(this);
-
-            Components.Add(screenManager);
-
-            // Activate the first screens.
-            screenManager.AddScreen(new BackgroundScreen(), null);
-            screenManager.AddScreen(new MainMenuScreen(), null);
-        }
-
-
-        #endregion
-
-        #region Draw
-
-
-        /// <summary>
-        /// This is called when the game should draw itself.
-        /// </summary>
-        protected override void Draw(GameTime gameTime)
-        {
-            graphics.GraphicsDevice.Clear(Color.Black);
-
-            // The real drawing happens inside the screen manager component.
-            base.Draw(gameTime);
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// Game.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// Sample showing how to manage different game states, with transitions
+    /// between menu screens, a loading screen, the game itself, and a pause
+    /// menu. This main game class is extremely simple: all the interesting
+    /// stuff happens in the ScreenManager component.
+    /// </summary>
+    public class GameStateManagementGame : Game
+    {
+
+        GraphicsDeviceManager graphics;
+        ScreenManager screenManager;
+
+#if ZUNE
+        int BufferWidth = 272;
+        int BufferHeight = 480;
+#elif IPHONE
+        int BufferWidth = 320;
+        int BufferHeight = 480;
+#else
+        int BufferWidth = 272;
+        int BufferHeight = 480;
+#endif
+
+
+
+        /// <summary>
+        /// The main game constructor.
+        /// </summary>
+        public GameStateManagementGame()
+        {
+            Content.RootDirectory = "Content";
+
+            graphics = new GraphicsDeviceManager(this);
+
+            graphics.PreferredBackBufferWidth = BufferWidth;
+            graphics.PreferredBackBufferHeight = BufferHeight;
+
+            // Create the screen manager component.
+            screenManager = new ScreenManager(this);
+
+            Components.Add(screenManager);
+
+            // Activate the first screens.
+            screenManager.AddScreen(new BackgroundScreen(), null);
+            screenManager.AddScreen(new MainMenuScreen(), null);
+        }
+
+
+
+
+
+        /// <summary>
+        /// This is called when the game should draw itself.
+        /// </summary>
+        protected override void Draw(GameTime gameTime)
+        {
+            graphics.GraphicsDevice.Clear(Color.Black);
+
+            // The real drawing happens inside the screen manager component.
+            base.Draw(gameTime);
+        }
+
+
+    }
+}

+ 22 - 0
GameStateManagement/Core/GameStateManagement.Core.csproj

@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <RootNamespace>GameStateManagement.Core</RootNamespace>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <Title>Game State Management</Title>
+    <Product>Game State Management</Product>
+    <Description>This sample shows how to manage the transitions between different menus and gameplay states.</Description>
+    <Company>Microsoft</Company>
+    <Copyright>Copyright © Microsoft 2007</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+  </ItemGroup>
+
+</Project>

+ 226 - 0
GameStateManagement/Core/Inputs/InputState.cs

@@ -0,0 +1,226 @@
+//-----------------------------------------------------------------------------
+// InputState.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Input.Touch;
+using System.Collections.Generic;
+
+namespace GameStateManagement;
+
+/// <summary>
+/// Helper for reading input from keyboard, gamepad, and touch input. This class 
+/// tracks both the current and previous state of the input devices, and implements 
+/// query methods for high level input actions such as "move up through the menu"
+/// or "pause the game".
+/// </summary>
+public class InputState
+{
+
+    public const int MaxInputs = 4;
+
+    public readonly KeyboardState[] CurrentKeyboardStates;
+    public readonly GamePadState[] CurrentGamePadStates;
+
+    public readonly KeyboardState[] LastKeyboardStates;
+    public readonly GamePadState[] LastGamePadStates;
+
+    public readonly bool[] GamePadWasConnected;
+
+    public TouchCollection TouchState;
+
+    public readonly List<GestureSample> Gestures = new List<GestureSample>();
+
+
+
+
+    /// <summary>
+    /// Constructs a new input state.
+    /// </summary>
+    public InputState()
+    {
+        CurrentKeyboardStates = new KeyboardState[MaxInputs];
+        CurrentGamePadStates = new GamePadState[MaxInputs];
+
+        LastKeyboardStates = new KeyboardState[MaxInputs];
+        LastGamePadStates = new GamePadState[MaxInputs];
+
+        GamePadWasConnected = new bool[MaxInputs];
+    }
+
+
+
+
+
+    /// <summary>
+    /// Reads the latest state of the keyboard and gamepad.
+    /// </summary>
+    public void Update()
+    {
+        for (int i = 0; i < MaxInputs; i++)
+        {
+            LastKeyboardStates[i] = CurrentKeyboardStates[i];
+            LastGamePadStates[i] = CurrentGamePadStates[i];
+
+            CurrentKeyboardStates[i] = Keyboard.GetState();
+            CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
+
+            // Keep track of whether a gamepad has ever been
+            // connected, so we can detect if it is unplugged.
+            if (CurrentGamePadStates[i].IsConnected)
+            {
+                GamePadWasConnected[i] = true;
+            }
+        }
+
+        TouchState = TouchPanel.GetState();
+
+        Gestures.Clear();
+        while (TouchPanel.IsGestureAvailable)
+        {
+            Gestures.Add(TouchPanel.ReadGesture());
+        }
+    }
+
+
+    /// <summary>
+    /// Helper for checking if a key was newly pressed during this update. The
+    /// controllingPlayer parameter specifies which player to read input for.
+    /// If this is null, it will accept input from any player. When a keypress
+    /// is detected, the output playerIndex reports which player pressed it.
+    /// </summary>
+    public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer,
+                                        out PlayerIndex playerIndex)
+    {
+        if (controllingPlayer.HasValue)
+        {
+            // Read input from the specified player.
+            playerIndex = controllingPlayer.Value;
+
+            int i = (int)playerIndex;
+
+            return (CurrentKeyboardStates[i].IsKeyDown(key) &&
+                    LastKeyboardStates[i].IsKeyUp(key));
+        }
+        else
+        {
+            // Accept input from any player.
+            return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
+                    IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
+                    IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
+                    IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
+        }
+    }
+
+
+    /// <summary>
+    /// Helper for checking if a button was newly pressed during this update.
+    /// The controllingPlayer parameter specifies which player to read input for.
+    /// If this is null, it will accept input from any player. When a button press
+    /// is detected, the output playerIndex reports which player pressed it.
+    /// </summary>
+    public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer,
+                                                 out PlayerIndex playerIndex)
+    {
+        if (controllingPlayer.HasValue)
+        {
+            // Read input from the specified player.
+            playerIndex = controllingPlayer.Value;
+
+            int i = (int)playerIndex;
+
+            return (CurrentGamePadStates[i].IsButtonDown(button) &&
+                    LastGamePadStates[i].IsButtonUp(button));
+        }
+        else
+        {
+            // Accept input from any player.
+            return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
+                    IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
+                    IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
+                    IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
+        }
+    }
+
+
+    /// <summary>
+    /// Checks for a "menu select" input action.
+    /// The controllingPlayer parameter specifies which player to read input for.
+    /// If this is null, it will accept input from any player. When the action
+    /// is detected, the output playerIndex reports which player pressed it.
+    /// </summary>
+    public bool IsMenuSelect(PlayerIndex? controllingPlayer,
+                             out PlayerIndex playerIndex)
+    {
+        return IsNewKeyPress(Keys.Space, controllingPlayer, out playerIndex) ||
+               IsNewKeyPress(Keys.Enter, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.A, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
+    }
+
+
+    /// <summary>
+    /// Checks for a "menu cancel" input action.
+    /// The controllingPlayer parameter specifies which player to read input for.
+    /// If this is null, it will accept input from any player. When the action
+    /// is detected, the output playerIndex reports which player pressed it.
+    /// </summary>
+    public bool IsMenuCancel(PlayerIndex? controllingPlayer,
+                             out PlayerIndex playerIndex)
+    {
+        return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.B, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex);
+    }
+
+
+    /// <summary>
+    /// Checks for a "menu up" input action.
+    /// The controllingPlayer parameter specifies which player to read
+    /// input for. If this is null, it will accept input from any player.
+    /// </summary>
+    public bool IsMenuUp(PlayerIndex? controllingPlayer)
+    {
+        PlayerIndex playerIndex;
+
+        return IsNewKeyPress(Keys.Up, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.DPadUp, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex);
+    }
+
+
+    /// <summary>
+    /// Checks for a "menu down" input action.
+    /// The controllingPlayer parameter specifies which player to read
+    /// input for. If this is null, it will accept input from any player.
+    /// </summary>
+    public bool IsMenuDown(PlayerIndex? controllingPlayer)
+    {
+        PlayerIndex playerIndex;
+
+        return IsNewKeyPress(Keys.Down, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.DPadDown, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex);
+    }
+
+
+    /// <summary>
+    /// Checks for a "pause the game" input action.
+    /// The controllingPlayer parameter specifies which player to read
+    /// input for. If this is null, it will accept input from any player.
+    /// </summary>
+    public bool IsPauseGame(PlayerIndex? controllingPlayer)
+    {
+        PlayerIndex playerIndex;
+
+        return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex) ||
+               IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
+    }
+
+
+}

+ 315 - 315
GameStateManagement/ScreenManager/ScreenManager.cs → GameStateManagement/Core/ScreenManager/ScreenManager.cs

@@ -1,315 +1,315 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// ScreenManager.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Diagnostics;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input.Touch;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// The screen manager is a component which manages one or more GameScreen
-    /// instances. It maintains a stack of screens, calls their Update and Draw
-    /// methods at the appropriate times, and automatically routes input to the
-    /// topmost active screen.
-    /// </summary>
-    public class ScreenManager : DrawableGameComponent
-    {
-        #region Fields
-
-        List<GameScreen> screens = new List<GameScreen>();
-        List<GameScreen> screensToUpdate = new List<GameScreen>();
-
-        InputState input = new InputState();
-
-        SpriteBatch spriteBatch;
-        SpriteFont font;
-        Texture2D blankTexture;
-
-        bool isInitialized;
-
-        bool traceEnabled;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// A default SpriteBatch shared by all the screens. This saves
-        /// each screen having to bother creating their own local instance.
-        /// </summary>
-        public SpriteBatch SpriteBatch
-        {
-            get { return spriteBatch; }
-        }
-
-
-        /// <summary>
-        /// A default font shared by all the screens. This saves
-        /// each screen having to bother loading their own local copy.
-        /// </summary>
-        public SpriteFont Font
-        {
-            get { return font; }
-        }
-
-
-        /// <summary>
-        /// If true, the manager prints out a list of all the screens
-        /// each time it is updated. This can be useful for making sure
-        /// everything is being added and removed at the right times.
-        /// </summary>
-        public bool TraceEnabled
-        {
-            get { return traceEnabled; }
-            set { traceEnabled = value; }
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new screen manager component.
-        /// </summary>
-        public ScreenManager(Game game)
-            : base(game)
-        {
-            // we must set EnabledGestures before we can query for them, but
-            // we don't assume the game wants to read them.
-            TouchPanel.EnabledGestures = GestureType.None;
-        }
-
-
-        /// <summary>
-        /// Initializes the screen manager component.
-        /// </summary>
-        public override void Initialize()
-        {
-            base.Initialize();
-
-            isInitialized = true;
-        }
-
-
-        /// <summary>
-        /// Load your graphics content.
-        /// </summary>
-        protected override void LoadContent()
-        {
-            // Load content belonging to the screen manager.
-            ContentManager content = Game.Content;
-
-            spriteBatch = new SpriteBatch(GraphicsDevice);
-            font = content.Load<SpriteFont>("menufont");
-            blankTexture = content.Load<Texture2D>("blank");
-
-            // Tell each of the screens to load their content.
-            foreach (GameScreen screen in screens)
-            {
-                screen.LoadContent();
-            }
-        }
-
-
-        /// <summary>
-        /// Unload your graphics content.
-        /// </summary>
-        protected override void UnloadContent()
-        {
-            // Tell each of the screens to unload their content.
-            foreach (GameScreen screen in screens)
-            {
-                screen.UnloadContent();
-            }
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Allows each screen to run logic.
-        /// </summary>
-        public override void Update(GameTime gameTime)
-        {
-            // Read the keyboard and gamepad.
-            input.Update();
-
-            // Make a copy of the master screen list, to avoid confusion if
-            // the process of updating one screen adds or removes others.
-            screensToUpdate.Clear();
-
-            foreach (GameScreen screen in screens)
-                screensToUpdate.Add(screen);
-
-            bool otherScreenHasFocus = !Game.IsActive;
-            bool coveredByOtherScreen = false;
-
-            // Loop as long as there are screens waiting to be updated.
-            while (screensToUpdate.Count > 0)
-            {
-                // Pop the topmost screen off the waiting list.
-                GameScreen screen = screensToUpdate[screensToUpdate.Count - 1];
-
-                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);
-
-                // Update the screen.
-                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-                if (screen.ScreenState == ScreenState.TransitionOn ||
-                    screen.ScreenState == ScreenState.Active)
-                {
-                    // If this is the first active screen we came across,
-                    // give it a chance to handle input.
-                    if (!otherScreenHasFocus)
-                    {
-                        screen.HandleInput(input);
-
-                        otherScreenHasFocus = true;
-                    }
-
-                    // If this is an active non-popup, inform any subsequent
-                    // screens that they are covered by it.
-                    if (!screen.IsPopup)
-                        coveredByOtherScreen = true;
-                }
-            }
-
-            // Print debug trace?
-            if (traceEnabled)
-                TraceScreens();
-        }
-
-
-        /// <summary>
-        /// Prints a list of all the screens, for debugging.
-        /// </summary>
-        void TraceScreens()
-        {
-            List<string> screenNames = new List<string>();
-
-            foreach (GameScreen screen in screens)
-                screenNames.Add(screen.GetType().Name);
-
-            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
-        }
-
-
-        /// <summary>
-        /// Tells each screen to draw itself.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            foreach (GameScreen screen in screens)
-            {
-                if (screen.ScreenState == ScreenState.Hidden)
-                    continue;
-
-                screen.Draw(gameTime);
-            }
-        }
-
-
-        #endregion
-
-        #region Public Methods
-
-
-        /// <summary>
-        /// Adds a new screen to the screen manager.
-        /// </summary>
-        public void AddScreen(GameScreen screen, PlayerIndex? controllingPlayer)
-        {
-            screen.ControllingPlayer = controllingPlayer;
-            screen.ScreenManager = this;
-            screen.IsExiting = false;
-
-            // If we have a graphics device, tell the screen to load content.
-            if (isInitialized)
-            {
-                screen.LoadContent();
-            }
-
-            screens.Add(screen);
-
-            // update the TouchPanel to respond to gestures this screen is interested in
-            TouchPanel.EnabledGestures = screen.EnabledGestures;
-        }
-
-
-        /// <summary>
-        /// Removes a screen from the screen manager. You should normally
-        /// use GameScreen.ExitScreen instead of calling this directly, so
-        /// the screen can gradually transition off rather than just being
-        /// instantly removed.
-        /// </summary>
-        public void RemoveScreen(GameScreen screen)
-        {
-            // If we have a graphics device, tell the screen to unload content.
-            if (isInitialized)
-            {
-                screen.UnloadContent();
-            }
-
-            screens.Remove(screen);
-            screensToUpdate.Remove(screen);
-
-            // if there is a screen still in the manager, update TouchPanel
-            // to respond to gestures that screen is interested in.
-            if (screens.Count > 0)
-            {
-                TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
-            }
-        }
-
-
-        /// <summary>
-        /// Expose an array holding all the screens. We return a copy rather
-        /// than the real master list, because screens should only ever be added
-        /// or removed using the AddScreen and RemoveScreen methods.
-        /// </summary>
-        public GameScreen[] GetScreens()
-        {
-            return screens.ToArray();
-        }
-
-
-        /// <summary>
-        /// Helper draws a translucent black fullscreen sprite, used for fading
-        /// screens in and out, and for darkening the background behind popups.
-        /// </summary>
-        public void FadeBackBufferToBlack(float alpha)
-        {
-            Viewport viewport = GraphicsDevice.Viewport;
-
-            spriteBatch.Begin();
-
-            spriteBatch.Draw(blankTexture,
-                             new Rectangle(0, 0, viewport.Width, viewport.Height),
-                             Color.Black * alpha);
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+#region File Description
+//-----------------------------------------------------------------------------
+// ScreenManager.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input.Touch;
+#endregion
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// The screen manager is a component which manages one or more GameScreen
+    /// instances. It maintains a stack of screens, calls their Update and Draw
+    /// methods at the appropriate times, and automatically routes input to the
+    /// topmost active screen.
+    /// </summary>
+    public class ScreenManager : DrawableGameComponent
+    {
+        #region Fields
+
+        List<GameScreen> screens = new List<GameScreen>();
+        List<GameScreen> screensToUpdate = new List<GameScreen>();
+
+        InputState input = new InputState();
+
+        SpriteBatch spriteBatch;
+        SpriteFont font;
+        Texture2D blankTexture;
+
+        bool isInitialized;
+
+        bool traceEnabled;
+
+        #endregion
+
+        #region Properties
+
+
+        /// <summary>
+        /// A default SpriteBatch shared by all the screens. This saves
+        /// each screen having to bother creating their own local instance.
+        /// </summary>
+        public SpriteBatch SpriteBatch
+        {
+            get { return spriteBatch; }
+        }
+
+
+        /// <summary>
+        /// A default font shared by all the screens. This saves
+        /// each screen having to bother loading their own local copy.
+        /// </summary>
+        public SpriteFont Font
+        {
+            get { return font; }
+        }
+
+
+        /// <summary>
+        /// If true, the manager prints out a list of all the screens
+        /// each time it is updated. This can be useful for making sure
+        /// everything is being added and removed at the right times.
+        /// </summary>
+        public bool TraceEnabled
+        {
+            get { return traceEnabled; }
+            set { traceEnabled = value; }
+        }
+
+
+        #endregion
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new screen manager component.
+        /// </summary>
+        public ScreenManager(Game game)
+            : base(game)
+        {
+            // we must set EnabledGestures before we can query for them, but
+            // we don't assume the game wants to read them.
+            TouchPanel.EnabledGestures = GestureType.None;
+        }
+
+
+        /// <summary>
+        /// Initializes the screen manager component.
+        /// </summary>
+        public override void Initialize()
+        {
+            base.Initialize();
+
+            isInitialized = true;
+        }
+
+
+        /// <summary>
+        /// Load your graphics content.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            // Load content belonging to the screen manager.
+            ContentManager content = Game.Content;
+
+            spriteBatch = new SpriteBatch(GraphicsDevice);
+            font = content.Load<SpriteFont>("menufont");
+            blankTexture = content.Load<Texture2D>("blank");
+
+            // Tell each of the screens to load their content.
+            foreach (GameScreen screen in screens)
+            {
+                screen.LoadContent();
+            }
+        }
+
+
+        /// <summary>
+        /// Unload your graphics content.
+        /// </summary>
+        protected override void UnloadContent()
+        {
+            // Tell each of the screens to unload their content.
+            foreach (GameScreen screen in screens)
+            {
+                screen.UnloadContent();
+            }
+        }
+
+
+        #endregion
+
+        #region Update and Draw
+
+
+        /// <summary>
+        /// Allows each screen to run logic.
+        /// </summary>
+        public override void Update(GameTime gameTime)
+        {
+            // Read the keyboard and gamepad.
+            input.Update();
+
+            // Make a copy of the master screen list, to avoid confusion if
+            // the process of updating one screen adds or removes others.
+            screensToUpdate.Clear();
+
+            foreach (GameScreen screen in screens)
+                screensToUpdate.Add(screen);
+
+            bool otherScreenHasFocus = !Game.IsActive;
+            bool coveredByOtherScreen = false;
+
+            // Loop as long as there are screens waiting to be updated.
+            while (screensToUpdate.Count > 0)
+            {
+                // Pop the topmost screen off the waiting list.
+                GameScreen screen = screensToUpdate[screensToUpdate.Count - 1];
+
+                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);
+
+                // Update the screen.
+                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+                if (screen.ScreenState == ScreenState.TransitionOn ||
+                    screen.ScreenState == ScreenState.Active)
+                {
+                    // If this is the first active screen we came across,
+                    // give it a chance to handle input.
+                    if (!otherScreenHasFocus)
+                    {
+                        screen.HandleInput(input);
+
+                        otherScreenHasFocus = true;
+                    }
+
+                    // If this is an active non-popup, inform any subsequent
+                    // screens that they are covered by it.
+                    if (!screen.IsPopup)
+                        coveredByOtherScreen = true;
+                }
+            }
+
+            // Print debug trace?
+            if (traceEnabled)
+                TraceScreens();
+        }
+
+
+        /// <summary>
+        /// Prints a list of all the screens, for debugging.
+        /// </summary>
+        void TraceScreens()
+        {
+            List<string> screenNames = new List<string>();
+
+            foreach (GameScreen screen in screens)
+                screenNames.Add(screen.GetType().Name);
+
+            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
+        }
+
+
+        /// <summary>
+        /// Tells each screen to draw itself.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            foreach (GameScreen screen in screens)
+            {
+                if (screen.ScreenState == ScreenState.Hidden)
+                    continue;
+
+                screen.Draw(gameTime);
+            }
+        }
+
+
+        #endregion
+
+        #region Public Methods
+
+
+        /// <summary>
+        /// Adds a new screen to the screen manager.
+        /// </summary>
+        public void AddScreen(GameScreen screen, PlayerIndex? controllingPlayer)
+        {
+            screen.ControllingPlayer = controllingPlayer;
+            screen.ScreenManager = this;
+            screen.IsExiting = false;
+
+            // If we have a graphics device, tell the screen to load content.
+            if (isInitialized)
+            {
+                screen.LoadContent();
+            }
+
+            screens.Add(screen);
+
+            // update the TouchPanel to respond to gestures this screen is interested in
+            TouchPanel.EnabledGestures = screen.EnabledGestures;
+        }
+
+
+        /// <summary>
+        /// Removes a screen from the screen manager. You should normally
+        /// use GameScreen.ExitScreen instead of calling this directly, so
+        /// the screen can gradually transition off rather than just being
+        /// instantly removed.
+        /// </summary>
+        public void RemoveScreen(GameScreen screen)
+        {
+            // If we have a graphics device, tell the screen to unload content.
+            if (isInitialized)
+            {
+                screen.UnloadContent();
+            }
+
+            screens.Remove(screen);
+            screensToUpdate.Remove(screen);
+
+            // if there is a screen still in the manager, update TouchPanel
+            // to respond to gestures that screen is interested in.
+            if (screens.Count > 0)
+            {
+                TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
+            }
+        }
+
+
+        /// <summary>
+        /// Expose an array holding all the screens. We return a copy rather
+        /// than the real master list, because screens should only ever be added
+        /// or removed using the AddScreen and RemoveScreen methods.
+        /// </summary>
+        public GameScreen[] GetScreens()
+        {
+            return screens.ToArray();
+        }
+
+
+        /// <summary>
+        /// Helper draws a translucent black fullscreen sprite, used for fading
+        /// screens in and out, and for darkening the background behind popups.
+        /// </summary>
+        public void FadeBackBufferToBlack(float alpha)
+        {
+            Viewport viewport = GraphicsDevice.Viewport;
+
+            spriteBatch.Begin();
+
+            spriteBatch.Draw(blankTexture,
+                             new Rectangle(0, 0, viewport.Width, viewport.Height),
+                             Color.Black * alpha);
+
+            spriteBatch.End();
+        }
+
+
+        #endregion
+    }
+}

+ 100 - 110
GameStateManagement/Screens/BackgroundScreen.cs → GameStateManagement/Core/Screens/BackgroundScreen.cs

@@ -1,110 +1,100 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// BackgroundScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// The background screen sits behind all the other menu screens.
-    /// It draws a background image that remains fixed in place regardless
-    /// of whatever transitions the screens on top of it may be doing.
-    /// </summary>
-    class BackgroundScreen : GameScreen
-    {
-        #region Fields
-
-        ContentManager content;
-        Texture2D backgroundTexture;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public BackgroundScreen()
-        {
-            TransitionOnTime = TimeSpan.FromSeconds(0.5);
-            TransitionOffTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        /// <summary>
-        /// Loads graphics content for this screen. The background texture is quite
-        /// big, so we use our own local ContentManager to load it. This allows us
-        /// to unload before going from the menus into the game itself, wheras if we
-        /// used the shared ContentManager provided by the Game class, the content
-        /// would remain loaded forever.
-        /// </summary>
-        public override void LoadContent()
-        {
-            if (content == null)
-                content = new ContentManager(ScreenManager.Game.Services, "Content");
-
-            backgroundTexture = content.Load<Texture2D>("background");
-        }
-
-
-        /// <summary>
-        /// Unloads graphics content for this screen.
-        /// </summary>
-        public override void UnloadContent()
-        {
-            content.Unload();
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the background screen. Unlike most screens, this should not
-        /// transition off even if it has been covered by another screen: it is
-        /// supposed to be covered, after all! This overload forces the
-        /// coveredByOtherScreen parameter to false in order to stop the base
-        /// Update method wanting to transition off.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, false);
-        }
-
-
-        /// <summary>
-        /// Draws the background screen.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-            Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);
-
-            spriteBatch.Begin();
-
-            spriteBatch.Draw(backgroundTexture, fullscreen,
-                             new Color(TransitionAlpha, TransitionAlpha, TransitionAlpha));
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// BackgroundScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// The background screen sits behind all the other menu screens.
+    /// It draws a background image that remains fixed in place regardless
+    /// of whatever transitions the screens on top of it may be doing.
+    /// </summary>
+    class BackgroundScreen : GameScreen
+    {
+
+        ContentManager content;
+        Texture2D backgroundTexture;
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public BackgroundScreen()
+        {
+            TransitionOnTime = TimeSpan.FromSeconds(0.5);
+            TransitionOffTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+        /// <summary>
+        /// Loads graphics content for this screen. The background texture is quite
+        /// big, so we use our own local ContentManager to load it. This allows us
+        /// to unload before going from the menus into the game itself, wheras if we
+        /// used the shared ContentManager provided by the Game class, the content
+        /// would remain loaded forever.
+        /// </summary>
+        public override void LoadContent()
+        {
+            if (content == null)
+                content = new ContentManager(ScreenManager.Game.Services, "Content");
+
+            backgroundTexture = content.Load<Texture2D>("background");
+        }
+
+
+        /// <summary>
+        /// Unloads graphics content for this screen.
+        /// </summary>
+        public override void UnloadContent()
+        {
+            content.Unload();
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the background screen. Unlike most screens, this should not
+        /// transition off even if it has been covered by another screen: it is
+        /// supposed to be covered, after all! This overload forces the
+        /// coveredByOtherScreen parameter to false in order to stop the base
+        /// Update method wanting to transition off.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, false);
+        }
+
+
+        /// <summary>
+        /// Draws the background screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);
+
+            spriteBatch.Begin();
+
+            spriteBatch.Draw(backgroundTexture, fullscreen,
+                             new Color(TransitionAlpha, TransitionAlpha, TransitionAlpha));
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 343 - 0
GameStateManagement/Core/Screens/GameScreen.cs

@@ -0,0 +1,343 @@
+//-----------------------------------------------------------------------------
+// GameScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input.Touch;
+using System.IO;
+
+namespace GameStateManagement;
+
+/// <summary>
+/// Enum describes the screen transition state.
+/// </summary>
+public enum ScreenState
+{
+    TransitionOn,
+    Active,
+    TransitionOff,
+    Hidden,
+}
+
+
+/// <summary>
+/// A screen is a single layer that has update and draw logic, and which
+/// can be combined with other layers to build up a complex menu system.
+/// For instance the main menu, the options menu, the "are you sure you
+/// want to quit" message box, and the main game itself are all implemented
+/// as screens.
+/// </summary>
+public abstract class GameScreen
+{
+
+
+    /// <summary>
+    /// Normally when one screen is brought up over the top of another,
+    /// the first screen will transition off to make room for the new
+    /// one. This property indicates whether the screen is only a small
+    /// popup, in which case screens underneath it do not need to bother
+    /// transitioning off.
+    /// </summary>
+    public bool IsPopup
+    {
+        get { return isPopup; }
+        protected set { isPopup = value; }
+    }
+
+    bool isPopup = false;
+
+
+    /// <summary>
+    /// Indicates how long the screen takes to
+    /// transition on when it is activated.
+    /// </summary>
+    public TimeSpan TransitionOnTime
+    {
+        get { return transitionOnTime; }
+        protected set { transitionOnTime = value; }
+    }
+
+    TimeSpan transitionOnTime = TimeSpan.Zero;
+
+
+    /// <summary>
+    /// Indicates how long the screen takes to
+    /// transition off when it is deactivated.
+    /// </summary>
+    public TimeSpan TransitionOffTime
+    {
+        get { return transitionOffTime; }
+        protected set { transitionOffTime = value; }
+    }
+
+    TimeSpan transitionOffTime = TimeSpan.Zero;
+
+
+    /// <summary>
+    /// Gets the current position of the screen transition, ranging
+    /// from zero (fully active, no transition) to one (transitioned
+    /// fully off to nothing).
+    /// </summary>
+    public float TransitionPosition
+    {
+        get { return transitionPosition; }
+        protected set { transitionPosition = value; }
+    }
+
+    float transitionPosition = 1;
+
+
+    /// <summary>
+    /// Gets the current alpha of the screen transition, ranging
+    /// from 1 (fully active, no transition) to 0 (transitioned
+    /// fully off to nothing).
+    /// </summary>
+    public float TransitionAlpha
+    {
+        get { return 1f - TransitionPosition; }
+    }
+
+
+    /// <summary>
+    /// Gets the current screen transition state.
+    /// </summary>
+    public ScreenState ScreenState
+    {
+        get { return screenState; }
+        protected set { screenState = value; }
+    }
+
+    ScreenState screenState = ScreenState.TransitionOn;
+
+
+    /// <summary>
+    /// There are two possible reasons why a screen might be transitioning
+    /// off. It could be temporarily going away to make room for another
+    /// screen that is on top of it, or it could be going away for good.
+    /// This property indicates whether the screen is exiting for real:
+    /// if set, the screen will automatically remove itself as soon as the
+    /// transition finishes.
+    /// </summary>
+    public bool IsExiting
+    {
+        get { return isExiting; }
+        protected internal set { isExiting = value; }
+    }
+
+    bool isExiting = false;
+
+
+    /// <summary>
+    /// Checks whether this screen is active and can respond to user input.
+    /// </summary>
+    public bool IsActive
+    {
+        get
+        {
+            return !otherScreenHasFocus &&
+                   (screenState == ScreenState.TransitionOn ||
+                    screenState == ScreenState.Active);
+        }
+    }
+
+    bool otherScreenHasFocus;
+
+
+    /// <summary>
+    /// Gets the manager that this screen belongs to.
+    /// </summary>
+    public ScreenManager ScreenManager
+    {
+        get { return screenManager; }
+        internal set { screenManager = value; }
+    }
+
+    ScreenManager screenManager;
+
+
+    /// <summary>
+    /// Gets the index of the player who is currently controlling this screen,
+    /// or null if it is accepting input from any player. This is used to lock
+    /// the game to a specific player profile. The main menu responds to input
+    /// from any connected gamepad, but whichever player makes a selection from
+    /// this menu is given control over all subsequent screens, so other gamepads
+    /// are inactive until the controlling player returns to the main menu.
+    /// </summary>
+    public PlayerIndex? ControllingPlayer
+    {
+        get { return controllingPlayer; }
+        internal set { controllingPlayer = value; }
+    }
+
+    PlayerIndex? controllingPlayer;
+
+
+    /// <summary>
+    /// Gets the gestures the screen is interested in. Screens should be as specific
+    /// as possible with gestures to increase the accuracy of the gesture engine.
+    /// For example, most menus only need Tap or perhaps Tap and VerticalDrag to operate.
+    /// These gestures are handled by the ScreenManager when screens change and
+    /// all gestures are placed in the InputState passed to the HandleInput method.
+    /// </summary>
+    public GestureType EnabledGestures
+    {
+        get { return enabledGestures; }
+        protected set
+        {
+            enabledGestures = value;
+
+            // the screen manager handles this during screen changes, but
+            // if this screen is active and the gesture types are changing,
+            // we have to update the TouchPanel ourself.
+            if (ScreenState == ScreenState.Active)
+            {
+                TouchPanel.EnabledGestures = value;
+            }
+        }
+    }
+
+    GestureType enabledGestures = GestureType.None;
+
+
+
+
+
+    /// <summary>
+    /// Load graphics content for the screen.
+    /// </summary>
+    public virtual void LoadContent() { }
+
+
+    /// <summary>
+    /// Unload content for the screen.
+    /// </summary>
+    public virtual void UnloadContent() { }
+
+
+
+
+
+    /// <summary>
+    /// Allows the screen to run logic, such as updating the transition position.
+    /// Unlike HandleInput, this method is called regardless of whether the screen
+    /// is active, hidden, or in the middle of a transition.
+    /// </summary>
+    public virtual void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                  bool coveredByOtherScreen)
+    {
+        this.otherScreenHasFocus = otherScreenHasFocus;
+
+        if (isExiting)
+        {
+            // If the screen is going away to die, it should transition off.
+            screenState = ScreenState.TransitionOff;
+
+            if (!UpdateTransition(gameTime, transitionOffTime, 1))
+            {
+                // When the transition finishes, remove the screen.
+                ScreenManager.RemoveScreen(this);
+            }
+        }
+        else if (coveredByOtherScreen)
+        {
+            // If the screen is covered by another, it should transition off.
+            if (UpdateTransition(gameTime, transitionOffTime, 1))
+            {
+                // Still busy transitioning.
+                screenState = ScreenState.TransitionOff;
+            }
+            else
+            {
+                // Transition finished!
+                screenState = ScreenState.Hidden;
+            }
+        }
+        else
+        {
+            // Otherwise the screen should transition on and become active.
+            if (UpdateTransition(gameTime, transitionOnTime, -1))
+            {
+                // Still busy transitioning.
+                screenState = ScreenState.TransitionOn;
+            }
+            else
+            {
+                // Transition finished!
+                screenState = ScreenState.Active;
+            }
+        }
+    }
+
+
+    /// <summary>
+    /// Helper for updating the screen transition position.
+    /// </summary>
+    bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
+    {
+        // How much should we move by?
+        float transitionDelta;
+
+        if (time == TimeSpan.Zero)
+            transitionDelta = 1;
+        else
+            transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
+                                      time.TotalMilliseconds);
+
+        // Update the transition position.
+        transitionPosition += transitionDelta * direction;
+
+        // Did we reach the end of the transition?
+        if (((direction < 0) && (transitionPosition <= 0)) ||
+            ((direction > 0) && (transitionPosition >= 1)))
+        {
+            transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
+            return false;
+        }
+
+        // Otherwise we are still busy transitioning.
+        return true;
+    }
+
+
+    /// <summary>
+    /// Allows the screen to handle user input. Unlike Update, this method
+    /// is only called when the screen is active, and not when some other
+    /// screen has taken the focus.
+    /// </summary>
+    public virtual void HandleInput(InputState input) { }
+
+
+    /// <summary>
+    /// This is called when the screen should draw itself.
+    /// </summary>
+    public virtual void Draw(GameTime gameTime) { }
+
+
+
+
+
+    /// <summary>
+    /// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
+    /// instantly kills the screen, this method respects the transition timings
+    /// and will give the screen a chance to gradually transition off.
+    /// </summary>
+    public void ExitScreen()
+    {
+        if (TransitionOffTime == TimeSpan.Zero)
+        {
+            // If the screen has a zero transition time, remove it immediately.
+            ScreenManager.RemoveScreen(this);
+        }
+        else
+        {
+            // Otherwise flag that it should transition off and then exit.
+            isExiting = true;
+        }
+    }
+
+
+}

+ 207 - 217
GameStateManagement/Screens/GameplayScreen.cs → GameStateManagement/Core/Screens/GameplayScreen.cs

@@ -1,217 +1,207 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// GameplayScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Threading;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// This screen implements the actual game logic. It is just a
-    /// placeholder to get the idea across: you'll probably want to
-    /// put some more interesting gameplay in here!
-    /// </summary>
-    class GameplayScreen : GameScreen
-    {
-        #region Fields
-
-        ContentManager content;
-        SpriteFont gameFont;
-
-        Vector2 playerPosition = new Vector2(100, 100);
-        Vector2 enemyPosition = new Vector2(100, 100);
-
-        Random random = new Random();
-
-        float pauseAlpha;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public GameplayScreen()
-        {
-            TransitionOnTime = TimeSpan.FromSeconds(1.5);
-            TransitionOffTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        /// <summary>
-        /// Load graphics content for the game.
-        /// </summary>
-        public override void LoadContent()
-        {
-            if (content == null)
-                content = new ContentManager(ScreenManager.Game.Services, "Content");
-
-            gameFont = content.Load<SpriteFont>("gamefont");
-
-            // A real game would probably have more content than this sample, so
-            // it would take longer to load. We simulate that by delaying for a
-            // while, giving you a chance to admire the beautiful loading screen.
-            Thread.Sleep(1000);
-
-            // once the load has finished, we use ResetElapsedTime to tell the game's
-            // timing mechanism that we have just finished a very long frame, and that
-            // it should not try to catch up.
-            ScreenManager.Game.ResetElapsedTime();
-        }
-
-
-        /// <summary>
-        /// Unload graphics content used by the game.
-        /// </summary>
-        public override void UnloadContent()
-        {
-            content.Unload();
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the state of the game. This method checks the GameScreen.IsActive
-        /// property, so the game will stop updating when the pause menu is active,
-        /// or if you tab away to a different application.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, false);
-
-            // Gradually fade in or out depending on whether we are covered by the pause screen.
-            if (coveredByOtherScreen)
-                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
-            else
-                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
-
-            if (IsActive)
-            {
-                // Apply some random jitter to make the enemy move around.
-                const float randomization = 10;
-
-                enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
-                enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
-
-                // Apply a stabilizing force to stop the enemy moving off the screen.
-                Vector2 targetPosition = new Vector2(
-                    ScreenManager.GraphicsDevice.Viewport.Width / 2 - gameFont.MeasureString("Insert Gameplay Here").X / 2, 
-                    200);
-
-                enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
-
-                // TODO: this game isn't very fun! You could probably improve
-                // it by inserting something more interesting in this space :-)
-            }
-        }
-
-
-        /// <summary>
-        /// Lets the game respond to player input. Unlike the Update method,
-        /// this will only be called when the gameplay screen is active.
-        /// </summary>
-        public override void HandleInput(InputState input)
-        {
-            if (input == null)
-                throw new ArgumentNullException("input");
-
-            // Look up inputs for the active player profile.
-            int playerIndex = (int)ControllingPlayer.Value;
-
-            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
-            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];
-
-            // The game pauses either if the user presses the pause button, or if
-            // they unplug the active gamepad. This requires us to keep track of
-            // whether a gamepad was ever plugged in, because we don't want to pause
-            // on PC if they are playing with a keyboard and have no gamepad at all!
-            bool gamePadDisconnected = !gamePadState.IsConnected &&
-                                       input.GamePadWasConnected[playerIndex];
-
-            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
-            {
-                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
-            }
-            else
-            {
-                // Otherwise move the player position.
-                Vector2 movement = Vector2.Zero;
-
-                if (keyboardState.IsKeyDown(Keys.Left))
-                    movement.X--;
-
-                if (keyboardState.IsKeyDown(Keys.Right))
-                    movement.X++;
-
-                if (keyboardState.IsKeyDown(Keys.Up))
-                    movement.Y--;
-
-                if (keyboardState.IsKeyDown(Keys.Down))
-                    movement.Y++;
-
-                Vector2 thumbstick = gamePadState.ThumbSticks.Left;
-
-                movement.X += thumbstick.X;
-                movement.Y -= thumbstick.Y;
-
-                if (movement.Length() > 1)
-                    movement.Normalize();
-
-                playerPosition += movement * 2;
-            }
-        }
-
-
-        /// <summary>
-        /// Draws the gameplay screen.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            // This game has a blue background. Why? Because!
-            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
-                                               Color.CornflowerBlue, 0, 0);
-
-            // Our player and enemy are both actually just text strings.
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-
-            spriteBatch.Begin();
-
-            spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
-
-            spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
-                                   enemyPosition, Color.DarkRed);
-
-            spriteBatch.End();
-
-            // If the game is transitioning on or off, fade it out to black.
-            if (TransitionPosition > 0 || pauseAlpha > 0)
-            {
-                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
-
-                ScreenManager.FadeBackBufferToBlack(alpha);
-            }
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// GameplayScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Threading;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// This screen implements the actual game logic. It is just a
+    /// placeholder to get the idea across: you'll probably want to
+    /// put some more interesting gameplay in here!
+    /// </summary>
+    class GameplayScreen : GameScreen
+    {
+
+        ContentManager content;
+        SpriteFont gameFont;
+
+        Vector2 playerPosition = new Vector2(100, 100);
+        Vector2 enemyPosition = new Vector2(100, 100);
+
+        Random random = new Random();
+
+        float pauseAlpha;
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public GameplayScreen()
+        {
+            TransitionOnTime = TimeSpan.FromSeconds(1.5);
+            TransitionOffTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+        /// <summary>
+        /// Load graphics content for the game.
+        /// </summary>
+        public override void LoadContent()
+        {
+            if (content == null)
+                content = new ContentManager(ScreenManager.Game.Services, "Content");
+
+            gameFont = content.Load<SpriteFont>("gamefont");
+
+            // A real game would probably have more content than this sample, so
+            // it would take longer to load. We simulate that by delaying for a
+            // while, giving you a chance to admire the beautiful loading screen.
+            Thread.Sleep(1000);
+
+            // once the load has finished, we use ResetElapsedTime to tell the game's
+            // timing mechanism that we have just finished a very long frame, and that
+            // it should not try to catch up.
+            ScreenManager.Game.ResetElapsedTime();
+        }
+
+
+        /// <summary>
+        /// Unload graphics content used by the game.
+        /// </summary>
+        public override void UnloadContent()
+        {
+            content.Unload();
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the state of the game. This method checks the GameScreen.IsActive
+        /// property, so the game will stop updating when the pause menu is active,
+        /// or if you tab away to a different application.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, false);
+
+            // Gradually fade in or out depending on whether we are covered by the pause screen.
+            if (coveredByOtherScreen)
+                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
+            else
+                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
+
+            if (IsActive)
+            {
+                // Apply some random jitter to make the enemy move around.
+                const float randomization = 10;
+
+                enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
+                enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
+
+                // Apply a stabilizing force to stop the enemy moving off the screen.
+                Vector2 targetPosition = new Vector2(
+                    ScreenManager.GraphicsDevice.Viewport.Width / 2 - gameFont.MeasureString("Insert Gameplay Here").X / 2, 
+                    200);
+
+                enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
+
+                // TODO: this game isn't very fun! You could probably improve
+                // it by inserting something more interesting in this space :-)
+            }
+        }
+
+
+        /// <summary>
+        /// Lets the game respond to player input. Unlike the Update method,
+        /// this will only be called when the gameplay screen is active.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            if (input == null)
+                throw new ArgumentNullException("input");
+
+            // Look up inputs for the active player profile.
+            int playerIndex = (int)ControllingPlayer.Value;
+
+            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
+            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];
+
+            // The game pauses either if the user presses the pause button, or if
+            // they unplug the active gamepad. This requires us to keep track of
+            // whether a gamepad was ever plugged in, because we don't want to pause
+            // on PC if they are playing with a keyboard and have no gamepad at all!
+            bool gamePadDisconnected = !gamePadState.IsConnected &&
+                                       input.GamePadWasConnected[playerIndex];
+
+            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
+            {
+                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
+            }
+            else
+            {
+                // Otherwise move the player position.
+                Vector2 movement = Vector2.Zero;
+
+                if (keyboardState.IsKeyDown(Keys.Left))
+                    movement.X--;
+
+                if (keyboardState.IsKeyDown(Keys.Right))
+                    movement.X++;
+
+                if (keyboardState.IsKeyDown(Keys.Up))
+                    movement.Y--;
+
+                if (keyboardState.IsKeyDown(Keys.Down))
+                    movement.Y++;
+
+                Vector2 thumbstick = gamePadState.ThumbSticks.Left;
+
+                movement.X += thumbstick.X;
+                movement.Y -= thumbstick.Y;
+
+                if (movement.Length() > 1)
+                    movement.Normalize();
+
+                playerPosition += movement * 2;
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the gameplay screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // This game has a blue background. Why? Because!
+            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
+                                               Color.CornflowerBlue, 0, 0);
+
+            // Our player and enemy are both actually just text strings.
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+
+            spriteBatch.Begin();
+
+            spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
+
+            spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
+                                   enemyPosition, Color.DarkRed);
+
+            spriteBatch.End();
+
+            // If the game is transitioning on or off, fade it out to black.
+            if (TransitionPosition > 0 || pauseAlpha > 0)
+            {
+                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
+
+                ScreenManager.FadeBackBufferToBlack(alpha);
+            }
+        }
+
+
+    }
+}

+ 152 - 162
GameStateManagement/Screens/LoadingScreen.cs → GameStateManagement/Core/Screens/LoadingScreen.cs

@@ -1,162 +1,152 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// LoadingScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// The loading screen coordinates transitions between the menu system and the
-    /// game itself. Normally one screen will transition off at the same time as
-    /// the next screen is transitioning on, but for larger transitions that can
-    /// take a longer time to load their data, we want the menu system to be entirely
-    /// gone before we start loading the game. This is done as follows:
-    /// 
-    /// - Tell all the existing screens to transition off.
-    /// - Activate a loading screen, which will transition on at the same time.
-    /// - The loading screen watches the state of the previous screens.
-    /// - When it sees they have finished transitioning off, it activates the real
-    ///   next screen, which may take a long time to load its data. The loading
-    ///   screen will be the only thing displayed while this load is taking place.
-    /// </summary>
-    class LoadingScreen : GameScreen
-    {
-        #region Fields
-
-        bool loadingIsSlow;
-        bool otherScreensAreGone;
-
-        GameScreen[] screensToLoad;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// The constructor is private: loading screens should
-        /// be activated via the static Load method instead.
-        /// </summary>
-        private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
-                              GameScreen[] screensToLoad)
-        {
-            this.loadingIsSlow = loadingIsSlow;
-            this.screensToLoad = screensToLoad;
-
-            TransitionOnTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        /// <summary>
-        /// Activates the loading screen.
-        /// </summary>
-        public static void Load(ScreenManager screenManager, bool loadingIsSlow,
-                                PlayerIndex? controllingPlayer,
-                                params GameScreen[] screensToLoad)
-        {
-            // Tell all the current screens to transition off.
-            foreach (GameScreen screen in screenManager.GetScreens())
-                screen.ExitScreen();
-
-            // Create and activate the loading screen.
-            LoadingScreen loadingScreen = new LoadingScreen(screenManager,
-                                                            loadingIsSlow,
-                                                            screensToLoad);
-
-            screenManager.AddScreen(loadingScreen, controllingPlayer);
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the loading screen.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-            // If all the previous screens have finished transitioning
-            // off, it is time to actually perform the load.
-            if (otherScreensAreGone)
-            {
-                ScreenManager.RemoveScreen(this);
-
-                foreach (GameScreen screen in screensToLoad)
-                {
-                    if (screen != null)
-                    {
-                        ScreenManager.AddScreen(screen, ControllingPlayer);
-                    }
-                }
-
-                // Once the load has finished, we use ResetElapsedTime to tell
-                // the  game timing mechanism that we have just finished a very
-                // long frame, and that it should not try to catch up.
-                ScreenManager.Game.ResetElapsedTime();
-            }
-        }
-
-
-        /// <summary>
-        /// Draws the loading screen.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            // If we are the only active screen, that means all the previous screens
-            // must have finished transitioning off. We check for this in the Draw
-            // method, rather than in Update, because it isn't enough just for the
-            // screens to be gone: in order for the transition to look good we must
-            // have actually drawn a frame without them before we perform the load.
-            if ((ScreenState == ScreenState.Active) &&
-                (ScreenManager.GetScreens().Length == 1))
-            {
-                otherScreensAreGone = true;
-            }
-
-            // The gameplay screen takes a while to load, so we display a loading
-            // message while that is going on, but the menus load very quickly, and
-            // it would look silly if we flashed this up for just a fraction of a
-            // second while returning from the game to the menus. This parameter
-            // tells us how long the loading is going to take, so we know whether
-            // to bother drawing the message.
-            if (loadingIsSlow)
-            {
-                SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-                SpriteFont font = ScreenManager.Font;
-
-                const string message = "Loading...";
-
-                // Center the text in the viewport.
-                Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-                Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
-                Vector2 textSize = font.MeasureString(message);
-                Vector2 textPosition = (viewportSize - textSize) / 2;
-
-                Color color = Color.White * TransitionAlpha;
-
-                // Draw the text.
-                spriteBatch.Begin();
-                spriteBatch.DrawString(font, message, textPosition, color);
-                spriteBatch.End();
-            }
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// LoadingScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// The loading screen coordinates transitions between the menu system and the
+    /// game itself. Normally one screen will transition off at the same time as
+    /// the next screen is transitioning on, but for larger transitions that can
+    /// take a longer time to load their data, we want the menu system to be entirely
+    /// gone before we start loading the game. This is done as follows:
+    /// 
+    /// - Tell all the existing screens to transition off.
+    /// - Activate a loading screen, which will transition on at the same time.
+    /// - The loading screen watches the state of the previous screens.
+    /// - When it sees they have finished transitioning off, it activates the real
+    ///   next screen, which may take a long time to load its data. The loading
+    ///   screen will be the only thing displayed while this load is taking place.
+    /// </summary>
+    class LoadingScreen : GameScreen
+    {
+
+        bool loadingIsSlow;
+        bool otherScreensAreGone;
+
+        GameScreen[] screensToLoad;
+
+
+
+
+        /// <summary>
+        /// The constructor is private: loading screens should
+        /// be activated via the static Load method instead.
+        /// </summary>
+        private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
+                              GameScreen[] screensToLoad)
+        {
+            this.loadingIsSlow = loadingIsSlow;
+            this.screensToLoad = screensToLoad;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+        /// <summary>
+        /// Activates the loading screen.
+        /// </summary>
+        public static void Load(ScreenManager screenManager, bool loadingIsSlow,
+                                PlayerIndex? controllingPlayer,
+                                params GameScreen[] screensToLoad)
+        {
+            // Tell all the current screens to transition off.
+            foreach (GameScreen screen in screenManager.GetScreens())
+                screen.ExitScreen();
+
+            // Create and activate the loading screen.
+            LoadingScreen loadingScreen = new LoadingScreen(screenManager,
+                                                            loadingIsSlow,
+                                                            screensToLoad);
+
+            screenManager.AddScreen(loadingScreen, controllingPlayer);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the loading screen.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            // If all the previous screens have finished transitioning
+            // off, it is time to actually perform the load.
+            if (otherScreensAreGone)
+            {
+                ScreenManager.RemoveScreen(this);
+
+                foreach (GameScreen screen in screensToLoad)
+                {
+                    if (screen != null)
+                    {
+                        ScreenManager.AddScreen(screen, ControllingPlayer);
+                    }
+                }
+
+                // Once the load has finished, we use ResetElapsedTime to tell
+                // the  game timing mechanism that we have just finished a very
+                // long frame, and that it should not try to catch up.
+                ScreenManager.Game.ResetElapsedTime();
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the loading screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // If we are the only active screen, that means all the previous screens
+            // must have finished transitioning off. We check for this in the Draw
+            // method, rather than in Update, because it isn't enough just for the
+            // screens to be gone: in order for the transition to look good we must
+            // have actually drawn a frame without them before we perform the load.
+            if ((ScreenState == ScreenState.Active) &&
+                (ScreenManager.GetScreens().Length == 1))
+            {
+                otherScreensAreGone = true;
+            }
+
+            // The gameplay screen takes a while to load, so we display a loading
+            // message while that is going on, but the menus load very quickly, and
+            // it would look silly if we flashed this up for just a fraction of a
+            // second while returning from the game to the menus. This parameter
+            // tells us how long the loading is going to take, so we know whether
+            // to bother drawing the message.
+            if (loadingIsSlow)
+            {
+                SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+                SpriteFont font = ScreenManager.Font;
+
+                const string message = "Loading...";
+
+                // Center the text in the viewport.
+                Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+                Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+                Vector2 textSize = font.MeasureString(message);
+                Vector2 textPosition = (viewportSize - textSize) / 2;
+
+                Color color = Color.White * TransitionAlpha;
+
+                // Draw the text.
+                spriteBatch.Begin();
+                spriteBatch.DrawString(font, message, textPosition, color);
+                spriteBatch.End();
+            }
+        }
+
+
+    }
+}

+ 90 - 98
GameStateManagement/Screens/MainMenuScreen.cs → GameStateManagement/Core/Screens/MainMenuScreen.cs

@@ -1,98 +1,90 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MainMenuScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// The main menu screen is the first thing displayed when the game starts up.
-    /// </summary>
-    class MainMenuScreen : MenuScreen
-    {
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor fills in the menu contents.
-        /// </summary>
-        public MainMenuScreen()
-            : base("Main Menu")
-        {
-            // Create our menu entries.
-            MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
-            MenuEntry optionsMenuEntry = new MenuEntry("Options");
-            MenuEntry exitMenuEntry = new MenuEntry("Exit");
-
-            // Hook up menu event handlers.
-            playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
-            optionsMenuEntry.Selected += OptionsMenuEntrySelected;
-            exitMenuEntry.Selected += OnCancel;
-
-            // Add entries to the menu.
-            MenuEntries.Add(playGameMenuEntry);
-            MenuEntries.Add(optionsMenuEntry);
-            MenuEntries.Add(exitMenuEntry);
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Event handler for when the Play Game menu entry is selected.
-        /// </summary>
-        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
-                               new GameplayScreen());
-        }
-
-
-        /// <summary>
-        /// Event handler for when the Options menu entry is selected.
-        /// </summary>
-        void OptionsMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            ScreenManager.AddScreen(new OptionsMenuScreen(), e.PlayerIndex);
-        }
-
-
-        /// <summary>
-        /// When the user cancels the main menu, ask if they want to exit the sample.
-        /// </summary>
-        protected override void OnCancel(PlayerIndex playerIndex)
-        {
-            const string message = "Are you sure you want to exit this sample?";
-
-            MessageBoxScreen confirmExitMessageBox = new MessageBoxScreen(message);
-
-            confirmExitMessageBox.Accepted += ConfirmExitMessageBoxAccepted;
-
-            ScreenManager.AddScreen(confirmExitMessageBox, playerIndex);
-        }
-
-
-        /// <summary>
-        /// Event handler for when the user selects ok on the "are you sure
-        /// you want to exit" message box.
-        /// </summary>
-        void ConfirmExitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
-        {
-            ScreenManager.Game.Exit();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MainMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// The main menu screen is the first thing displayed when the game starts up.
+    /// </summary>
+    class MainMenuScreen : MenuScreen
+    {
+
+
+        /// <summary>
+        /// Constructor fills in the menu contents.
+        /// </summary>
+        public MainMenuScreen()
+            : base("Main Menu")
+        {
+            // Create our menu entries.
+            MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
+            MenuEntry optionsMenuEntry = new MenuEntry("Options");
+            MenuEntry exitMenuEntry = new MenuEntry("Exit");
+
+            // Hook up menu event handlers.
+            playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
+            optionsMenuEntry.Selected += OptionsMenuEntrySelected;
+            exitMenuEntry.Selected += OnCancel;
+
+            // Add entries to the menu.
+            MenuEntries.Add(playGameMenuEntry);
+            MenuEntries.Add(optionsMenuEntry);
+            MenuEntries.Add(exitMenuEntry);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Event handler for when the Play Game menu entry is selected.
+        /// </summary>
+        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
+                               new GameplayScreen());
+        }
+
+
+        /// <summary>
+        /// Event handler for when the Options menu entry is selected.
+        /// </summary>
+        void OptionsMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            ScreenManager.AddScreen(new OptionsMenuScreen(), e.PlayerIndex);
+        }
+
+
+        /// <summary>
+        /// When the user cancels the main menu, ask if they want to exit the sample.
+        /// </summary>
+        protected override void OnCancel(PlayerIndex playerIndex)
+        {
+            const string message = "Are you sure you want to exit this sample?";
+
+            MessageBoxScreen confirmExitMessageBox = new MessageBoxScreen(message);
+
+            confirmExitMessageBox.Accepted += ConfirmExitMessageBoxAccepted;
+
+            ScreenManager.AddScreen(confirmExitMessageBox, playerIndex);
+        }
+
+
+        /// <summary>
+        /// Event handler for when the user selects ok on the "are you sure
+        /// you want to exit" message box.
+        /// </summary>
+        void ConfirmExitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+        {
+            ScreenManager.Game.Exit();
+        }
+
+
+    }
+}

+ 177 - 191
GameStateManagement/Screens/MenuEntry.cs → GameStateManagement/Core/Screens/MenuEntry.cs

@@ -1,191 +1,177 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MenuEntry.cs
-//
-// XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// Helper class represents a single entry in a MenuScreen. By default this
-    /// just draws the entry text string, but it can be customized to display menu
-    /// entries in different ways. This also provides an event that will be raised
-    /// when the menu entry is selected.
-    /// </summary>
-    class MenuEntry
-    {
-        #region Fields
-
-        /// <summary>
-        /// The text rendered for this entry.
-        /// </summary>
-        string text;
-
-        /// <summary>
-        /// Tracks a fading selection effect on the entry.
-        /// </summary>
-        /// <remarks>
-        /// The entries transition out of the selection effect when they are deselected.
-        /// </remarks>
-        float selectionFade;
-
-        /// <summary>
-        /// The position at which the entry is drawn. This is set by the MenuScreen
-        /// each frame in Update.
-        /// </summary>
-        Vector2 position;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// Gets or sets the text of this menu entry.
-        /// </summary>
-        public string Text
-        {
-            get { return text; }
-            set { text = value; }
-        }
-
-
-        /// <summary>
-        /// Gets or sets the position at which to draw this menu entry.
-        /// </summary>
-        public Vector2 Position
-        {
-            get { return position; }
-            set { position = value; }
-        }
-
-
-        #endregion
-
-        #region Events
-
-
-        /// <summary>
-        /// Event raised when the menu entry is selected.
-        /// </summary>
-        public event EventHandler<PlayerIndexEventArgs> Selected;
-
-
-        /// <summary>
-        /// Method for raising the Selected event.
-        /// </summary>
-        protected internal virtual void OnSelectEntry(PlayerIndex playerIndex)
-        {
-            if (Selected != null)
-                Selected(this, new PlayerIndexEventArgs(playerIndex));
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new menu entry with the specified text.
-        /// </summary>
-        public MenuEntry(string text)
-        {
-            this.text = text;
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the menu entry.
-        /// </summary>
-        public virtual void Update(MenuScreen screen, bool isSelected, GameTime gameTime)
-        {
-            // there is no such thing as a selected item on Windows Phone, so we always
-            // force isSelected to be false
-#if WINDOWS_PHONE
-            isSelected = false;
-#endif
-
-            // When the menu selection changes, entries gradually fade between
-            // their selected and deselected appearance, rather than instantly
-            // popping to the new state.
-            float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;
-
-            if (isSelected)
-                selectionFade = Math.Min(selectionFade + fadeSpeed, 1);
-            else
-                selectionFade = Math.Max(selectionFade - fadeSpeed, 0);
-        }
-
-
-        /// <summary>
-        /// Draws the menu entry. This can be overridden to customize the appearance.
-        /// </summary>
-        public virtual void Draw(MenuScreen screen, bool isSelected, GameTime gameTime)
-        {
-            // there is no such thing as a selected item on Windows Phone, so we always
-            // force isSelected to be false
-#if WINDOWS_PHONE
-            isSelected = false;
-#endif
-
-            // Draw the selected entry in yellow, otherwise white.
-            Color color = isSelected ? Color.Yellow : Color.White;
-
-            // Pulsate the size of the selected menu entry.
-            double time = gameTime.TotalGameTime.TotalSeconds;
-            
-            float pulsate = (float)Math.Sin(time * 6) + 1;
-
-            float scale = 1 + pulsate * 0.05f * selectionFade;
-
-            // Modify the alpha to fade text out during transitions.
-            color *= screen.TransitionAlpha;
-
-            // Draw text, centered on the middle of each line.
-            ScreenManager screenManager = screen.ScreenManager;
-            SpriteBatch spriteBatch = screenManager.SpriteBatch;
-            SpriteFont font = screenManager.Font;
-
-            Vector2 origin = new Vector2(0, font.LineSpacing / 2);
-
-            spriteBatch.DrawString(font, text, position, color, 0,
-                                   origin, scale, SpriteEffects.None, 0);
-        }
-
-
-        /// <summary>
-        /// Queries how much space this menu entry requires.
-        /// </summary>
-        public virtual int GetHeight(MenuScreen screen)
-        {
-            return screen.ScreenManager.Font.LineSpacing;
-        }
-
-
-        /// <summary>
-        /// Queries how wide the entry is, used for centering on the screen.
-        /// </summary>
-        public virtual int GetWidth(MenuScreen screen)
-        {
-            return (int)screen.ScreenManager.Font.MeasureString(Text).X;
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MenuEntry.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// Helper class represents a single entry in a MenuScreen. By default this
+    /// just draws the entry text string, but it can be customized to display menu
+    /// entries in different ways. This also provides an event that will be raised
+    /// when the menu entry is selected.
+    /// </summary>
+    class MenuEntry
+    {
+
+        /// <summary>
+        /// The text rendered for this entry.
+        /// </summary>
+        string text;
+
+        /// <summary>
+        /// Tracks a fading selection effect on the entry.
+        /// </summary>
+        /// <remarks>
+        /// The entries transition out of the selection effect when they are deselected.
+        /// </remarks>
+        float selectionFade;
+
+        /// <summary>
+        /// The position at which the entry is drawn. This is set by the MenuScreen
+        /// each frame in Update.
+        /// </summary>
+        Vector2 position;
+
+
+
+
+        /// <summary>
+        /// Gets or sets the text of this menu entry.
+        /// </summary>
+        public string Text
+        {
+            get { return text; }
+            set { text = value; }
+        }
+
+
+        /// <summary>
+        /// Gets or sets the position at which to draw this menu entry.
+        /// </summary>
+        public Vector2 Position
+        {
+            get { return position; }
+            set { position = value; }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Event raised when the menu entry is selected.
+        /// </summary>
+        public event EventHandler<PlayerIndexEventArgs> Selected;
+
+
+        /// <summary>
+        /// Method for raising the Selected event.
+        /// </summary>
+        protected internal virtual void OnSelectEntry(PlayerIndex playerIndex)
+        {
+            if (Selected != null)
+                Selected(this, new PlayerIndexEventArgs(playerIndex));
+        }
+
+
+
+
+
+        /// <summary>
+        /// Constructs a new menu entry with the specified text.
+        /// </summary>
+        public MenuEntry(string text)
+        {
+            this.text = text;
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the menu entry.
+        /// </summary>
+        public virtual void Update(MenuScreen screen, bool isSelected, GameTime gameTime)
+        {
+            // there is no such thing as a selected item on Windows Phone, so we always
+            // force isSelected to be false
+#if WINDOWS_PHONE
+            isSelected = false;
+#endif
+
+            // When the menu selection changes, entries gradually fade between
+            // their selected and deselected appearance, rather than instantly
+            // popping to the new state.
+            float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;
+
+            if (isSelected)
+                selectionFade = Math.Min(selectionFade + fadeSpeed, 1);
+            else
+                selectionFade = Math.Max(selectionFade - fadeSpeed, 0);
+        }
+
+
+        /// <summary>
+        /// Draws the menu entry. This can be overridden to customize the appearance.
+        /// </summary>
+        public virtual void Draw(MenuScreen screen, bool isSelected, GameTime gameTime)
+        {
+            // there is no such thing as a selected item on Windows Phone, so we always
+            // force isSelected to be false
+#if WINDOWS_PHONE
+            isSelected = false;
+#endif
+
+            // Draw the selected entry in yellow, otherwise white.
+            Color color = isSelected ? Color.Yellow : Color.White;
+
+            // Pulsate the size of the selected menu entry.
+            double time = gameTime.TotalGameTime.TotalSeconds;
+            
+            float pulsate = (float)Math.Sin(time * 6) + 1;
+
+            float scale = 1 + pulsate * 0.05f * selectionFade;
+
+            // Modify the alpha to fade text out during transitions.
+            color *= screen.TransitionAlpha;
+
+            // Draw text, centered on the middle of each line.
+            ScreenManager screenManager = screen.ScreenManager;
+            SpriteBatch spriteBatch = screenManager.SpriteBatch;
+            SpriteFont font = screenManager.Font;
+
+            Vector2 origin = new Vector2(0, font.LineSpacing / 2);
+
+            spriteBatch.DrawString(font, text, position, color, 0,
+                                   origin, scale, SpriteEffects.None, 0);
+        }
+
+
+        /// <summary>
+        /// Queries how much space this menu entry requires.
+        /// </summary>
+        public virtual int GetHeight(MenuScreen screen)
+        {
+            return screen.ScreenManager.Font.LineSpacing;
+        }
+
+
+        /// <summary>
+        /// Queries how wide the entry is, used for centering on the screen.
+        /// </summary>
+        public virtual int GetWidth(MenuScreen screen)
+        {
+            return (int)screen.ScreenManager.Font.MeasureString(Text).X;
+        }
+
+
+    }
+}

+ 230 - 244
GameStateManagement/Screens/MenuScreen.cs → GameStateManagement/Core/Screens/MenuScreen.cs

@@ -1,244 +1,230 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MenuScreen.cs
-//
-// XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input.Touch;
-using Microsoft.Xna.Framework.Input;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// Base class for screens that contain a menu of options. The user can
-    /// move up and down to select an entry, or cancel to back out of the screen.
-    /// </summary>
-    abstract class MenuScreen : GameScreen
-    {
-        #region Fields
-
-        List<MenuEntry> menuEntries = new List<MenuEntry>();
-        int selectedEntry = 0;
-        string menuTitle;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// Gets the list of menu entries, so derived classes can add
-        /// or change the menu contents.
-        /// </summary>
-        protected IList<MenuEntry> MenuEntries
-        {
-            get { return menuEntries; }
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public MenuScreen(string menuTitle)
-        {
-            this.menuTitle = menuTitle;
-
-            TransitionOnTime = TimeSpan.FromSeconds(0.5);
-            TransitionOffTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Responds to user input, changing the selected entry and accepting
-        /// or cancelling the menu.
-        /// </summary>
-        public override void HandleInput(InputState input)
-        {
-            // Move to the previous menu entry?
-            if (input.IsMenuUp(ControllingPlayer))
-            {
-                selectedEntry--;
-
-                if (selectedEntry < 0)
-                    selectedEntry = menuEntries.Count - 1;
-            }
-
-            // Move to the next menu entry?
-            if (input.IsMenuDown(ControllingPlayer))
-            {
-                selectedEntry++;
-
-                if (selectedEntry >= menuEntries.Count)
-                    selectedEntry = 0;
-            }
-
-            // Accept or cancel the menu? We pass in our ControllingPlayer, which may
-            // either be null (to accept input from any player) or a specific index.
-            // If we pass a null controlling player, the InputState helper returns to
-            // us which player actually provided the input. We pass that through to
-            // OnSelectEntry and OnCancel, so they can tell which player triggered them.
-            PlayerIndex playerIndex;
-
-            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
-            {
-                OnSelectEntry(selectedEntry, playerIndex);
-            }
-            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
-            {
-                OnCancel(playerIndex);
-            }
-        }
-
-
-        /// <summary>
-        /// Handler for when the user has chosen a menu entry.
-        /// </summary>
-        protected virtual void OnSelectEntry(int entryIndex, PlayerIndex playerIndex)
-        {
-            menuEntries[entryIndex].OnSelectEntry(playerIndex);
-        }
-
-
-        /// <summary>
-        /// Handler for when the user has cancelled the menu.
-        /// </summary>
-        protected virtual void OnCancel(PlayerIndex playerIndex)
-        {
-            ExitScreen();
-        }
-
-
-        /// <summary>
-        /// Helper overload makes it easy to use OnCancel as a MenuEntry event handler.
-        /// </summary>
-        protected void OnCancel(object sender, PlayerIndexEventArgs e)
-        {
-            OnCancel(e.PlayerIndex);
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Allows the screen the chance to position the menu entries. By default
-        /// all menu entries are lined up in a vertical list, centered on the screen.
-        /// </summary>
-        protected virtual void UpdateMenuEntryLocations()
-        {
-            // Make the menu slide into place during transitions, using a
-            // power curve to make things look more interesting (this makes
-            // the movement slow down as it nears the end).
-            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
-
-            // start at Y = 175; each X value is generated per entry
-            Vector2 position = new Vector2(0f, 175f);
-
-            // update each menu entry's location in turn
-            for (int i = 0; i < menuEntries.Count; i++)
-            {
-                MenuEntry menuEntry = menuEntries[i];
-                
-                // each entry is to be centered horizontally
-                position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;
-
-                if (ScreenState == ScreenState.TransitionOn)
-                    position.X -= transitionOffset * 256;
-                else
-                    position.X += transitionOffset * 512;
-
-                // set the entry's position
-                menuEntry.Position = position;
-
-                // move down for the next entry the size of this entry
-                position.Y += menuEntry.GetHeight(this);
-            }
-        }
-
-
-        /// <summary>
-        /// Updates the menu.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-            // Update each nested MenuEntry object.
-            for (int i = 0; i < menuEntries.Count; i++)
-            {
-                bool isSelected = IsActive && (i == selectedEntry);
-
-                menuEntries[i].Update(this, isSelected, gameTime);
-            }
-        }
-
-
-        /// <summary>
-        /// Draws the menu.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            // make sure our entries are in the right place before we draw them
-            UpdateMenuEntryLocations();
-
-            GraphicsDevice graphics = ScreenManager.GraphicsDevice;
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-            SpriteFont font = ScreenManager.Font;
-
-            spriteBatch.Begin();
-
-            // Draw each menu entry in turn.
-            for (int i = 0; i < menuEntries.Count; i++)
-            {
-                MenuEntry menuEntry = menuEntries[i];
-
-                bool isSelected = IsActive && (i == selectedEntry);
-
-                menuEntry.Draw(this, isSelected, gameTime);
-            }
-
-            // Make the menu slide into place during transitions, using a
-            // power curve to make things look more interesting (this makes
-            // the movement slow down as it nears the end).
-            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
-
-            // Draw the menu title centered on the screen
-            Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
-            Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
-            Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
-            float titleScale = 1.25f;
-
-            titlePosition.Y -= transitionOffset * 100;
-
-            spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
-                                   titleOrigin, titleScale, SpriteEffects.None, 0);
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MenuScreen.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input.Touch;
+using Microsoft.Xna.Framework.Input;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// Base class for screens that contain a menu of options. The user can
+    /// move up and down to select an entry, or cancel to back out of the screen.
+    /// </summary>
+    abstract class MenuScreen : GameScreen
+    {
+
+        List<MenuEntry> menuEntries = new List<MenuEntry>();
+        int selectedEntry = 0;
+        string menuTitle;
+
+
+
+
+        /// <summary>
+        /// Gets the list of menu entries, so derived classes can add
+        /// or change the menu contents.
+        /// </summary>
+        protected IList<MenuEntry> MenuEntries
+        {
+            get { return menuEntries; }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public MenuScreen(string menuTitle)
+        {
+            this.menuTitle = menuTitle;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.5);
+            TransitionOffTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Responds to user input, changing the selected entry and accepting
+        /// or cancelling the menu.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            // Move to the previous menu entry?
+            if (input.IsMenuUp(ControllingPlayer))
+            {
+                selectedEntry--;
+
+                if (selectedEntry < 0)
+                    selectedEntry = menuEntries.Count - 1;
+            }
+
+            // Move to the next menu entry?
+            if (input.IsMenuDown(ControllingPlayer))
+            {
+                selectedEntry++;
+
+                if (selectedEntry >= menuEntries.Count)
+                    selectedEntry = 0;
+            }
+
+            // Accept or cancel the menu? We pass in our ControllingPlayer, which may
+            // either be null (to accept input from any player) or a specific index.
+            // If we pass a null controlling player, the InputState helper returns to
+            // us which player actually provided the input. We pass that through to
+            // OnSelectEntry and OnCancel, so they can tell which player triggered them.
+            PlayerIndex playerIndex;
+
+            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
+            {
+                OnSelectEntry(selectedEntry, playerIndex);
+            }
+            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
+            {
+                OnCancel(playerIndex);
+            }
+        }
+
+
+        /// <summary>
+        /// Handler for when the user has chosen a menu entry.
+        /// </summary>
+        protected virtual void OnSelectEntry(int entryIndex, PlayerIndex playerIndex)
+        {
+            menuEntries[entryIndex].OnSelectEntry(playerIndex);
+        }
+
+
+        /// <summary>
+        /// Handler for when the user has cancelled the menu.
+        /// </summary>
+        protected virtual void OnCancel(PlayerIndex playerIndex)
+        {
+            ExitScreen();
+        }
+
+
+        /// <summary>
+        /// Helper overload makes it easy to use OnCancel as a MenuEntry event handler.
+        /// </summary>
+        protected void OnCancel(object sender, PlayerIndexEventArgs e)
+        {
+            OnCancel(e.PlayerIndex);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Allows the screen the chance to position the menu entries. By default
+        /// all menu entries are lined up in a vertical list, centered on the screen.
+        /// </summary>
+        protected virtual void UpdateMenuEntryLocations()
+        {
+            // Make the menu slide into place during transitions, using a
+            // power curve to make things look more interesting (this makes
+            // the movement slow down as it nears the end).
+            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+            // start at Y = 175; each X value is generated per entry
+            Vector2 position = new Vector2(0f, 175f);
+
+            // update each menu entry's location in turn
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                MenuEntry menuEntry = menuEntries[i];
+                
+                // each entry is to be centered horizontally
+                position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;
+
+                if (ScreenState == ScreenState.TransitionOn)
+                    position.X -= transitionOffset * 256;
+                else
+                    position.X += transitionOffset * 512;
+
+                // set the entry's position
+                menuEntry.Position = position;
+
+                // move down for the next entry the size of this entry
+                position.Y += menuEntry.GetHeight(this);
+            }
+        }
+
+
+        /// <summary>
+        /// Updates the menu.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            // Update each nested MenuEntry object.
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                bool isSelected = IsActive && (i == selectedEntry);
+
+                menuEntries[i].Update(this, isSelected, gameTime);
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the menu.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // make sure our entries are in the right place before we draw them
+            UpdateMenuEntryLocations();
+
+            GraphicsDevice graphics = ScreenManager.GraphicsDevice;
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            SpriteFont font = ScreenManager.Font;
+
+            spriteBatch.Begin();
+
+            // Draw each menu entry in turn.
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                MenuEntry menuEntry = menuEntries[i];
+
+                bool isSelected = IsActive && (i == selectedEntry);
+
+                menuEntry.Draw(this, isSelected, gameTime);
+            }
+
+            // Make the menu slide into place during transitions, using a
+            // power curve to make things look more interesting (this makes
+            // the movement slow down as it nears the end).
+            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+            // Draw the menu title centered on the screen
+            Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
+            Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
+            Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
+            float titleScale = 1.25f;
+
+            titlePosition.Y -= transitionOffset * 100;
+
+            spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
+                                   titleOrigin, titleScale, SpriteEffects.None, 0);
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 156 - 170
GameStateManagement/Screens/MessageBoxScreen.cs → GameStateManagement/Core/Screens/MessageBoxScreen.cs

@@ -1,170 +1,156 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MessageBoxScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// A popup message box screen, used to display "are you sure?"
-    /// confirmation messages.
-    /// </summary>
-    class MessageBoxScreen : GameScreen
-    {
-        #region Fields
-
-        string message;
-        Texture2D gradientTexture;
-
-        #endregion
-
-        #region Events
-
-        public event EventHandler<PlayerIndexEventArgs> Accepted;
-        public event EventHandler<PlayerIndexEventArgs> Cancelled;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor automatically includes the standard "A=ok, B=cancel"
-        /// usage text prompt.
-        /// </summary>
-        public MessageBoxScreen(string message)
-            : this(message, true)
-        { }
-
-
-        /// <summary>
-        /// Constructor lets the caller specify whether to include the standard
-        /// "A=ok, B=cancel" usage text prompt.
-        /// </summary>
-        public MessageBoxScreen(string message, bool includeUsageText)
-        {
-            const string usageText = "\nA button, Space, Enter = ok" +
-                                     "\nB button, Esc = cancel"; 
-            
-            if (includeUsageText)
-                this.message = message + usageText;
-            else
-                this.message = message;
-
-            IsPopup = true;
-
-            TransitionOnTime = TimeSpan.FromSeconds(0.2);
-            TransitionOffTime = TimeSpan.FromSeconds(0.2);
-        }
-
-
-        /// <summary>
-        /// Loads graphics content for this screen. This uses the shared ContentManager
-        /// provided by the Game class, so the content will remain loaded forever.
-        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
-        /// it will just get back another reference to the already loaded data.
-        /// </summary>
-        public override void LoadContent()
-        {
-            ContentManager content = ScreenManager.Game.Content;
-
-            gradientTexture = content.Load<Texture2D>("gradient");
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Responds to user input, accepting or cancelling the message box.
-        /// </summary>
-        public override void HandleInput(InputState input)
-        {
-            PlayerIndex playerIndex;
-
-            // We pass in our ControllingPlayer, which may either be null (to
-            // accept input from any player) or a specific index. If we pass a null
-            // controlling player, the InputState helper returns to us which player
-            // actually provided the input. We pass that through to our Accepted and
-            // Cancelled events, so they can tell which player triggered them.
-            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
-            {
-                // Raise the accepted event, then exit the message box.
-                if (Accepted != null)
-                    Accepted(this, new PlayerIndexEventArgs(playerIndex));
-
-                ExitScreen();
-            }
-            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
-            {
-                // Raise the cancelled event, then exit the message box.
-                if (Cancelled != null)
-                    Cancelled(this, new PlayerIndexEventArgs(playerIndex));
-
-                ExitScreen();
-            }
-        }
-
-
-        #endregion
-
-        #region Draw
-
-
-        /// <summary>
-        /// Draws the message box.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-            SpriteFont font = ScreenManager.Font;
-
-            // Darken down any other screens that were drawn beneath the popup.
-            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);
-
-            // Center the message text in the viewport.
-            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
-            Vector2 textSize = font.MeasureString(message);
-            Vector2 textPosition = (viewportSize - textSize) / 2;
-
-            // The background includes a border somewhat larger than the text itself.
-            const int hPad = 32;
-            const int vPad = 16;
-
-            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
-                                                          (int)textPosition.Y - vPad,
-                                                          (int)textSize.X + hPad * 2,
-                                                          (int)textSize.Y + vPad * 2);
-
-            // Fade the popup alpha during transitions.
-            Color color = Color.White * TransitionAlpha;
-
-            spriteBatch.Begin();
-
-            // Draw the background rectangle.
-            spriteBatch.Draw(gradientTexture, backgroundRectangle, color);
-
-            // Draw the message box text.
-            spriteBatch.DrawString(font, message, textPosition, color);
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MessageBoxScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// A popup message box screen, used to display "are you sure?"
+    /// confirmation messages.
+    /// </summary>
+    class MessageBoxScreen : GameScreen
+    {
+
+        string message;
+        Texture2D gradientTexture;
+
+
+
+        public event EventHandler<PlayerIndexEventArgs> Accepted;
+        public event EventHandler<PlayerIndexEventArgs> Cancelled;
+
+
+
+
+        /// <summary>
+        /// Constructor automatically includes the standard "A=ok, B=cancel"
+        /// usage text prompt.
+        /// </summary>
+        public MessageBoxScreen(string message)
+            : this(message, true)
+        { }
+
+
+        /// <summary>
+        /// Constructor lets the caller specify whether to include the standard
+        /// "A=ok, B=cancel" usage text prompt.
+        /// </summary>
+        public MessageBoxScreen(string message, bool includeUsageText)
+        {
+            const string usageText = "\nA button, Space, Enter = ok" +
+                                     "\nB button, Esc = cancel"; 
+            
+            if (includeUsageText)
+                this.message = message + usageText;
+            else
+                this.message = message;
+
+            IsPopup = true;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.2);
+            TransitionOffTime = TimeSpan.FromSeconds(0.2);
+        }
+
+
+        /// <summary>
+        /// Loads graphics content for this screen. This uses the shared ContentManager
+        /// provided by the Game class, so the content will remain loaded forever.
+        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
+        /// it will just get back another reference to the already loaded data.
+        /// </summary>
+        public override void LoadContent()
+        {
+            ContentManager content = ScreenManager.Game.Content;
+
+            gradientTexture = content.Load<Texture2D>("gradient");
+        }
+
+
+
+
+
+        /// <summary>
+        /// Responds to user input, accepting or cancelling the message box.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            PlayerIndex playerIndex;
+
+            // We pass in our ControllingPlayer, which may either be null (to
+            // accept input from any player) or a specific index. If we pass a null
+            // controlling player, the InputState helper returns to us which player
+            // actually provided the input. We pass that through to our Accepted and
+            // Cancelled events, so they can tell which player triggered them.
+            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
+            {
+                // Raise the accepted event, then exit the message box.
+                if (Accepted != null)
+                    Accepted(this, new PlayerIndexEventArgs(playerIndex));
+
+                ExitScreen();
+            }
+            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
+            {
+                // Raise the cancelled event, then exit the message box.
+                if (Cancelled != null)
+                    Cancelled(this, new PlayerIndexEventArgs(playerIndex));
+
+                ExitScreen();
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Draws the message box.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            SpriteFont font = ScreenManager.Font;
+
+            // Darken down any other screens that were drawn beneath the popup.
+            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);
+
+            // Center the message text in the viewport.
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+            Vector2 textSize = font.MeasureString(message);
+            Vector2 textPosition = (viewportSize - textSize) / 2;
+
+            // The background includes a border somewhat larger than the text itself.
+            const int hPad = 32;
+            const int vPad = 16;
+
+            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
+                                                          (int)textPosition.Y - vPad,
+                                                          (int)textSize.X + hPad * 2,
+                                                          (int)textSize.Y + vPad * 2);
+
+            // Fade the popup alpha during transitions.
+            Color color = Color.White * TransitionAlpha;
+
+            spriteBatch.Begin();
+
+            // Draw the background rectangle.
+            spriteBatch.Draw(gradientTexture, backgroundRectangle, color);
+
+            // Draw the message box text.
+            spriteBatch.DrawString(font, message, textPosition, color);
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 139 - 149
GameStateManagement/Screens/OptionsMenuScreen.cs → GameStateManagement/Core/Screens/OptionsMenuScreen.cs

@@ -1,149 +1,139 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// OptionsMenuScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// The options screen is brought up over the top of the main menu
-    /// screen, and gives the user a chance to configure the game
-    /// in various hopefully useful ways.
-    /// </summary>
-    class OptionsMenuScreen : MenuScreen
-    {
-        #region Fields
-
-        MenuEntry ungulateMenuEntry;
-        MenuEntry languageMenuEntry;
-        MenuEntry frobnicateMenuEntry;
-        MenuEntry elfMenuEntry;
-
-        enum Ungulate
-        {
-            BactrianCamel,
-            Dromedary,
-            Llama,
-        }
-
-        static Ungulate currentUngulate = Ungulate.Dromedary;
-
-        static string[] languages = { "C#", "French", "Deoxyribonucleic acid" };
-        static int currentLanguage = 0;
-
-        static bool frobnicate = true;
-
-        static int elf = 23;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public OptionsMenuScreen()
-            : base("Options")
-        {
-            // Create our menu entries.
-            ungulateMenuEntry = new MenuEntry(string.Empty);
-            languageMenuEntry = new MenuEntry(string.Empty);
-            frobnicateMenuEntry = new MenuEntry(string.Empty);
-            elfMenuEntry = new MenuEntry(string.Empty);
-
-            SetMenuEntryText();
-
-            MenuEntry back = new MenuEntry("Back");
-
-            // Hook up menu event handlers.
-            ungulateMenuEntry.Selected += UngulateMenuEntrySelected;
-            languageMenuEntry.Selected += LanguageMenuEntrySelected;
-            frobnicateMenuEntry.Selected += FrobnicateMenuEntrySelected;
-            elfMenuEntry.Selected += ElfMenuEntrySelected;
-            back.Selected += OnCancel;
-            
-            // Add entries to the menu.
-            MenuEntries.Add(ungulateMenuEntry);
-            MenuEntries.Add(languageMenuEntry);
-            MenuEntries.Add(frobnicateMenuEntry);
-            MenuEntries.Add(elfMenuEntry);
-            MenuEntries.Add(back);
-        }
-
-
-        /// <summary>
-        /// Fills in the latest values for the options screen menu text.
-        /// </summary>
-        void SetMenuEntryText()
-        {
-            ungulateMenuEntry.Text = "Preferred ungulate: " + currentUngulate;
-            languageMenuEntry.Text = "Language: " + languages[currentLanguage];
-            frobnicateMenuEntry.Text = "Frobnicate: " + (frobnicate ? "on" : "off");
-            elfMenuEntry.Text = "elf: " + elf;
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Event handler for when the Ungulate menu entry is selected.
-        /// </summary>
-        void UngulateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            currentUngulate++;
-
-            if (currentUngulate > Ungulate.Llama)
-                currentUngulate = 0;
-
-            SetMenuEntryText();
-        }
-
-
-        /// <summary>
-        /// Event handler for when the Language menu entry is selected.
-        /// </summary>
-        void LanguageMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            currentLanguage = (currentLanguage + 1) % languages.Length;
-
-            SetMenuEntryText();
-        }
-
-
-        /// <summary>
-        /// Event handler for when the Frobnicate menu entry is selected.
-        /// </summary>
-        void FrobnicateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            frobnicate = !frobnicate;
-
-            SetMenuEntryText();
-        }
-
-
-        /// <summary>
-        /// Event handler for when the Elf menu entry is selected.
-        /// </summary>
-        void ElfMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            elf++;
-
-            SetMenuEntryText();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// OptionsMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// The options screen is brought up over the top of the main menu
+    /// screen, and gives the user a chance to configure the game
+    /// in various hopefully useful ways.
+    /// </summary>
+    class OptionsMenuScreen : MenuScreen
+    {
+
+        MenuEntry ungulateMenuEntry;
+        MenuEntry languageMenuEntry;
+        MenuEntry frobnicateMenuEntry;
+        MenuEntry elfMenuEntry;
+
+        enum Ungulate
+        {
+            BactrianCamel,
+            Dromedary,
+            Llama,
+        }
+
+        static Ungulate currentUngulate = Ungulate.Dromedary;
+
+        static string[] languages = { "C#", "French", "Deoxyribonucleic acid" };
+        static int currentLanguage = 0;
+
+        static bool frobnicate = true;
+
+        static int elf = 23;
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public OptionsMenuScreen()
+            : base("Options")
+        {
+            // Create our menu entries.
+            ungulateMenuEntry = new MenuEntry(string.Empty);
+            languageMenuEntry = new MenuEntry(string.Empty);
+            frobnicateMenuEntry = new MenuEntry(string.Empty);
+            elfMenuEntry = new MenuEntry(string.Empty);
+
+            SetMenuEntryText();
+
+            MenuEntry back = new MenuEntry("Back");
+
+            // Hook up menu event handlers.
+            ungulateMenuEntry.Selected += UngulateMenuEntrySelected;
+            languageMenuEntry.Selected += LanguageMenuEntrySelected;
+            frobnicateMenuEntry.Selected += FrobnicateMenuEntrySelected;
+            elfMenuEntry.Selected += ElfMenuEntrySelected;
+            back.Selected += OnCancel;
+            
+            // Add entries to the menu.
+            MenuEntries.Add(ungulateMenuEntry);
+            MenuEntries.Add(languageMenuEntry);
+            MenuEntries.Add(frobnicateMenuEntry);
+            MenuEntries.Add(elfMenuEntry);
+            MenuEntries.Add(back);
+        }
+
+
+        /// <summary>
+        /// Fills in the latest values for the options screen menu text.
+        /// </summary>
+        void SetMenuEntryText()
+        {
+            ungulateMenuEntry.Text = "Preferred ungulate: " + currentUngulate;
+            languageMenuEntry.Text = "Language: " + languages[currentLanguage];
+            frobnicateMenuEntry.Text = "Frobnicate: " + (frobnicate ? "on" : "off");
+            elfMenuEntry.Text = "elf: " + elf;
+        }
+
+
+
+
+
+        /// <summary>
+        /// Event handler for when the Ungulate menu entry is selected.
+        /// </summary>
+        void UngulateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            currentUngulate++;
+
+            if (currentUngulate > Ungulate.Llama)
+                currentUngulate = 0;
+
+            SetMenuEntryText();
+        }
+
+
+        /// <summary>
+        /// Event handler for when the Language menu entry is selected.
+        /// </summary>
+        void LanguageMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            currentLanguage = (currentLanguage + 1) % languages.Length;
+
+            SetMenuEntryText();
+        }
+
+
+        /// <summary>
+        /// Event handler for when the Frobnicate menu entry is selected.
+        /// </summary>
+        void FrobnicateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            frobnicate = !frobnicate;
+
+            SetMenuEntryText();
+        }
+
+
+        /// <summary>
+        /// Event handler for when the Elf menu entry is selected.
+        /// </summary>
+        void ElfMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            elf++;
+
+            SetMenuEntryText();
+        }
+
+
+    }
+}

+ 71 - 79
GameStateManagement/Screens/PauseMenuScreen.cs → GameStateManagement/Core/Screens/PauseMenuScreen.cs

@@ -1,79 +1,71 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// PauseMenuScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// The pause menu comes up over the top of the game,
-    /// giving the player options to resume or quit.
-    /// </summary>
-    class PauseMenuScreen : MenuScreen
-    {
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public PauseMenuScreen()
-            : base("Paused")
-        {
-            // Create our menu entries.
-            MenuEntry resumeGameMenuEntry = new MenuEntry("Resume Game");
-            MenuEntry quitGameMenuEntry = new MenuEntry("Quit Game");
-            
-            // Hook up menu event handlers.
-            resumeGameMenuEntry.Selected += OnCancel;
-            quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
-
-            // Add entries to the menu.
-            MenuEntries.Add(resumeGameMenuEntry);
-            MenuEntries.Add(quitGameMenuEntry);
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Event handler for when the Quit Game menu entry is selected.
-        /// </summary>
-        void QuitGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
-        {
-            const string message = "Are you sure you want to quit this game?";
-
-            MessageBoxScreen confirmQuitMessageBox = new MessageBoxScreen(message);
-
-            confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;
-
-            ScreenManager.AddScreen(confirmQuitMessageBox, ControllingPlayer);
-        }
-
-
-        /// <summary>
-        /// Event handler for when the user selects ok on the "are you sure
-        /// you want to quit" message box. This uses the loading screen to
-        /// transition from the game back to the main menu screen.
-        /// </summary>
-        void ConfirmQuitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
-        {
-            LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
-                                                           new MainMenuScreen());
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// PauseMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// The pause menu comes up over the top of the game,
+    /// giving the player options to resume or quit.
+    /// </summary>
+    class PauseMenuScreen : MenuScreen
+    {
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public PauseMenuScreen()
+            : base("Paused")
+        {
+            // Create our menu entries.
+            MenuEntry resumeGameMenuEntry = new MenuEntry("Resume Game");
+            MenuEntry quitGameMenuEntry = new MenuEntry("Quit Game");
+            
+            // Hook up menu event handlers.
+            resumeGameMenuEntry.Selected += OnCancel;
+            quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
+
+            // Add entries to the menu.
+            MenuEntries.Add(resumeGameMenuEntry);
+            MenuEntries.Add(quitGameMenuEntry);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Event handler for when the Quit Game menu entry is selected.
+        /// </summary>
+        void QuitGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+        {
+            const string message = "Are you sure you want to quit this game?";
+
+            MessageBoxScreen confirmQuitMessageBox = new MessageBoxScreen(message);
+
+            confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;
+
+            ScreenManager.AddScreen(confirmQuitMessageBox, ControllingPlayer);
+        }
+
+
+        /// <summary>
+        /// Event handler for when the user selects ok on the "are you sure
+        /// you want to quit" message box. This uses the loading screen to
+        /// transition from the game back to the main menu screen.
+        /// </summary>
+        void ConfirmQuitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+        {
+            LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
+                                                           new MainMenuScreen());
+        }
+
+
+    }
+}

+ 38 - 42
GameStateManagement/Screens/PlayerIndexEventArgs.cs → GameStateManagement/Core/Screens/PlayerIndexEventArgs.cs

@@ -1,42 +1,38 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// PlayerIndexEventArgs.cs
-//
-// XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// Custom event argument which includes the index of the player who
-    /// triggered the event. This is used by the MenuEntry.Selected event.
-    /// </summary>
-    class PlayerIndexEventArgs : EventArgs
-    {
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public PlayerIndexEventArgs(PlayerIndex playerIndex)
-        {
-            this.playerIndex = playerIndex;
-        }
-
-
-        /// <summary>
-        /// Gets the index of the player who triggered this event.
-        /// </summary>
-        public PlayerIndex PlayerIndex
-        {
-            get { return playerIndex; }
-        }
-
-        PlayerIndex playerIndex;
-    }
-}
+//-----------------------------------------------------------------------------
+// PlayerIndexEventArgs.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement
+{
+    /// <summary>
+    /// Custom event argument which includes the index of the player who
+    /// triggered the event. This is used by the MenuEntry.Selected event.
+    /// </summary>
+    class PlayerIndexEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public PlayerIndexEventArgs(PlayerIndex playerIndex)
+        {
+            this.playerIndex = playerIndex;
+        }
+
+
+        /// <summary>
+        /// Gets the index of the player who triggered this event.
+        /// </summary>
+        public PlayerIndex PlayerIndex
+        {
+            get { return playerIndex; }
+        }
+
+        PlayerIndex playerIndex;
+    }
+}

+ 0 - 104
GameStateManagement/GameStateManagement.MacOS.csproj

@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{4AD6BC7A-DB9A-4A6F-9EE2-DAD9B0BBA2A8}</ProjectGuid>
-    <ProjectTypeGuids>{948B3504-5B70-4649-8FE4-BDE1FB46EC69};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>GameStateManagement</RootNamespace>
-    <AssemblyName>GameStateManagement</AssemblyName>
-    <SuppressXamMacUpsell>True</SuppressXamMacUpsell>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>True</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;MONOMAC</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>False</ConsolePause>
-    <EnableCodeSigning>False</EnableCodeSigning>
-    <CreatePackage>False</CreatePackage>
-    <EnablePackageSigning>False</EnablePackageSigning>
-    <IncludeMonoRuntime>False</IncludeMonoRuntime>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>False</ConsolePause>
-    <DefineConstants>MONOMAC</DefineConstants>
-    <EnableCodeSigning>False</EnableCodeSigning>
-    <CreatePackage>False</CreatePackage>
-    <EnablePackageSigning>False</EnablePackageSigning>
-    <IncludeMonoRuntime>False</IncludeMonoRuntime>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="MonoMac" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Info.plist">
-    </None>
-    <None Include="Background.png" />
-    <None Include="Game.ico" />
-    <None Include="Content\background.png" />
-    <None Include="Content\blank.png" />
-    <None Include="Content\gamefont.spritefont" />
-    <None Include="Content\gradient.png" />
-    <None Include="Content\menufont.spritefont" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
-  <ItemGroup>
-    <Compile Include="Game.cs" />
-    <Compile Include="ScreenManager\GameScreen.cs" />
-    <Compile Include="ScreenManager\InputState.cs" />
-    <Compile Include="ScreenManager\ScreenManager.cs" />
-    <Compile Include="Screens\BackgroundScreen.cs" />
-    <Compile Include="Screens\GameplayScreen.cs" />
-    <Compile Include="Screens\LoadingScreen.cs" />
-    <Compile Include="Screens\MainMenuScreen.cs" />
-    <Compile Include="Screens\MenuEntry.cs" />
-    <Compile Include="Screens\MenuScreen.cs" />
-    <Compile Include="Screens\MessageBoxScreen.cs" />
-    <Compile Include="Screens\OptionsMenuScreen.cs" />
-    <Compile Include="Screens\PauseMenuScreen.cs" />
-    <Compile Include="Screens\PlayerIndexEventArgs.cs" />
-    <Compile Include="Program.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Content\" />
-    <Folder Include="ScreenManager\" />
-    <Folder Include="Screens\" />
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\background.xnb" />
-    <Content Include="Content\blank.xnb" />
-    <Content Include="Content\gamefont.xnb" />
-    <Content Include="Content\gradient.xnb" />
-    <Content Include="Content\menufont.xnb" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.MacOS.csproj">
-      <Project>{36C538E6-C32A-4A8D-A39C-566173D7118E}</Project>
-      <Name>MonoGame.Framework.MacOS</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\ThirdParty\Lidgren.Network\Lidgren.Network.MacOS.csproj">
-      <Project>{AE483C29-042E-4226-BA52-D247CE7676DA}</Project>
-      <Name>Lidgren.Network.MacOS</Name>
-    </ProjectReference>
-  </ItemGroup>
-</Project>

+ 0 - 141
GameStateManagement/GameStateManagement.iOS.csproj

@@ -1,141 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
-  <PropertyGroup>
-    <ProjectGuid>{B1A596F8-B26C-4826-99D1-94C9327AB586}</ProjectGuid>
-    <ProjectTypeGuids>{6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
-    <ProductVersion>9.0.21022</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>GameStateManagement</RootNamespace>
-    <Thumbnail>GameThumbnail.png</Thumbnail>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
-    <DebugSymbols>True</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
-    <DefineConstants>DEBUG;IPHONE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
-    <MtouchLink>None</MtouchLink>
-    <MtouchDebug>True</MtouchDebug>
-    <MtouchI18n />
-    <MtouchUseArmv7>false</MtouchUseArmv7>
-    <AssemblyName>GameStateManagement</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
-    <DebugType>none</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\iPhoneSimulator\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <DefineConstants>IPHONE</DefineConstants>
-    <WarningLevel>4</WarningLevel>
-    <MtouchI18n />
-    <MtouchUseArmv7>false</MtouchUseArmv7>
-    <AssemblyName>GameStateManagement</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
-    <DebugSymbols>True</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\iPhone\Debug</OutputPath>
-    <DefineConstants>DEBUG;IPHONE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <MtouchDebug>True</MtouchDebug>
-    <MtouchI18n />
-    <MtouchSdkVersion>4.0</MtouchSdkVersion>
-    <MtouchUseArmv7>false</MtouchUseArmv7>
-    <AssemblyName>GameStateManagement</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
-    <DebugType>none</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\iPhone\Release</OutputPath>
-    <DefineConstants>IPHONE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <MtouchI18n />
-    <CodesignKey>iPhone Developer</CodesignKey>
-    <MtouchSdkVersion>4.0</MtouchSdkVersion>
-    <MtouchUseArmv7>false</MtouchUseArmv7>
-    <AssemblyName>GameStateManagement</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <WarningLevel>4</WarningLevel>
-    <AssemblyName>MonoGameSamplesGameStateManagement</AssemblyName>
-    <MtouchUseArmv7>false</MtouchUseArmv7>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <WarningLevel>4</WarningLevel>
-    <AssemblyName>MonoGameSamplesGameStateManagement</AssemblyName>
-    <MtouchUseArmv7>false</MtouchUseArmv7>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Core" />
-    <Reference Include="monotouch" />
-  </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Content\" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Game.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="ScreenManager\GameScreen.cs" />
-    <Compile Include="ScreenManager\InputState.cs" />
-    <Compile Include="ScreenManager\ScreenManager.cs" />
-    <Compile Include="Screens\BackgroundScreen.cs" />
-    <Compile Include="Screens\GameplayScreen.cs" />
-    <Compile Include="Screens\LoadingScreen.cs" />
-    <Compile Include="Screens\MainMenuScreen.cs" />
-    <Compile Include="Screens\MenuEntry.cs" />
-    <Compile Include="Screens\MenuScreen.cs" />
-    <Compile Include="Screens\MessageBoxScreen.cs" />
-    <Compile Include="Screens\OptionsMenuScreen.cs" />
-    <Compile Include="Screens\PauseMenuScreen.cs" />
-    <Compile Include="Screens\PlayerIndexEventArgs.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="GameThumbnail.png" />
-    <None Include="Info.plist" />
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\background.png">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\blank.png">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Default.png">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\gamefont.xnb">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\gradient.png">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\menufont.xnb" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>

+ 37 - 17
GameStateManagement/GameStateManagement.sln

@@ -1,29 +1,49 @@
 
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameStateManagement", "GameStateManagement.csproj", "{4AD6BC7A-DB9A-4A6F-9EE2-DAD9B0BBA2A8}"
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32106.194
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameStateManagement.Core", "GameStateManagement.Core\GameStateManagement.Core.csproj", "{E3CBEA41-1B9A-4D84-B0A2-2A877C8B9ADE}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Framework.MacOS", "..\..\..\..\..\..\..\Users\Jimmy\Public\Share\MonoMacSource\kjpgit\MonoGame\MonoGame.Framework\MonoGame.Framework.MacOS.csproj", "{36C538E6-C32A-4A8D-A39C-566173D7118E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameStateManagement.DesktopGL", "GameStateManagement.DesktopGL.csproj", "{F5A3C9E7-8B97-4F42-8A5D-2C7B4F7E9E1A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameStateManagement.WindowsDX", "GameStateManagement.WindowsDX\GameStateManagement.WindowsDX.csproj", "{1E2B4A6C-3D8F-4E9F-B5A1-7F8E9B2C4D5F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameStateManagement.Android", "GameStateManagement.Android\GameStateManagement.Android.csproj", "{8F2A3B7E-4C9D-4E1F-A6B2-9E8F7D3C5A1B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameStateManagement.iOS", "GameStateManagement.iOS.csproj", "{B1A596F8-B26C-4826-99D1-94C9327AB586}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
-		Distribution|Any CPU = Distribution|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Distribution|Any CPU.ActiveCfg = Distribution|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Distribution|Any CPU.Build.0 = Distribution|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4AD6BC7A-DB9A-4A6F-9EE2-DAD9B0BBA2A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4AD6BC7A-DB9A-4A6F-9EE2-DAD9B0BBA2A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4AD6BC7A-DB9A-4A6F-9EE2-DAD9B0BBA2A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4AD6BC7A-DB9A-4A6F-9EE2-DAD9B0BBA2A8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E3CBEA41-1B9A-4D84-B0A2-2A877C8B9ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E3CBEA41-1B9A-4D84-B0A2-2A877C8B9ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E3CBEA41-1B9A-4D84-B0A2-2A877C8B9ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E3CBEA41-1B9A-4D84-B0A2-2A877C8B9ADE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F5A3C9E7-8B97-4F42-8A5D-2C7B4F7E9E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F5A3C9E7-8B97-4F42-8A5D-2C7B4F7E9E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F5A3C9E7-8B97-4F42-8A5D-2C7B4F7E9E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F5A3C9E7-8B97-4F42-8A5D-2C7B4F7E9E1A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1E2B4A6C-3D8F-4E9F-B5A1-7F8E9B2C4D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1E2B4A6C-3D8F-4E9F-B5A1-7F8E9B2C4D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1E2B4A6C-3D8F-4E9F-B5A1-7F8E9B2C4D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1E2B4A6C-3D8F-4E9F-B5A1-7F8E9B2C4D5F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8F2A3B7E-4C9D-4E1F-A6B2-9E8F7D3C5A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8F2A3B7E-4C9D-4E1F-A6B2-9E8F7D3C5A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8F2A3B7E-4C9D-4E1F-A6B2-9E8F7D3C5A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8F2A3B7E-4C9D-4E1F-A6B2-9E8F7D3C5A1B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B1A596F8-B26C-4826-99D1-94C9327AB586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B1A596F8-B26C-4826-99D1-94C9327AB586}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B1A596F8-B26C-4826-99D1-94C9327AB586}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B1A596F8-B26C-4826-99D1-94C9327AB586}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
 	EndGlobalSection
-	GlobalSection(MonoDevelopProperties) = preSolution
-		StartupItem = GameStateManagement.csproj
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {A5B7C9E1-2F4D-4A3B-8E7F-1C9D5A6B8E2F}
 	EndGlobalSection
 EndGlobal

+ 15 - 0
GameStateManagement/Platforms/Android/AndroidManifest.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.companyname.gamestatemanagement"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
+    <application android:label="GameStateManagement" android:icon="@mipmap/icon">
+        <activity android:name="md5b60ffeb829f638581ab2bb9b1a7f4f3f.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>

+ 48 - 0
GameStateManagement/Platforms/Android/GameStateManagement.Android.csproj

@@ -0,0 +1,48 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-android</TargetFramework>
+    <RollForward>Major</RollForward>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <Title>Game State Management</Title>
+    <Product>Game State Management</Product>
+    <Description>This sample shows how to manage the transitions between different menus and gameplay states.</Description>
+    <Company>Microsoft</Company>
+    <Copyright>Copyright © Microsoft 2007</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.Android" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../Core/GameStateManagement.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\..\CompiledContent\Android\Content\Fonts\menufont.xnb" Link="Content\menufont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Android\Content\Fonts\gamefont.xnb" Link="Content\gamefont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Android\Content\Textures\blank.xnb" Link="Content\blank.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Android\Content\Textures\background.xnb" Link="Content\background.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Android\Content\Textures\gradient.xnb" Link="Content\gradient.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 19 - 0
GameStateManagement/Platforms/Android/MainActivity.cs

@@ -0,0 +1,19 @@
+using Android.App;
+using Android.OS;
+using Android.Content.PM;
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement.Android
+{
+    [Activity(Label = "GameStateManagement", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize)]
+    public class MainActivity : AndroidGameActivity
+    {
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+            var g = new GameStateManagementGame();
+            SetContentView((View)g.Services.GetService(typeof(View)));
+            g.Run();
+        }
+    }
+}

+ 48 - 0
GameStateManagement/Platforms/Desktop/GameStateManagement.DesktopGL.csproj

@@ -0,0 +1,48 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <RollForward>Major</RollForward>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <Title>Game State Management</Title>
+    <Product>Game State Management</Product>
+    <Description>This sample shows how to manage the transitions between different menus and gameplay states.</Description>
+    <Company>Microsoft</Company>
+    <Copyright>Copyright © Microsoft 2007</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../Core/GameStateManagement.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Fonts\menufont.xnb" Link="Content\menufont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Fonts\gamefont.xnb" Link="Content\gamefont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Textures\blank.xnb" Link="Content\blank.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Textures\background.xnb" Link="Content\background.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Textures\gradient.xnb" Link="Content\gradient.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 14 - 0
GameStateManagement/Platforms/Desktop/Program.cs

@@ -0,0 +1,14 @@
+using System;
+
+namespace GameStateManagement.DesktopGL
+{
+    public static class Program
+    {
+        [STAThread]
+        static void Main()
+        {
+            using (var game = new GameStateManagementGame())
+                game.Run();
+        }
+    }
+}

+ 50 - 0
GameStateManagement/Platforms/Windows/GameStateManagement.Windows.csproj

@@ -0,0 +1,50 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>net8.0-windows</TargetFramework>
+    <RollForward>Major</RollForward>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+    <UseWindowsForms>true</UseWindowsForms>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <Title>Game State Management</Title>
+    <Product>Game State Management</Product>
+    <Description>This sample shows how to manage the transitions between different menus and gameplay states.</Description>
+    <Company>Microsoft</Company>
+    <Copyright>Copyright © Microsoft 2007</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+    <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.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../Core/GameStateManagement.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Fonts\menufont.xnb" Link="Content\menufont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Fonts\gamefont.xnb" Link="Content\gamefont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Textures\blank.xnb" Link="Content\blank.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Textures\background.xnb" Link="Content\background.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\Windows\Content\Textures\gradient.xnb" Link="Content\gradient.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 14 - 0
GameStateManagement/Platforms/Windows/Program.cs

@@ -0,0 +1,14 @@
+using System;
+
+namespace GameStateManagement.WindowsDX
+{
+    public static class Program
+    {
+        [STAThread]
+        static void Main()
+        {
+            using (var game = new GameStateManagementGame())
+                game.Run();
+        }
+    }
+}

+ 19 - 0
GameStateManagement/Platforms/iOS/AppDelegate.cs

@@ -0,0 +1,19 @@
+using Foundation;
+using UIKit;
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement.iOS
+{
+    [Register("AppDelegate")]
+    public class AppDelegate : UIApplicationDelegate
+    {
+        private GameStateManagementGame game;
+
+        public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
+        {
+            game = new GameStateManagementGame();
+            game.Run();
+            return true;
+        }
+    }
+}

+ 48 - 0
GameStateManagement/Platforms/iOS/GameStateManagement.iOS.csproj

@@ -0,0 +1,48 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-ios</TargetFramework>
+    <RollForward>Major</RollForward>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <Title>Game State Management</Title>
+    <Product>Game State Management</Product>
+    <Description>This sample shows how to manage the transitions between different menus and gameplay states.</Description>
+    <Company>Microsoft</Company>
+    <Copyright>Copyright © Microsoft 2007</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.iOS" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../Core/GameStateManagement.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\..\CompiledContent\iOS\Content\Fonts\menufont.xnb" Link="Content\menufont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\iOS\Content\Fonts\gamefont.xnb" Link="Content\gamefont.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\iOS\Content\Textures\blank.xnb" Link="Content\blank.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\iOS\Content\Textures\background.xnb" Link="Content\background.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\..\CompiledContent\iOS\Content\Textures\gradient.xnb" Link="Content\gradient.xnb">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 0 - 0
GameStateManagement/Info.plist → GameStateManagement/Platforms/iOS/Info.plist


+ 13 - 0
GameStateManagement/Platforms/iOS/Program.cs

@@ -0,0 +1,13 @@
+using UIKit;
+
+namespace GameStateManagement.iOS
+{
+    public class Application
+    {
+        // This is the main entry point of the application.
+        static void Main(string[] args)
+        {
+            UIApplication.Main(args, null, typeof(AppDelegate));
+        }
+    }
+}

+ 0 - 115
GameStateManagement/Program.cs

@@ -1,115 +0,0 @@
-#region Using Statements
-using System;
-#if MONOMAC
-using MonoMac.AppKit;
-using MonoMac.Foundation;
-#elif IPHONE
-using MonoTouch.Foundation;
-using MonoTouch.UIKit;
-using Microsoft.Xna;
-using Microsoft.Xna.Framework.Media;
-#elif MONOMAC
-
-#endif
-#endregion
-
-namespace GameStateManagement
-{
-    #region Entry Point
-#if MONOMAC
-	class Program
-	{
-		static void Main (string[] args)
-		{
-			NSApplication.Init ();
-
-			using (var p = new NSAutoreleasePool ()) {
-				NSApplication.SharedApplication.Delegate = new AppDelegate ();			
-
-				NSApplication.Main (args);
-			}
-		}
-	}
-
-	class AppDelegate : NSApplicationDelegate
-	{
-		private GameStateManagementGame game;
-
-		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
-		{
-			game = new GameStateManagementGame ();
-			game.Run();
-		}
-
-		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
-		{
-			return true;
-		}
-	}
-#elif IPHONE
-    [Register("AppDelegate")]
-    class Program : UIApplicationDelegate
-    {
-        GameStateManagementGame game;
-        public override void FinishedLaunching(UIApplication app)
-        {
-            // Fun begins..
-            game = new GameStateManagementGame();
-            game.Run();
-        }
-
-        /// <summary>
-        /// The main entry point for the application.
-        /// </summary>
-        static void Main(string[] args)
-        {
-            UIApplication.Main(args, null, "AppDelegate");
-        }
-    }    
-#elif MONOMAC
-	static class Program
-	{	
-		/// <summary>
-		/// The main entry point for the application.
-		/// </summary>
-		static void Main (string[] args)
-		{
-			MonoMac.AppKit.NSApplication.Init ();
-			
-			using (var p = new MonoMac.Foundation.NSAutoreleasePool ()) {
-				MonoMac.AppKit.NSApplication.SharedApplication.Delegate = new AppDelegate();
-				MonoMac.AppKit.NSApplication.Main(args);
-			}
-		}
-	}
-	
-	class AppDelegate : MonoMac.AppKit.NSApplicationDelegate
-	{
-		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
-		{
-			var game = new GameStateManagementGame();
-			game.Run();
-		}
-		
-		public override bool ApplicationShouldTerminateAfterLastWindowClosed (MonoMac.AppKit.NSApplication sender)
-		{
-			return true;
-		}
-	}
-#else
-    /// <summary>
-    /// The main entry point for the application.
-    /// </summary>
-    static class Program
-    {
-        static void Main()
-        {
-            using (GameStateManagementGame game = new GameStateManagementGame())
-            {
-                game.Run();
-            }
-        }
-    }    
-#endif
-    #endregion
-}

+ 0 - 33
GameStateManagement/Properties/AssemblyInfo.cs

@@ -1,33 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Game State Management")]
-[assembly: AssemblyProduct("Game State Management")]
-[assembly: AssemblyDescription("This sample shows how to manage the transitions between different menus and gameplay states.")]
-[assembly: AssemblyCompany("Microsoft")]
-
-[assembly: AssemblyCopyright("Copyright © Microsoft 2007")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("d2049bb7-2a0a-4c44-bb6f-4580d47c64fe")]
-
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-[assembly: AssemblyVersion("1.0.0.0")]

+ 46 - 0
GameStateManagement/README.md

@@ -0,0 +1,46 @@
+# Game State Management Sample
+
+This project demonstrates a cross-platform game state management system using MonoGame. It supports Windows (DirectX), DesktopGL, Android, and iOS platforms, with a shared core game logic project.
+
+## Project Structure
+
+- **/Core**: Shared game logic and screens
+- **/Platforms/Windows**: Windows (DirectX) entry point and project
+- **/Platforms/Desktop**: DesktopGL entry point and project
+- **/Platforms/Android**: Android entry point and project
+- **/Platforms/iOS**: iOS entry point and project
+
+## Building and Running
+
+### Prerequisites
+- .NET 8 SDK or later
+- MonoGame 3.8+ (NuGet packages are referenced in each platform project)
+- Platform-specific build tools (e.g., Android/iOS SDKs for mobile targets)
+
+### Windows (DirectX)
+```
+dotnet build Platforms/Windows/GameStateManagement.Windows.csproj
+```
+
+### DesktopGL
+```
+dotnet build Platforms/Desktop/GameStateManagement.DesktopGL.csproj
+```
+
+### Android
+```
+dotnet build Platforms/Android/GameStateManagement.Android.csproj
+```
+
+### iOS
+```
+dotnet build Platforms/iOS/GameStateManagement.iOS.csproj
+```
+
+## Notes
+- All platform projects reference the shared core logic in `/Core`.
+- Content pipeline warnings may appear if no MonoGame content is referenced. Add a `.mgcb` file if you need custom content.
+- For Android/iOS, ensure you have the required SDKs and emulators/simulators installed.
+
+## License
+This sample is based on the Microsoft XNA Community Game Platform samples.

+ 0 - 356
GameStateManagement/ScreenManager/GameScreen.cs

@@ -1,356 +0,0 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// GameScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Input.Touch;
-using System.IO;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// Enum describes the screen transition state.
-    /// </summary>
-    public enum ScreenState
-    {
-        TransitionOn,
-        Active,
-        TransitionOff,
-        Hidden,
-    }
-
-
-    /// <summary>
-    /// A screen is a single layer that has update and draw logic, and which
-    /// can be combined with other layers to build up a complex menu system.
-    /// For instance the main menu, the options menu, the "are you sure you
-    /// want to quit" message box, and the main game itself are all implemented
-    /// as screens.
-    /// </summary>
-    public abstract class GameScreen
-    {
-        #region Properties
-
-
-        /// <summary>
-        /// Normally when one screen is brought up over the top of another,
-        /// the first screen will transition off to make room for the new
-        /// one. This property indicates whether the screen is only a small
-        /// popup, in which case screens underneath it do not need to bother
-        /// transitioning off.
-        /// </summary>
-        public bool IsPopup
-        {
-            get { return isPopup; }
-            protected set { isPopup = value; }
-        }
-
-        bool isPopup = false;
-
-
-        /// <summary>
-        /// Indicates how long the screen takes to
-        /// transition on when it is activated.
-        /// </summary>
-        public TimeSpan TransitionOnTime
-        {
-            get { return transitionOnTime; }
-            protected set { transitionOnTime = value; }
-        }
-
-        TimeSpan transitionOnTime = TimeSpan.Zero;
-
-
-        /// <summary>
-        /// Indicates how long the screen takes to
-        /// transition off when it is deactivated.
-        /// </summary>
-        public TimeSpan TransitionOffTime
-        {
-            get { return transitionOffTime; }
-            protected set { transitionOffTime = value; }
-        }
-
-        TimeSpan transitionOffTime = TimeSpan.Zero;
-
-
-        /// <summary>
-        /// Gets the current position of the screen transition, ranging
-        /// from zero (fully active, no transition) to one (transitioned
-        /// fully off to nothing).
-        /// </summary>
-        public float TransitionPosition
-        {
-            get { return transitionPosition; }
-            protected set { transitionPosition = value; }
-        }
-
-        float transitionPosition = 1;
-
-
-        /// <summary>
-        /// Gets the current alpha of the screen transition, ranging
-        /// from 1 (fully active, no transition) to 0 (transitioned
-        /// fully off to nothing).
-        /// </summary>
-        public float TransitionAlpha
-        {
-            get { return 1f - TransitionPosition; }
-        }
-
-
-        /// <summary>
-        /// Gets the current screen transition state.
-        /// </summary>
-        public ScreenState ScreenState
-        {
-            get { return screenState; }
-            protected set { screenState = value; }
-        }
-
-        ScreenState screenState = ScreenState.TransitionOn;
-
-
-        /// <summary>
-        /// There are two possible reasons why a screen might be transitioning
-        /// off. It could be temporarily going away to make room for another
-        /// screen that is on top of it, or it could be going away for good.
-        /// This property indicates whether the screen is exiting for real:
-        /// if set, the screen will automatically remove itself as soon as the
-        /// transition finishes.
-        /// </summary>
-        public bool IsExiting
-        {
-            get { return isExiting; }
-            protected internal set { isExiting = value; }
-        }
-
-        bool isExiting = false;
-
-
-        /// <summary>
-        /// Checks whether this screen is active and can respond to user input.
-        /// </summary>
-        public bool IsActive
-        {
-            get
-            {
-                return !otherScreenHasFocus &&
-                       (screenState == ScreenState.TransitionOn ||
-                        screenState == ScreenState.Active);
-            }
-        }
-
-        bool otherScreenHasFocus;
-
-
-        /// <summary>
-        /// Gets the manager that this screen belongs to.
-        /// </summary>
-        public ScreenManager ScreenManager
-        {
-            get { return screenManager; }
-            internal set { screenManager = value; }
-        }
-
-        ScreenManager screenManager;
-
-
-        /// <summary>
-        /// Gets the index of the player who is currently controlling this screen,
-        /// or null if it is accepting input from any player. This is used to lock
-        /// the game to a specific player profile. The main menu responds to input
-        /// from any connected gamepad, but whichever player makes a selection from
-        /// this menu is given control over all subsequent screens, so other gamepads
-        /// are inactive until the controlling player returns to the main menu.
-        /// </summary>
-        public PlayerIndex? ControllingPlayer
-        {
-            get { return controllingPlayer; }
-            internal set { controllingPlayer = value; }
-        }
-
-        PlayerIndex? controllingPlayer;
-
-
-        /// <summary>
-        /// Gets the gestures the screen is interested in. Screens should be as specific
-        /// as possible with gestures to increase the accuracy of the gesture engine.
-        /// For example, most menus only need Tap or perhaps Tap and VerticalDrag to operate.
-        /// These gestures are handled by the ScreenManager when screens change and
-        /// all gestures are placed in the InputState passed to the HandleInput method.
-        /// </summary>
-        public GestureType EnabledGestures
-        {
-            get { return enabledGestures; }
-            protected set
-            {
-                enabledGestures = value;
-
-                // the screen manager handles this during screen changes, but
-                // if this screen is active and the gesture types are changing,
-                // we have to update the TouchPanel ourself.
-                if (ScreenState == ScreenState.Active)
-                {
-                    TouchPanel.EnabledGestures = value;
-                }
-            }
-        }
-
-        GestureType enabledGestures = GestureType.None;
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Load graphics content for the screen.
-        /// </summary>
-        public virtual void LoadContent() { }
-
-
-        /// <summary>
-        /// Unload content for the screen.
-        /// </summary>
-        public virtual void UnloadContent() { }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Allows the screen to run logic, such as updating the transition position.
-        /// Unlike HandleInput, this method is called regardless of whether the screen
-        /// is active, hidden, or in the middle of a transition.
-        /// </summary>
-        public virtual void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                      bool coveredByOtherScreen)
-        {
-            this.otherScreenHasFocus = otherScreenHasFocus;
-
-            if (isExiting)
-            {
-                // If the screen is going away to die, it should transition off.
-                screenState = ScreenState.TransitionOff;
-
-                if (!UpdateTransition(gameTime, transitionOffTime, 1))
-                {
-                    // When the transition finishes, remove the screen.
-                    ScreenManager.RemoveScreen(this);
-                }
-            }
-            else if (coveredByOtherScreen)
-            {
-                // If the screen is covered by another, it should transition off.
-                if (UpdateTransition(gameTime, transitionOffTime, 1))
-                {
-                    // Still busy transitioning.
-                    screenState = ScreenState.TransitionOff;
-                }
-                else
-                {
-                    // Transition finished!
-                    screenState = ScreenState.Hidden;
-                }
-            }
-            else
-            {
-                // Otherwise the screen should transition on and become active.
-                if (UpdateTransition(gameTime, transitionOnTime, -1))
-                {
-                    // Still busy transitioning.
-                    screenState = ScreenState.TransitionOn;
-                }
-                else
-                {
-                    // Transition finished!
-                    screenState = ScreenState.Active;
-                }
-            }
-        }
-
-
-        /// <summary>
-        /// Helper for updating the screen transition position.
-        /// </summary>
-        bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
-        {
-            // How much should we move by?
-            float transitionDelta;
-
-            if (time == TimeSpan.Zero)
-                transitionDelta = 1;
-            else
-                transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
-                                          time.TotalMilliseconds);
-
-            // Update the transition position.
-            transitionPosition += transitionDelta * direction;
-
-            // Did we reach the end of the transition?
-            if (((direction < 0) && (transitionPosition <= 0)) ||
-                ((direction > 0) && (transitionPosition >= 1)))
-            {
-                transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
-                return false;
-            }
-
-            // Otherwise we are still busy transitioning.
-            return true;
-        }
-
-
-        /// <summary>
-        /// Allows the screen to handle user input. Unlike Update, this method
-        /// is only called when the screen is active, and not when some other
-        /// screen has taken the focus.
-        /// </summary>
-        public virtual void HandleInput(InputState input) { }
-
-
-        /// <summary>
-        /// This is called when the screen should draw itself.
-        /// </summary>
-        public virtual void Draw(GameTime gameTime) { }
-
-
-        #endregion
-
-        #region Public Methods
-
-
-        /// <summary>
-        /// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
-        /// instantly kills the screen, this method respects the transition timings
-        /// and will give the screen a chance to gradually transition off.
-        /// </summary>
-        public void ExitScreen()
-        {
-            if (TransitionOffTime == TimeSpan.Zero)
-            {
-                // If the screen has a zero transition time, remove it immediately.
-                ScreenManager.RemoveScreen(this);
-            }
-            else
-            {
-                // Otherwise flag that it should transition off and then exit.
-                isExiting = true;
-            }
-        }
-
-
-        #endregion
-    }
-}

+ 0 - 237
GameStateManagement/ScreenManager/InputState.cs

@@ -1,237 +0,0 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// InputState.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Input.Touch;
-using System.Collections.Generic;
-#endregion
-
-namespace GameStateManagement
-{
-    /// <summary>
-    /// Helper for reading input from keyboard, gamepad, and touch input. This class 
-    /// tracks both the current and previous state of the input devices, and implements 
-    /// query methods for high level input actions such as "move up through the menu"
-    /// or "pause the game".
-    /// </summary>
-    public class InputState
-    {
-        #region Fields
-
-        public const int MaxInputs = 4;
-
-        public readonly KeyboardState[] CurrentKeyboardStates;
-        public readonly GamePadState[] CurrentGamePadStates;
-
-        public readonly KeyboardState[] LastKeyboardStates;
-        public readonly GamePadState[] LastGamePadStates;
-
-        public readonly bool[] GamePadWasConnected;
-
-        public TouchCollection TouchState;
-
-        public readonly List<GestureSample> Gestures = new List<GestureSample>();
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new input state.
-        /// </summary>
-        public InputState()
-        {
-            CurrentKeyboardStates = new KeyboardState[MaxInputs];
-            CurrentGamePadStates = new GamePadState[MaxInputs];
-
-            LastKeyboardStates = new KeyboardState[MaxInputs];
-            LastGamePadStates = new GamePadState[MaxInputs];
-
-            GamePadWasConnected = new bool[MaxInputs];
-        }
-
-
-        #endregion
-
-        #region Public Methods
-
-
-        /// <summary>
-        /// Reads the latest state of the keyboard and gamepad.
-        /// </summary>
-        public void Update()
-        {
-            for (int i = 0; i < MaxInputs; i++)
-            {
-                LastKeyboardStates[i] = CurrentKeyboardStates[i];
-                LastGamePadStates[i] = CurrentGamePadStates[i];
-
-                CurrentKeyboardStates[i] = Keyboard.GetState((PlayerIndex)i);
-                CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
-
-                // Keep track of whether a gamepad has ever been
-                // connected, so we can detect if it is unplugged.
-                if (CurrentGamePadStates[i].IsConnected)
-                {
-                    GamePadWasConnected[i] = true;
-                }
-            }
-
-            TouchState = TouchPanel.GetState();
-
-            Gestures.Clear();
-            while (TouchPanel.IsGestureAvailable)
-            {
-                Gestures.Add(TouchPanel.ReadGesture());
-            }
-        }
-
-
-        /// <summary>
-        /// Helper for checking if a key was newly pressed during this update. The
-        /// controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When a keypress
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer,
-                                            out PlayerIndex playerIndex)
-        {
-            if (controllingPlayer.HasValue)
-            {
-                // Read input from the specified player.
-                playerIndex = controllingPlayer.Value;
-
-                int i = (int)playerIndex;
-
-                return (CurrentKeyboardStates[i].IsKeyDown(key) &&
-                        LastKeyboardStates[i].IsKeyUp(key));
-            }
-            else
-            {
-                // Accept input from any player.
-                return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
-                        IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
-                        IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
-                        IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
-            }
-        }
-
-
-        /// <summary>
-        /// Helper for checking if a button was newly pressed during this update.
-        /// The controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When a button press
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer,
-                                                     out PlayerIndex playerIndex)
-        {
-            if (controllingPlayer.HasValue)
-            {
-                // Read input from the specified player.
-                playerIndex = controllingPlayer.Value;
-
-                int i = (int)playerIndex;
-
-                return (CurrentGamePadStates[i].IsButtonDown(button) &&
-                        LastGamePadStates[i].IsButtonUp(button));
-            }
-            else
-            {
-                // Accept input from any player.
-                return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
-                        IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
-                        IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
-                        IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
-            }
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu select" input action.
-        /// The controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When the action
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsMenuSelect(PlayerIndex? controllingPlayer,
-                                 out PlayerIndex playerIndex)
-        {
-            return IsNewKeyPress(Keys.Space, controllingPlayer, out playerIndex) ||
-                   IsNewKeyPress(Keys.Enter, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.A, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu cancel" input action.
-        /// The controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When the action
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsMenuCancel(PlayerIndex? controllingPlayer,
-                                 out PlayerIndex playerIndex)
-        {
-            return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.B, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu up" input action.
-        /// The controllingPlayer parameter specifies which player to read
-        /// input for. If this is null, it will accept input from any player.
-        /// </summary>
-        public bool IsMenuUp(PlayerIndex? controllingPlayer)
-        {
-            PlayerIndex playerIndex;
-
-            return IsNewKeyPress(Keys.Up, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.DPadUp, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu down" input action.
-        /// The controllingPlayer parameter specifies which player to read
-        /// input for. If this is null, it will accept input from any player.
-        /// </summary>
-        public bool IsMenuDown(PlayerIndex? controllingPlayer)
-        {
-            PlayerIndex playerIndex;
-
-            return IsNewKeyPress(Keys.Down, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.DPadDown, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "pause the game" input action.
-        /// The controllingPlayer parameter specifies which player to read
-        /// input for. If this is null, it will accept input from any player.
-        /// </summary>
-        public bool IsPauseGame(PlayerIndex? controllingPlayer)
-        {
-            PlayerIndex playerIndex;
-
-            return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
-        }
-
-
-        #endregion
-    }
-}