ChaseCameraGame.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // Game.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Content;
  12. using Microsoft.Xna.Framework.Graphics;
  13. using Microsoft.Xna.Framework.Input;
  14. using System;
  15. #endregion
  16. namespace ChaseCameraSample
  17. {
  18. /// <summary>
  19. /// Sample showing how to implement a simple chase camera.
  20. /// </summary>
  21. public class ChaseCameraGame : Microsoft.Xna.Framework.Game
  22. {
  23. #region Fields
  24. GraphicsDeviceManager graphics;
  25. SpriteBatch spriteBatch;
  26. SpriteFont spriteFont;
  27. KeyboardState lastKeyboardState = new KeyboardState();
  28. GamePadState lastGamePadState = new GamePadState();
  29. MouseState lastMousState = new MouseState();
  30. KeyboardState currentKeyboardState = new KeyboardState();
  31. GamePadState currentGamePadState = new GamePadState();
  32. MouseState currentMouseState = new MouseState();
  33. Ship ship;
  34. ChaseCamera camera;
  35. Model shipModel;
  36. Model groundModel;
  37. bool cameraSpringEnabled = true;
  38. #endregion
  39. #region Initialization
  40. public ChaseCameraGame()
  41. {
  42. graphics = new GraphicsDeviceManager(this);
  43. graphics.SupportedOrientations = DisplayOrientation.Portrait;
  44. Content.RootDirectory = "Content";
  45. IsMouseVisible = true;
  46. #if WINDOWS_PHONE
  47. graphics.PreferredBackBufferWidth = 480;
  48. graphics.PreferredBackBufferHeight = 800;
  49. TargetElapsedTime = TimeSpan.FromTicks(333333);
  50. graphics.IsFullScreen = true;
  51. #else
  52. graphics.PreferredBackBufferWidth = 853;
  53. graphics.PreferredBackBufferHeight = 480;
  54. #endif
  55. // Create the chase camera
  56. camera = new ChaseCamera();
  57. // Set the camera offsets
  58. camera.DesiredPositionOffset = new Vector3(0.0f, 2000.0f, 3500.0f);
  59. camera.LookAtOffset = new Vector3(0.0f, 150.0f, 0.0f);
  60. // Set camera perspective
  61. camera.NearPlaneDistance = 10.0f;
  62. camera.FarPlaneDistance = 100000.0f;
  63. //TODO: Set any other camera invariants here such as field of view
  64. }
  65. /// <summary>
  66. /// Initalize the game
  67. /// </summary>
  68. protected override void Initialize()
  69. {
  70. base.Initialize();
  71. ship = new Ship(GraphicsDevice);
  72. // Set the camera aspect ratio
  73. // This must be done after the class to base.Initalize() which will
  74. // initialize the graphics device.
  75. camera.AspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
  76. graphics.GraphicsDevice.Viewport.Height;
  77. // Perform an inital reset on the camera so that it starts at the resting
  78. // position. If we don't do this, the camera will start at the origin and
  79. // race across the world to get behind the chased object.
  80. // This is performed here because the aspect ratio is needed by Reset.
  81. UpdateCameraChaseTarget();
  82. camera.Reset();
  83. }
  84. /// <summary>
  85. /// Load graphics content.
  86. /// </summary>
  87. protected override void LoadContent()
  88. {
  89. spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
  90. spriteFont = Content.Load<SpriteFont>("gameFont");
  91. shipModel = Content.Load<Model>("Ship");
  92. groundModel = Content.Load<Model>("Ground");
  93. }
  94. #endregion
  95. #region Update and Draw
  96. /// <summary>
  97. /// Allows the game to run logic.
  98. /// </summary>
  99. protected override void Update(GameTime gameTime)
  100. {
  101. lastKeyboardState = currentKeyboardState;
  102. lastGamePadState = currentGamePadState;
  103. lastMousState = currentMouseState;
  104. #if WINDOWS_PHONE
  105. currentKeyboardState = new KeyboardState();
  106. #else
  107. currentKeyboardState = Keyboard.GetState();
  108. #endif
  109. currentGamePadState = GamePad.GetState(PlayerIndex.One);
  110. currentMouseState = Mouse.GetState();
  111. // Exit when the Escape key or Back button is pressed
  112. if (currentKeyboardState.IsKeyDown(Keys.Escape) ||
  113. currentGamePadState.Buttons.Back == ButtonState.Pressed)
  114. {
  115. Exit();
  116. }
  117. bool touchTopLeft = currentMouseState.LeftButton == ButtonState.Pressed &&
  118. lastMousState.LeftButton != ButtonState.Pressed &&
  119. currentMouseState.X < GraphicsDevice.Viewport.Width / 10 &&
  120. currentMouseState.Y < GraphicsDevice.Viewport.Height / 10;
  121. // Pressing the A button or key toggles the spring behavior on and off
  122. if (lastKeyboardState.IsKeyUp(Keys.A) &&
  123. (currentKeyboardState.IsKeyDown(Keys.A)) ||
  124. (lastGamePadState.Buttons.A == ButtonState.Released &&
  125. currentGamePadState.Buttons.A == ButtonState.Pressed) ||
  126. touchTopLeft)
  127. {
  128. cameraSpringEnabled = !cameraSpringEnabled;
  129. }
  130. // Reset the ship on R key or right thumb stick clicked
  131. if (currentKeyboardState.IsKeyDown(Keys.R) ||
  132. currentGamePadState.Buttons.RightStick == ButtonState.Pressed)
  133. {
  134. ship.Reset();
  135. camera.Reset();
  136. }
  137. // Update the ship
  138. ship.Update(gameTime);
  139. // Update the camera to chase the new target
  140. UpdateCameraChaseTarget();
  141. // The chase camera's update behavior is the springs, but we can
  142. // use the Reset method to have a locked, spring-less camera
  143. if (cameraSpringEnabled)
  144. camera.Update(gameTime);
  145. else
  146. camera.Reset();
  147. base.Update(gameTime);
  148. }
  149. /// <summary>
  150. /// Update the values to be chased by the camera
  151. /// </summary>
  152. private void UpdateCameraChaseTarget()
  153. {
  154. camera.ChasePosition = ship.Position;
  155. camera.ChaseDirection = ship.Direction;
  156. camera.Up = ship.Up;
  157. }
  158. /// <summary>
  159. /// Draws the ship and ground.
  160. /// </summary>
  161. protected override void Draw(GameTime gameTime)
  162. {
  163. GraphicsDevice device = graphics.GraphicsDevice;
  164. device.Clear(Color.CornflowerBlue);
  165. GraphicsDevice.BlendState = BlendState.Opaque;
  166. GraphicsDevice.DepthStencilState = DepthStencilState.Default;
  167. GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
  168. DrawModel(shipModel, ship.World);
  169. DrawModel(groundModel, Matrix.Identity);
  170. DrawOverlayText();
  171. base.Draw(gameTime);
  172. }
  173. /// <summary>
  174. /// Simple model drawing method. The interesting part here is that
  175. /// the view and projection matrices are taken from the camera object.
  176. /// </summary>
  177. private void DrawModel(Model model, Matrix world)
  178. {
  179. Matrix[] transforms = new Matrix[model.Bones.Count];
  180. model.CopyAbsoluteBoneTransformsTo(transforms);
  181. foreach (ModelMesh mesh in model.Meshes)
  182. {
  183. foreach (BasicEffect effect in mesh.Effects)
  184. {
  185. effect.EnableDefaultLighting();
  186. effect.World = transforms[mesh.ParentBone.Index] * world;
  187. // Use the matrices provided by the chase camera
  188. effect.View = camera.View;
  189. effect.Projection = camera.Projection;
  190. }
  191. mesh.Draw();
  192. }
  193. }
  194. /// <summary>
  195. /// Displays an overlay showing what the controls are,
  196. /// and which settings are currently selected.
  197. /// </summary>
  198. private void DrawOverlayText()
  199. {
  200. spriteBatch.Begin();
  201. string text = "-Touch, Right Trigger, or Spacebar = thrust\n" +
  202. "-Screen edges, Left Thumb Stick,\n or Arrow keys = steer\n" +
  203. "-Press A or touch the top left corner\n to toggle camera spring (" + (cameraSpringEnabled ?
  204. "on" : "off") + ")";
  205. // Draw the string twice to create a drop shadow, first colored black
  206. // and offset one pixel to the bottom right, then again in white at the
  207. // intended position. This makes text easier to read over the background.
  208. spriteBatch.DrawString(spriteFont, text, new Vector2(65, 65), Color.Black);
  209. spriteBatch.DrawString(spriteFont, text, new Vector2(64, 64), Color.White);
  210. spriteBatch.End();
  211. }
  212. #endregion
  213. }
  214. #region Entry Point
  215. /// <summary>
  216. /// The main entry point for the application.
  217. /// </summary>
  218. static class Program
  219. {
  220. static void Main()
  221. {
  222. using (ChaseCameraGame game = new ChaseCameraGame())
  223. {
  224. game.Run();
  225. }
  226. }
  227. }
  228. #endregion
  229. }