#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.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GameStateManagement;
using Microsoft.Xna.Framework.GamerServices;
using System.Xml.Linq;
using Microsoft.Xna.Framework.Input.Touch;
#endregion
namespace MemoryMadness
{
class GameplayScreen : GameScreen
{
#region Fields
private bool isActive;
private bool isLevelChange;
///
/// Sets/gets whether or not the game is active. Set operations propogate
/// to the current level.
///
public new bool IsActive
{
get { return isActive; }
set
{
isActive = value;
if (null != currentLevel)
currentLevel.IsActive = value;
}
}
bool moveToHighScore = false;
// Gameplay variables
public Level currentLevel;
int currentLevelNumber;
int movesPerformed = 0;
int maxLevelNumber;
// Rendering variables
SpriteFont levelNumberFont;
SpriteFont textFont;
Texture2D background;
Texture2D buttonsTexture;
// Input related variables
TimeSpan inputTimeMeasure;
TimeSpan inputGracePeriod = TimeSpan.FromMilliseconds(150);
TouchInputState inputState = TouchInputState.Idle;
List lastPressInput;
#endregion
#region Initializations
public GameplayScreen(int levelNumber, int movesPerformed)
: this(levelNumber)
{
this.movesPerformed = movesPerformed;
}
public GameplayScreen(int levelNumber)
{
TransitionOnTime = TimeSpan.FromSeconds(0.0);
TransitionOffTime = TimeSpan.FromSeconds(0.0);
currentLevelNumber = levelNumber;
}
#endregion
#region Loading
///
/// Load the game content
///
public override void LoadContent()
{
XDocument doc = XDocument.Load(@"Content\Gameplay\LevelDefinitions.xml");
var levels = doc.Document.Descendants(XName.Get("Level"));
foreach (var level in levels)
{
maxLevelNumber++;
}
// Resolution for a possible situation which can occur while debugging the
// game. The game may remember it is on a level which is higher than the
// highest available level, following a change to the definition file.
if (currentLevelNumber > maxLevelNumber)
currentLevelNumber = 1;
InitializeLevel();
base.LoadContent();
}
///
/// Initialize the level portrayed by the gameplay screen.
///
private void InitializeLevel()
{
currentLevel = new Level(ScreenManager.Game,
ScreenManager.SpriteBatch,
currentLevelNumber, movesPerformed, buttonsTexture);
currentLevel.IsActive = true;
ScreenManager.Game.Components.Add(currentLevel);
}
///
/// Load assets used by the gameplay screen.
///
public void LoadAssets()
{
levelNumberFont =
ScreenManager.Game.Content.Load(@"Fonts\GameplayLargeFont");
textFont =
ScreenManager.Game.Content.Load(@"Fonts\GameplaySmallFont");
background =
ScreenManager.Game.Content.Load(
@"Textures\Backgrounds\gameplayBG");
buttonsTexture =
ScreenManager.Game.Content.Load(@"Textures\ButtonStates");
}
#endregion
#region Update
///
/// Handle user input.
///
/// The input to handle.
public override void HandleInput(InputState input)
{
if (IsActive)
{
if (input == null)
throw new ArgumentNullException("input");
if (input.IsPauseGame(null))
{
PauseCurrentGame();
}
if (input.TouchState.Count > 0)
{
// We are about to handle touch input
switch (inputState)
{
case TouchInputState.Idle:
// We have yet to receive input, start grace period
inputTimeMeasure = TimeSpan.Zero;
inputState = TouchInputState.GracePeriod;
lastPressInput = new List();
foreach (var touch in input.TouchState)
{
if (touch.State == TouchLocationState.Pressed)
{
lastPressInput.Add(touch);
}
}
break;
case TouchInputState.GracePeriod:
// Do nothing during the grace period other than remembering
// additional presses
foreach (var touch in input.TouchState)
{
if (touch.State == TouchLocationState.Pressed)
{
lastPressInput.Add(touch);
}
}
break;
default:
break;
}
}
}
}
///
/// Update all the game component
///
///
///
///
public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
{
// Do not advance to the highscore screen if sounds are playing
if (moveToHighScore && !AudioManager.AreSoundsPlaying())
{
ScreenManager.Game.Components.Remove(currentLevel);
foreach (GameScreen screen in ScreenManager.GetScreens())
screen.ExitScreen();
ScreenManager.AddScreen(new BackgroundScreen(true), null);
ScreenManager.AddScreen(new HighScoreScreen(), null);
}
// Do not perform advance update logic if the game is inactive or we are
// moving to the highscore screen
if (!IsActive || moveToHighScore)
{
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
return;
}
if ((inputState == TouchInputState.GracePeriod) && (isActive))
{
inputTimeMeasure += gameTime.ElapsedGameTime;
// if the input grace period is over, handle the touch input
if (inputTimeMeasure >= inputGracePeriod)
{
currentLevel.RegisterTouch(lastPressInput);
inputState = TouchInputState.Idle;
}
}
// If the user passed the level, advance to the next or finish the game if
// the current level was last
if (currentLevel.CurrentState == LevelState.FinishedOk && isActive)
{
AudioManager.PlaySound("success");
if (currentLevelNumber < maxLevelNumber)
{
currentLevelNumber++;
isLevelChange = true;
}
else
{
FinishCurrentGame();
}
}
// If the user failed to pass the level, revert to level one, allowing the
// user to register a highscore if he reached a high enough level
else if (currentLevel.CurrentState == LevelState.FinishedFail)
{
isActive = false;
if (HighScoreScreen.IsInHighscores(currentLevelNumber))
{
// The player has a highscore - show the device's keyboard
Guide.BeginShowKeyboardInput(PlayerIndex.One,
Constants.HighscorePopupTitle, Constants.HighscorePopupText,
Constants.HighscorePopupDefault, ShowHighscorePromptEnded,
false);
}
else
{
AudioManager.PlaySound("fail");
isActive = true;
currentLevelNumber = 1;
isLevelChange = true;
}
}
if (isLevelChange)
{
ScreenManager.Game.Components.Remove(currentLevel);
currentLevel = new Level(ScreenManager.Game,
ScreenManager.SpriteBatch,
currentLevelNumber, buttonsTexture);
currentLevel.IsActive = true;
ScreenManager.Game.Components.Add(currentLevel);
isLevelChange = false;
}
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
}
#endregion
#region Render
///
/// Draw The gameplay screen
///
///
public override void Draw(GameTime gameTime)
{
ScreenManager.GraphicsDevice.Clear(Color.CornflowerBlue);
ScreenManager.SpriteBatch.Begin();
ScreenManager.SpriteBatch.Draw(background, Vector2.Zero, Color.White);
if (IsActive)
{
string text;
Vector2 size;
Vector2 position;
if (currentLevel.CurrentState == LevelState.NotReady)
{
text = "Preparing...";
size = textFont.MeasureString(text);
position = new Vector2((ScreenManager.GraphicsDevice.Viewport.Width - size.X) / 2,
(ScreenManager.GraphicsDevice.Viewport.Height - size.Y) / 2);
position.X += 20f;
ScreenManager.SpriteBatch.DrawString(textFont, text,
position, Color.White, 0f, Vector2.Zero, 0.9f, SpriteEffects.None, 0f);
}
else
{
// Draw the current level text, with the text color representing the
// game's current state
Color levelColor = Color.White;
switch (currentLevel.CurrentState)
{
case LevelState.NotReady:
case LevelState.Ready:
break;
case LevelState.Flashing:
levelColor = Color.Yellow;
break;
case LevelState.Started:
case LevelState.Success:
case LevelState.InProcess:
case LevelState.FinishedOk:
levelColor = Color.LimeGreen;
break;
case LevelState.Fault:
case LevelState.FinishedFail:
levelColor = Color.Red;
break;
default:
break;
}
// Draw "Level" text
text = "Level";
size = textFont.MeasureString(text);
position = new Vector2(70, (
ScreenManager.GraphicsDevice.Viewport.Height - size.Y) / 2);
ScreenManager.SpriteBatch.DrawString(
textFont, text, position, levelColor);
// Draw level number
text = currentLevelNumber.ToString("D2");
size = levelNumberFont.MeasureString(text);
position = new Vector2(290, (
ScreenManager.GraphicsDevice.Viewport.Height - size.Y) / 2);
ScreenManager.SpriteBatch.DrawString(
levelNumberFont, text, position, levelColor);
}
}
ScreenManager.SpriteBatch.End();
base.Draw(gameTime);
}
#endregion
#region Private functions
///
/// Finish the current game
///
private void FinishCurrentGame()
{
isActive = false;
if (HighScoreScreen.IsInHighscores(currentLevelNumber))
{
// Show the device's keyboard to enter a name for the highscore
Guide.BeginShowKeyboardInput(PlayerIndex.One,
Constants.HighscorePopupTitle, Constants.HighscorePopupText,
Constants.HighscorePopupDefault, ShowHighscorePromptEnded, true);
}
else
{
moveToHighScore = true;
}
}
///
/// Asynchronous handler for the highscore player name popup messagebox.
///
/// The popup messagebox result. The result's
/// AsyncState property should be true if the user successfully finished
/// the game, or false otherwise.
private void ShowHighscorePromptEnded(IAsyncResult result)
{
string playerName = Guide.EndShowKeyboardInput(result);
bool finishedGame = (bool)result.AsyncState;
if (playerName != null)
{
if (playerName.Length > 15)
playerName = playerName.Substring(0, 15);
HighScoreScreen.PutHighScore(playerName, currentLevelNumber);
}
if (finishedGame)
{
moveToHighScore = true;
}
else
{
AudioManager.PlaySound("fail");
isActive = true;
currentLevelNumber = 1;
isLevelChange = true;
}
}
///
/// Pause the game.
///
private void PauseCurrentGame()
{
IsActive = false;
// Pause sounds
AudioManager.PauseResumeSounds(false);
ScreenManager.AddScreen(new BackgroundScreen(false), null);
ScreenManager.AddScreen(new PauseScreen(false), null);
}
#endregion
}
}