#region File Description
//-----------------------------------------------------------------------------
// PlatformerGame.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;
namespace Platformer
{
///
/// This is the main type for your game
///
public class PlatformerGame : Microsoft.Xna.Framework.Game
{
// Resources for drawing.
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
// Global content.
private SpriteFont hudFont;
private Texture2D winOverlay;
private Texture2D loseOverlay;
private Texture2D diedOverlay;
// Meta-level game state.
private int levelIndex = -1;
private Level level;
private bool wasContinuePressed;
// When the time remaining is less than the warning time, it blinks on the hud
private static readonly TimeSpan WarningTime = TimeSpan.FromSeconds(30);
// We store our input states so that we only poll once per frame,
// then we use the same input state wherever needed
private GamePadState gamePadState;
private KeyboardState keyboardState;
private TouchCollection touchState;
private AccelerometerState accelerometerState;
// The number of levels in the Levels directory of our content. We assume that
// levels in our content are 0-based and that all numbers under this constant
// have a level file present. This allows us to not need to check for the file
// or handle exceptions, both of which can add unnecessary time to level loading.
private const int numberOfLevels = 3;
public PlatformerGame()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
#if WINDOWS_PHONE
graphics.IsFullScreen = true;
TargetElapsedTime = TimeSpan.FromTicks(333333);
#endif
Accelerometer.Initialize();
}
///
/// LoadContent will be called once per game and is the place to load
/// all of your content.
///
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// Load fonts
hudFont = Content.Load("Fonts/Hud");
// Load overlay textures
winOverlay = Content.Load("Overlays/you_win");
loseOverlay = Content.Load("Overlays/you_lose");
diedOverlay = Content.Load("Overlays/you_died");
//Known issue that you get exceptions if you use Media PLayer while connected to your PC
//See http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/c8a243d2-d360-46b1-96bd-62b1ef268c66
//Which means its impossible to test this from VS.
//So we have to catch the exception and throw it away
try
{
MediaPlayer.IsRepeating = true;
MediaPlayer.Play(Content.Load("Sounds/Music"));
}
catch { }
LoadNextLevel();
}
///
/// 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)
{
// Handle polling for our input and handling high-level input
HandleInput();
// update our level, passing down the GameTime along with all of our input states
level.Update(gameTime, keyboardState, gamePadState, touchState,
accelerometerState, Window.CurrentOrientation);
base.Update(gameTime);
}
private void HandleInput()
{
// get all of our input states
keyboardState = Keyboard.GetState();
gamePadState = GamePad.GetState(PlayerIndex.One);
touchState = TouchPanel.GetState();
accelerometerState = Accelerometer.GetState();
// Exit the game when back is pressed.
if (gamePadState.Buttons.Back == ButtonState.Pressed)
Exit();
bool continuePressed =
keyboardState.IsKeyDown(Keys.Space) ||
gamePadState.IsButtonDown(Buttons.A) ||
touchState.AnyTouch();
// Perform the appropriate action to advance the game and
// to get the player back to playing.
if (!wasContinuePressed && continuePressed)
{
if (!level.Player.IsAlive)
{
level.StartNewLife();
}
else if (level.TimeRemaining == TimeSpan.Zero)
{
if (level.ReachedExit)
LoadNextLevel();
else
ReloadCurrentLevel();
}
}
wasContinuePressed = continuePressed;
}
private void LoadNextLevel()
{
// move to the next level
levelIndex = (levelIndex + 1) % numberOfLevels;
// Unloads the content for the current level before loading the next one.
if (level != null)
level.Dispose();
// Load the level.
string levelPath = string.Format("Content/Levels/{0}.txt", levelIndex);
using (Stream fileStream = TitleContainer.OpenStream(levelPath))
level = new Level(Services, fileStream, levelIndex);
}
private void ReloadCurrentLevel()
{
--levelIndex;
LoadNextLevel();
}
///
/// Draws the game from background to foreground.
///
/// Provides a snapshot of timing values.
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
level.Draw(gameTime, spriteBatch);
DrawHud();
spriteBatch.End();
base.Draw(gameTime);
}
private void DrawHud()
{
Rectangle titleSafeArea = GraphicsDevice.Viewport.TitleSafeArea;
Vector2 hudLocation = new Vector2(titleSafeArea.X, titleSafeArea.Y);
Vector2 center = new Vector2(titleSafeArea.X + titleSafeArea.Width / 2.0f,
titleSafeArea.Y + titleSafeArea.Height / 2.0f);
// Draw time remaining. Uses modulo division to cause blinking when the
// player is running out of time.
string timeString = "TIME: " + level.TimeRemaining.Minutes.ToString("00") + ":" + level.TimeRemaining.Seconds.ToString("00");
Color timeColor;
if (level.TimeRemaining > WarningTime ||
level.ReachedExit ||
(int)level.TimeRemaining.TotalSeconds % 2 == 0)
{
timeColor = Color.Yellow;
}
else
{
timeColor = Color.Red;
}
DrawShadowedString(hudFont, timeString, hudLocation, timeColor);
// Draw score
float timeHeight = hudFont.MeasureString(timeString).Y;
DrawShadowedString(hudFont, "SCORE: " + level.Score.ToString(), hudLocation + new Vector2(0.0f, timeHeight * 1.2f), Color.Yellow);
// Determine the status overlay message to show.
Texture2D status = null;
if (level.TimeRemaining == TimeSpan.Zero)
{
if (level.ReachedExit)
{
status = winOverlay;
}
else
{
status = loseOverlay;
}
}
else if (!level.Player.IsAlive)
{
status = diedOverlay;
}
if (status != null)
{
// Draw status message.
Vector2 statusSize = new Vector2(status.Width, status.Height);
spriteBatch.Draw(status, center - statusSize / 2, Color.White);
}
}
private void DrawShadowedString(SpriteFont font, string value, Vector2 position, Color color)
{
spriteBatch.DrawString(font, value, position + new Vector2(1.0f, 1.0f), Color.Black);
spriteBatch.DrawString(font, value, position, color);
}
}
}