tasting on MonoGame
[tastes.git] / Platformer2D / Platformer2D.Core / Game.cs
blobbec87d5b325843ac9b69cdfab4a7074cb2c922c0
1 #region File Description
2 //-----------------------------------------------------------------------------
3 // PlatformerGame.cs
4 //
5 // Microsoft XNA Community Game Platform
6 // Copyright (C) Microsoft Corporation. All rights reserved.
7 //-----------------------------------------------------------------------------
8 #endregion
10 using System;
11 using System.IO;
12 using Microsoft.Xna.Framework;
13 using Microsoft.Xna.Framework.Graphics;
14 using Microsoft.Xna.Framework.Input;
15 using Microsoft.Xna.Framework.Media;
16 using Microsoft.Xna.Framework.Input.Touch;
17 using Microsoft.Xna.Framework.Content;
19 namespace Platformer2D
21 /// <summary>
22 /// This is the main type for your game
23 /// </summary>
24 public class PlatformerGame : Microsoft.Xna.Framework.Game
26 // Resources for drawing.
27 private GraphicsDeviceManager graphics;
28 private SpriteBatch spriteBatch;
29 Vector2 baseScreenSize = new Vector2(800, 480);
30 private Matrix globalTransformation;
31 int backbufferWidth, backbufferHeight;
33 // Global content.
34 private SpriteFont hudFont;
36 private Texture2D winOverlay;
37 private Texture2D loseOverlay;
38 private Texture2D diedOverlay;
40 // Meta-level game state.
41 private int levelIndex = -1;
42 private Level level;
43 private bool wasContinuePressed;
45 // When the time remaining is less than the warning time, it blinks on the hud
46 private static readonly TimeSpan WarningTime = TimeSpan.FromSeconds(30);
48 // We store our input states so that we only poll once per frame,
49 // then we use the same input state wherever needed
50 private GamePadState gamePadState;
51 private KeyboardState keyboardState;
52 private TouchCollection touchState;
53 private AccelerometerState accelerometerState;
55 private VirtualGamePad virtualGamePad;
57 // The number of levels in the Levels directory of our content. We assume that
58 // levels in our content are 0-based and that all numbers under this constant
59 // have a level file present. This allows us to not need to check for the file
60 // or handle exceptions, both of which can add unnecessary time to level loading.
61 private const int numberOfLevels = 3;
63 public PlatformerGame()
65 graphics = new GraphicsDeviceManager(this);
67 #if WINDOWS_PHONE
68 TargetElapsedTime = TimeSpan.FromTicks(333333);
69 #endif
70 graphics.IsFullScreen = false;
72 //graphics.PreferredBackBufferWidth = 800;
73 //graphics.PreferredBackBufferHeight = 480;
74 graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
76 Accelerometer.Initialize();
79 /// <summary>
80 /// LoadContent will be called once per game and is the place to load
81 /// all of your content.
82 /// </summary>
83 protected override void LoadContent()
85 this.Content.RootDirectory = "Content";
87 // Create a new SpriteBatch, which can be used to draw textures.
88 spriteBatch = new SpriteBatch(GraphicsDevice);
90 // Load fonts
91 hudFont = Content.Load<SpriteFont>("Fonts/Hud");
93 // Load overlay textures
94 winOverlay = Content.Load<Texture2D>("Overlays/you_win");
95 loseOverlay = Content.Load<Texture2D>("Overlays/you_lose");
96 diedOverlay = Content.Load<Texture2D>("Overlays/you_died");
98 ScalePresentationArea();
100 virtualGamePad = new VirtualGamePad(baseScreenSize, globalTransformation, Content.Load<Texture2D>("Sprites/VirtualControlArrow"));
102 //Known issue that you get exceptions if you use Media PLayer while connected to your PC
103 //See http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/c8a243d2-d360-46b1-96bd-62b1ef268c66
104 //Which means its impossible to test this from VS.
105 //So we have to catch the exception and throw it away
108 MediaPlayer.IsRepeating = true;
109 MediaPlayer.Play(Content.Load<Song>("Sounds/Music"));
111 catch { }
113 LoadNextLevel();
116 public void ScalePresentationArea()
118 //Work out how much we need to scale our graphics to fill the screen
119 backbufferWidth = GraphicsDevice.PresentationParameters.BackBufferWidth;
120 backbufferHeight = GraphicsDevice.PresentationParameters.BackBufferHeight;
121 float horScaling = backbufferWidth / baseScreenSize.X;
122 float verScaling = backbufferHeight / baseScreenSize.Y;
123 Vector3 screenScalingFactor = new Vector3(horScaling, verScaling, 1);
124 globalTransformation = Matrix.CreateScale(screenScalingFactor);
125 System.Diagnostics.Debug.WriteLine("Screen Size - Width[" + GraphicsDevice.PresentationParameters.BackBufferWidth + "] Height [" + GraphicsDevice.PresentationParameters.BackBufferHeight + "]");
129 /// <summary>
130 /// Allows the game to run logic such as updating the world,
131 /// checking for collisions, gathering input, and playing audio.
132 /// </summary>
133 /// <param name="gameTime">Provides a snapshot of timing values.</param>
134 protected override void Update(GameTime gameTime)
136 //Confirm the screen has not been resized by the user
137 if (backbufferHeight != GraphicsDevice.PresentationParameters.BackBufferHeight ||
138 backbufferWidth != GraphicsDevice.PresentationParameters.BackBufferWidth)
140 ScalePresentationArea();
142 // Handle polling for our input and handling high-level input
143 HandleInput(gameTime);
145 // update our level, passing down the GameTime along with all of our input states
146 level.Update(gameTime, keyboardState, gamePadState,
147 accelerometerState, Window.CurrentOrientation);
149 if (level.Player.Velocity != Vector2.Zero)
150 virtualGamePad.NotifyPlayerIsMoving();
152 base.Update(gameTime);
155 private void HandleInput(GameTime gameTime)
157 // get all of our input states
158 keyboardState = Keyboard.GetState();
159 touchState = TouchPanel.GetState();
160 gamePadState = virtualGamePad.GetState(touchState, GamePad.GetState(PlayerIndex.One));
161 accelerometerState = Accelerometer.GetState();
163 #if !NETFX_CORE
164 // Exit the game when back is pressed.
165 if (gamePadState.Buttons.Back == ButtonState.Pressed)
166 Exit();
167 #endif
168 bool continuePressed =
169 keyboardState.IsKeyDown(Keys.Space) ||
170 gamePadState.IsButtonDown(Buttons.A) ||
171 touchState.AnyTouch();
173 // Perform the appropriate action to advance the game and
174 // to get the player back to playing.
175 if (!wasContinuePressed && continuePressed)
177 if (!level.Player.IsAlive)
179 level.StartNewLife();
181 else if (level.TimeRemaining == TimeSpan.Zero)
183 if (level.ReachedExit)
184 LoadNextLevel();
185 else
186 ReloadCurrentLevel();
190 wasContinuePressed = continuePressed;
192 virtualGamePad.Update(gameTime);
195 private void LoadNextLevel()
197 // move to the next level
198 levelIndex = (levelIndex + 1) % numberOfLevels;
200 // Unloads the content for the current level before loading the next one.
201 if (level != null)
202 level.Dispose();
204 // Load the level.
205 string levelPath = string.Format("Content/Levels/{0}.txt", levelIndex);
206 using (Stream fileStream = TitleContainer.OpenStream(levelPath))
207 level = new Level(Services, fileStream, levelIndex);
210 private void ReloadCurrentLevel()
212 --levelIndex;
213 LoadNextLevel();
216 /// <summary>
217 /// Draws the game from background to foreground.
218 /// </summary>
219 /// <param name="gameTime">Provides a snapshot of timing values.</param>
220 protected override void Draw(GameTime gameTime)
222 graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
224 spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null,null, globalTransformation);
226 level.Draw(gameTime, spriteBatch);
228 DrawHud();
230 spriteBatch.End();
232 base.Draw(gameTime);
235 private void DrawHud()
237 Rectangle titleSafeArea = GraphicsDevice.Viewport.TitleSafeArea;
238 Vector2 hudLocation = new Vector2(titleSafeArea.X, titleSafeArea.Y);
239 //Vector2 center = new Vector2(titleSafeArea.X + titleSafeArea.Width / 2.0f,
240 // titleSafeArea.Y + titleSafeArea.Height / 2.0f);
242 Vector2 center = new Vector2(baseScreenSize.X / 2, baseScreenSize.Y / 2);
244 // Draw time remaining. Uses modulo division to cause blinking when the
245 // player is running out of time.
246 string timeString = "TIME: " + level.TimeRemaining.Minutes.ToString("00") + ":" + level.TimeRemaining.Seconds.ToString("00");
247 Color timeColor;
248 if (level.TimeRemaining > WarningTime ||
249 level.ReachedExit ||
250 (int)level.TimeRemaining.TotalSeconds % 2 == 0)
252 timeColor = Color.Yellow;
254 else
256 timeColor = Color.Red;
258 DrawShadowedString(hudFont, timeString, hudLocation, timeColor);
260 // Draw score
261 float timeHeight = hudFont.MeasureString(timeString).Y;
262 DrawShadowedString(hudFont, "SCORE: " + level.Score.ToString(), hudLocation + new Vector2(0.0f, timeHeight * 1.2f), Color.Yellow);
264 // Determine the status overlay message to show.
265 Texture2D status = null;
266 if (level.TimeRemaining == TimeSpan.Zero)
268 if (level.ReachedExit)
270 status = winOverlay;
272 else
274 status = loseOverlay;
277 else if (!level.Player.IsAlive)
279 status = diedOverlay;
282 if (status != null)
284 // Draw status message.
285 Vector2 statusSize = new Vector2(status.Width, status.Height);
286 spriteBatch.Draw(status, center - statusSize / 2, Color.White);
289 if (touchState.IsConnected)
290 virtualGamePad.Draw(spriteBatch);
293 private void DrawShadowedString(SpriteFont font, string value, Vector2 position, Color color)
295 spriteBatch.DrawString(font, value, position + new Vector2(1.0f, 1.0f), Color.Black);
296 spriteBatch.DrawString(font, value, position, color);