bool drawUserInput; ButtonColors?[] currentTouchSampleColors = new ButtonColors?[4]; // Define spheres covering the various buttons BoundingSphere redShpere; BoundingSphere blueShpere; BoundingSphere greenShpere; BoundingSphere yellowShpere; // Rendering members SpriteBatch spriteBatch; Texture2D buttonsTexture; These variables will give the Level class access to the game object and to a SpriteBatch that can be used for visual output and will allow it to keep track of the player’s progress. Add a set of initialization methods for the Level class. Two of the methods are constructors and the third is an override of the DrawableGameComponent’s Initialize method, which is typically used for loading resources required by the component before displaying it: C# public Level(Game game, SpriteBatch spriteBatch, int levelNumber, int movesPerformed, Texture2D buttonsTexture) : base(game) { this.levelNumber = levelNumber; this.spriteBatch = spriteBatch; CurrentState = LevelState.NotReady; this.buttonsTexture = buttonsTexture; MovesPerformed = movesPerformed; } public Level(Game game, SpriteBatch spriteBatch, int levelNumber, Texture2D buttonsTexture) : this(game, spriteBatch, levelNumber, 0, buttonsTexture) { } public override void Initialize() { // Update delays to match level difficulty UpdateDelays(); // Define button bounding spheres DefineBoundingSpheres(); // Load sequences for current level from definitions XML
case LevelState.Started: break; case LevelState.InProcess: break; case LevelState.Fault: break; case LevelState.Success: break; case LevelState.FinishedOk: break; case LevelState.FinishedFail: break; default: break; } base.Update(gameTime); } Replace the “Ready” case with the following code snippet: C# delayPeriod += gameTime.ElapsedGameTime; if (delayPeriod >= delayFlashOn) { // Initiate flashing sequence currentSequenceItem = //TODO #5 CurrentState = LevelState.Flashing; delayPeriod = TimeSpan.Zero; flashOn = true; } break; Note: By “replacing” a specific case, we mean to use the snippet as its implementation, and not to delete the case statement (in the above step, the snippet should still be preceded by the line “case LevelState.Ready:”. Replace the “Flashing” case with the following code snippet: C# // Display the level's move set. When done, start accepting // user input delayPeriod += gameTime.ElapsedGameTime; if ((delayPeriod >= delayFlashOn) && (flashOn)) { delayPeriod = TimeSpan.Zero; flashOn = false; }
C# public BackgroundScreen(bool animateDoors) { TransitionOnTime = TimeSpan.FromSeconds(0.0); TransitionOffTime = TimeSpan.FromSeconds(0.5); this.animateDoors = animateDoors; if (animateDoors) { AudioManager.PlaySound("doorOpen"); } } The preceding code simply sets values to some of the properties derived from GameScreen, control how the screen is brought in and out of view and defines if the screen should animate the background. Override the base “LoadContent” method to load the background image: C# public override void LoadContent() { background = Load<Texture2D>(@"Textures\Backgrounds\titleBG"); leftDoor = Load<Texture2D>(@"Textures\Backgrounds\leftDoor"); rightDoor = Load<Texture2D>(@"Textures\Backgrounds\rightDoor"); // Prepare to run the doors’ animation if (animateDoors) doorsInTranistion = true; // Set the doors’ start position leftDoorPosition = Settings.LeftDoorClosedPosition; rightDoorPosition = Settings.RightDoorClosedPosition; } Add custom update logic to the class by overriding the Update method: C# public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { if (doorsInTranistion && animateDoors) AnimateDoors(); base.Update(gameTime, otherScreenHasFocus, false); } This method uses helper method named “AnimateDoors”. The helper method produces a sliding doors animation effect. Add the helper method according to the following code snippet:
if (!isResuming) { background = Load<Texture2D>(@"Textures\Backgrounds\Instructions"); } else { background = Load<Texture2D>(@"Textures\Backgrounds\Resuming"); } font = Load<SpriteFont>(@"Fonts\MenuFont"); // Create a new instance of the gameplay screen gameplayScreen = new GameplayScreen(levelNumber, movesPerformed); gameplayScreen.ScreenManager = ScreenManager; } Override the “HandleInput” method as shown in the following code: C# public override void HandleInput(InputState input) { if (!isLoading) { if (input.Gestures.Count > 0) { if (input.Gestures[0].GestureType == GestureType.Tap) { // Start loading the resources in an additional thread thread = new Thread( new ThreadStart(gameplayScreen.LoadAssets)); isLoading = true; thread.Start(); } } } base.HandleInput(input); } The preceding method for a tap from the user in order to dismiss the instructions screen. We would like to display the gameplay screen next, but waiting for it to load its assets will cause a noticeable delay between the tap and the appearance of the gameplay screen. Therefore, we will create an additional thread to perform the gameplay screen’s asset initialization. We will display a loading prompt until the process finishes and then display the gameplay screen. Let us move on to the Update method where we will wait for all assets to load. Override the “Update” method with the following code: C# public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)