/* * Game Design Studio (Spring 2007) * Optimization and Debugging example code * April 2007 * by * Priyesh Dixit * * Main focus of this sample code is to show: * - Bad debugging * - Good debugging * - Great debugging * - Multithreading * - Using CLR */ #region Using Statements using System; using System.Collections.Generic; using System.Threading; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; #endregion namespace Presentation { /// /// This is the main type for your game /// public class MainGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; ContentManager content; SpriteBatch spriteBatch; public static int GAME_WINDOW_WIDTH = 1280; public static int GAME_WINDOW_HEIGHT = 720; public static int MAX_CREATURES_X = 25; public static int MAX_CREATURES_Y = 20; public enum GameModeType { TITLE, GAME_SETUP, GAME_RUNNING, }; GameModeType gameMode = GameModeType.TITLE; public enum GamePhaseType { PRINTS, BREAKS, PROFILE, THREADS }; GamePhaseType currentGamePhase = GamePhaseType.PRINTS; //Menus TitleScreen titleScreen = new TitleScreen(); GameSetup gameSetupScreen = new GameSetup(); string sortType = ""; bool inputReleased = true; static int currentSortIndex = 0; static bool FINISHED_SORTING = true; Thread thread; private class Creature { public int x, y; public int value; public Color color = Color.White; public int index; public Creature() { x = 0; y = 0; value = 0; } public Creature(int newX, int newY, int newValue) { x = newX; y = newY; value = newValue; } public Creature(Creature copyFrom) { x = copyFrom.x; y = copyFrom.y; value = copyFrom.value; } }; static List creatureList = new List(); Texture2D creatureTexture; //~5% can't be seen on the TV public const float SCREEN_CUTOFF_AVOIDANCE = 0.05f; public MainGame() { graphics = new GraphicsDeviceManager(this); content = new ContentManager(Services); } /// /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// protected override void Initialize() { // TODO: Add your initialization logic here graphics.PreferredBackBufferWidth = GAME_WINDOW_WIDTH; graphics.PreferredBackBufferHeight = GAME_WINDOW_HEIGHT; graphics.ApplyChanges(); //calculate max creatures MAX_CREATURES_X = (GAME_WINDOW_WIDTH) / 32 - 2; MAX_CREATURES_Y = (GAME_WINDOW_HEIGHT) / 32 - 2; gameMode = GameModeType.TITLE; spriteBatch = new SpriteBatch(graphics.GraphicsDevice); TextWriter.initFont(graphics.GraphicsDevice, content); base.Initialize(); } /// /// Load your graphics content. If loadAllContent is true, you should /// load content from both ResourceManagementMode pools. Otherwise, just /// load ResourceManagementMode.Manual content. /// /// Which type of content to load. protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) { // TODO: Load any ResourceManagementMode.Automatic content if ((1.0f * GAME_WINDOW_WIDTH) / (1.0f * GAME_WINDOW_HEIGHT) > 1.5) { titleScreen.SetBackground(content.Load("_textures/TitleScreen_wide")); } else { titleScreen.SetBackground(content.Load("_textures/TitleScreen")); } creatureTexture = content.Load("_textures/fatmodabu"); } // TODO: Load any ResourceManagementMode.Manual content } /// /// Unload your graphics content. If unloadAllContent is true, you should /// unload content from both ResourceManagementMode pools. Otherwise, just /// unload ResourceManagementMode.Manual content. Manual content will get /// Disposed by the GraphicsDevice during a Reset. /// /// Which type of content to unload. protected override void UnloadGraphicsContent(bool unloadAllContent) { if (unloadAllContent == true) { content.Unload(); } } /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input and playing audio. /// /// Provides a snapshot of timing values. protected override void Update(GameTime gameTime) { GamePadState gamePadState = GamePad.GetState(PlayerIndex.One); KeyboardState keyboardState = Keyboard.GetState(); if (inputReleased == true) { if (gameMode == GameModeType.TITLE) { if (gamePadState.Buttons.Start == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Enter)) { inputReleased = false; gameMode = GameModeType.GAME_SETUP; } if (gamePadState.Buttons.Back == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Escape)) { this.Exit(); } } else if (gameMode == GameModeType.GAME_SETUP) { if (gamePadState.Buttons.Start == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Enter)) { inputReleased = false; gameMode = GameModeType.GAME_RUNNING; //Get game phase GameMenuOption option = (GameMenuOption)gameSetupScreen.GetMenu().GetMenuElement("Phase:"); switch (option.GetActiveOption()) { case "Prints": currentGamePhase = GamePhaseType.PRINTS; break; case "Breaks": currentGamePhase = GamePhaseType.BREAKS; break; case "Profile": currentGamePhase = GamePhaseType.PROFILE; break; case "Threads": currentGamePhase = GamePhaseType.THREADS; break; } option = (GameMenuOption)gameSetupScreen.GetMenu().GetMenuElement("Sort:"); sortType = option.GetActiveOption(); //Get value of Population input //GameMenuValueInput input = (GameMenuValueInput)gameSetupScreen.GetMenu().GetMenuElement("Population:"); InitializeCreatures(MAX_CREATURES_X*MAX_CREATURES_Y); if (currentGamePhase == GamePhaseType.THREADS) { if (sortType == "Bubble") { thread = new Thread(new ThreadStart(AllInOneBubbleSort)); thread.Start(); } else if (sortType == "Insertion") { thread = new Thread(new ThreadStart(AllInOneInsertionSort)); thread.Start(); } } } if (gamePadState.Buttons.Back == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Escape)) { this.Exit(); } // Navigate menu // Check for the keys and then do the appropriate action bool menuUp = ((gamePadState.DPad.Up == ButtonState.Pressed) || (keyboardState.IsKeyDown(Keys.Up))); bool menuDown = ((gamePadState.DPad.Down == ButtonState.Pressed) || (keyboardState.IsKeyDown(Keys.Down))); bool menuLeft = ((gamePadState.DPad.Left == ButtonState.Pressed) || (keyboardState.IsKeyDown(Keys.Left))); bool menuRight = ((gamePadState.DPad.Right == ButtonState.Pressed) || (keyboardState.IsKeyDown(Keys.Right))); // Navigate up and down if (menuUp || menuDown) { inputReleased = false; // If they pressed Up then get the previous element if (menuUp) { gameSetupScreen.GetMenu().PreviousMenuElement(); } // Or if they pressed down, get the next one else { gameSetupScreen.GetMenu().NextMenuElement(); } } // Change menu options or values if (menuLeft || menuRight) { inputReleased = false; GameMenuElement activeElement = gameSetupScreen.GetMenu().GetActiveMenuElement(); // OptionBox if (activeElement.GetElementType() == MenuElementType.OPTION) { // Cast as option and change value GameMenuOption option = (GameMenuOption)activeElement; // If they pressed left, get previous option if (menuLeft) { option.PreviousOption(); } // Or if they pressed right, get next option else { option.NextOption(); } } // ValueSlider else if (activeElement.GetElementType() == MenuElementType.VALUE) { // Cast as ValueInput type and change value GameMenuValueInput valueInput = (GameMenuValueInput)activeElement; int activeIndex = gameSetupScreen.GetMenu().GetActiveIndex(); // If they pressed left, decrease the value if (menuLeft) { valueInput.Decrement(); } // Or if they pressed right, increase it else { valueInput.Increment(); } } } } else { // Game running if (gamePadState.Buttons.Back == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Escape)) { inputReleased = false; gameMode = GameModeType.GAME_SETUP; } if (currentGamePhase == GamePhaseType.BREAKS) { int x = 0; } //Else run the sorting algorithm if (currentGamePhase != GamePhaseType.THREADS) { if (FINISHED_SORTING == false) { if (sortType == "Insertion") { if (currentGamePhase == GamePhaseType.PROFILE) { AllInOneInsertionSort(); } else { InsertionSort(); } } else if (sortType == "Bubble") { if (currentGamePhase == GamePhaseType.PROFILE) { AllInOneBubbleSort(); } else { bool swapped = BubbleSort(); if (!swapped) { FINISHED_SORTING = true; } } } } } } } else if (gamePadState.Buttons.Start == ButtonState.Released && gamePadState.Buttons.Back == ButtonState.Released && (keyboardState.IsKeyUp(Keys.Enter)) && (keyboardState.IsKeyUp(Keys.Escape)) && (gamePadState.DPad.Up == ButtonState.Released) && (keyboardState.IsKeyUp(Keys.Up)) && (gamePadState.DPad.Down == ButtonState.Released) && (keyboardState.IsKeyUp(Keys.Down)) && (gamePadState.DPad.Left == ButtonState.Released) && (keyboardState.IsKeyUp(Keys.Left)) && (gamePadState.DPad.Right == ButtonState.Released) && (keyboardState.IsKeyUp(Keys.Right))) { inputReleased = true; } base.Update(gameTime); } /// /// This is called when the game should draw itself. /// /// Provides a snapshot of timing values. protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.Black); if (gameMode == GameModeType.TITLE) { //draw title screen titleScreen.Draw(spriteBatch); } else if (gameMode == GameModeType.GAME_SETUP) { //draw menu gameSetupScreen.Draw(spriteBatch); } else { //game running //draw the creatures DrawCreatures(); } base.Draw(gameTime); } private void AllInOneInsertionSort() { while (!FINISHED_SORTING) { InsertionSort(); } } private void InsertionSort() { if (currentSortIndex >= creatureList.Count) { //Done! FINISHED_SORTING = true; return; } //Does sorting algorithm for (int i = currentSortIndex+1; i < creatureList.Count; i++) { //found something smaller! if (creatureList[i].value < creatureList[currentSortIndex].value) { //swap them Creature temp = new Creature(creatureList[currentSortIndex]); creatureList[currentSortIndex] = new Creature(creatureList[i]); creatureList[i] = new Creature(temp); } } //Finished sorting this creature.. place in right place creatureList[currentSortIndex].color = new Color(100, 0, 0, 255); creatureList[currentSortIndex].x = (currentSortIndex % MAX_CREATURES_X) * 32 + 32; creatureList[currentSortIndex].y = (int)((currentSortIndex) / MAX_CREATURES_X) * 32 + 32; currentSortIndex++; if (currentGamePhase == GamePhaseType.PRINTS) { System.Diagnostics.Debug.WriteLine("Done with " + currentSortIndex); } } private void AllInOneBubbleSort() { // Bubble sort bool swapped; do { swapped = BubbleSort(); } while (swapped); } private bool BubbleSort() { bool swapped = false; for (int i = 0; i < creatureList.Count - 1; i++) { //smaller than the one before it if (creatureList[i].value > creatureList[i + 1].value) { //swap them Creature temp = new Creature(creatureList[i + 1]); creatureList[i + 1] = new Creature(creatureList[i]); creatureList[i] = new Creature(temp); creatureList[i].color = new Color(100, 100, 0, 255); swapped = true; } } if (currentGamePhase == GamePhaseType.PRINTS) { System.Diagnostics.Debug.WriteLine("swapped= " + swapped.ToString()); } //test to see if some of them are already sorted bool sorted = true; for (int j = 0; j < creatureList.Count; j++) { sorted = true; for (int i = j + 1; i < creatureList.Count; i++) { if (creatureList[i].value < creatureList[j].value) { sorted = false; break; } } if (sorted) { if (currentGamePhase == GamePhaseType.PRINTS) { System.Diagnostics.Debug.WriteLine("Creature#" + j + " already sorted"); } creatureList[j].color = new Color(100, 0, 0, 255); creatureList[j].x = (j % MAX_CREATURES_X) * 32 + 32; creatureList[j].y = (int)((j) / MAX_CREATURES_X) * 32 + 32; } } return swapped; } private void DrawCreatures() { for (int i = 0; i < creatureList.Count; i++) { spriteBatch.Begin(); spriteBatch.Draw(creatureTexture, new Vector2(creatureList[i].x, creatureList[i].y), creatureList[i].color); spriteBatch.End(); TextWriter.Arial.Draw(creatureList[i].x, creatureList[i].y+15, ""+creatureList[i].value, RobLoach.Alignment.Left, Color.Green); } } private void InitializeCreatures(int num) { Random rand = new Random(); creatureList.Clear(); for (int i = 0; i < num; i++) { creatureList.Add(new Creature()); creatureList[i].x = rand.Next(GAME_WINDOW_WIDTH);// - 2*(int)(0.05f * GAME_WINDOW_WIDTH)) + (int)(0.05f * GAME_WINDOW_WIDTH); creatureList[i].y = rand.Next(GAME_WINDOW_HEIGHT);// - 2*(int)(0.05f * GAME_WINDOW_HEIGHT)) + (int)(0.05f * GAME_WINDOW_HEIGHT); creatureList[i].value = rand.Next(100000) % 1000; creatureList[i].index = i; } currentSortIndex = 0; FINISHED_SORTING = false; } } }