#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); } } }