|
@@ -0,0 +1,264 @@
|
|
|
+#region File Description
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// PlatformerGame.cs
|
|
|
+//
|
|
|
+// Microsoft XNA Community Game Platform
|
|
|
+// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+#endregion
|
|
|
+
|
|
|
+#if ANDROID
|
|
|
+using Android.App;
|
|
|
+#endif
|
|
|
+
|
|
|
+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
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// This is the main type for your game
|
|
|
+ /// </summary>
|
|
|
+ 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;
|
|
|
+
|
|
|
+#if ANDROID
|
|
|
+ public PlatformerGame (Activity activity) : base (activity)
|
|
|
+#else
|
|
|
+ public PlatformerGame()
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ graphics = new GraphicsDeviceManager(this);
|
|
|
+ Content.RootDirectory = "Content";
|
|
|
+
|
|
|
+#if WINDOWS_PHONE || ANDROID
|
|
|
+ graphics.IsFullScreen = true;
|
|
|
+ TargetElapsedTime = TimeSpan.FromTicks(333333);
|
|
|
+#endif
|
|
|
+ //Accelerometer.Initialize();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// LoadContent will be called once per game and is the place to load
|
|
|
+ /// all of your content.
|
|
|
+ /// </summary>
|
|
|
+ protected override void LoadContent()
|
|
|
+ {
|
|
|
+ // Create a new SpriteBatch, which can be used to draw textures.
|
|
|
+ spriteBatch = new SpriteBatch(GraphicsDevice);
|
|
|
+
|
|
|
+ // Load fonts
|
|
|
+ hudFont = Content.Load<SpriteFont>("Fonts/Hud");
|
|
|
+
|
|
|
+ // Load overlay textures
|
|
|
+ winOverlay = Content.Load<Texture2D>("Overlays/you_win");
|
|
|
+ loseOverlay = Content.Load<Texture2D>("Overlays/you_lose");
|
|
|
+ diedOverlay = Content.Load<Texture2D>("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<Song>("Sounds/Music"));
|
|
|
+ }
|
|
|
+ catch { }
|
|
|
+
|
|
|
+ LoadNextLevel();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Allows the game to run logic such as updating the world,
|
|
|
+ /// checking for collisions, gathering input, and playing audio.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="gameTime">Provides a snapshot of timing values.</param>
|
|
|
+ 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;
|
|
|
+ int j = 4 ;
|
|
|
+ // 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);
|
|
|
+ j = 4 ;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ReloadCurrentLevel()
|
|
|
+ {
|
|
|
+ --levelIndex;
|
|
|
+ LoadNextLevel();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Draws the game from background to foreground.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="gameTime">Provides a snapshot of timing values.</param>
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|