Cursor.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // Cursor.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 System;
  11. using Microsoft.Xna.Framework;
  12. using Microsoft.Xna.Framework.Content;
  13. using Microsoft.Xna.Framework.Graphics;
  14. using Microsoft.Xna.Framework.Input;
  15. #endregion
  16. namespace TrianglePicking
  17. {
  18. /// <summary>
  19. /// Cursor is a DrawableGameComponent that draws a cursor on the screen. It works
  20. /// differently on Xbox and Windows. On windows, this will be a cursor that is
  21. /// controlled using both the mouse and the gamepad. On Xbox, the cursor will be
  22. /// controlled using only the gamepad.
  23. /// </summary>
  24. public class Cursor : DrawableGameComponent
  25. {
  26. #region Constants
  27. // this constant controls how fast the gamepad moves the cursor. this constant
  28. // is in pixels per second.
  29. const float CursorSpeed = 250.0f;
  30. #endregion
  31. #region Fields and properties
  32. // the content manager is passed in in Cursor's constructor, and will be used to
  33. // load the texture for the cursor to draw with.
  34. ContentManager content;
  35. // this spritebatch is created internally, and is used to draw the cursor.
  36. SpriteBatch spriteBatch;
  37. // this is the sprite that is drawn at the current cursor position.
  38. // textureCenter is used to center the sprite when drawing.
  39. Texture2D cursorTexture;
  40. Vector2 textureCenter;
  41. // Position is the cursor position, and is in screen space.
  42. private Vector2 position;
  43. public Vector2 Position
  44. {
  45. get { return position;}
  46. }
  47. #endregion
  48. #region Creation and initialization
  49. // this constructor doesn't really do much of anything, just calls the base
  50. // constructor, and saves the contentmanager so it can be used in
  51. // LoadContent.
  52. public Cursor(Game game, ContentManager content)
  53. : base(game)
  54. {
  55. this.content = content;
  56. }
  57. // on Xbox360, initialize is overriden so that we can center the cursor once we
  58. // know how big the viewport will be.
  59. #if XBOX360
  60. public override void Initialize()
  61. {
  62. base.Initialize();
  63. Viewport vp = GraphicsDevice.Viewport;
  64. position.X = vp.X + (vp.Width / 2);
  65. position.Y = vp.Y + (vp.Height / 2);
  66. }
  67. #endif
  68. // LoadContent needs to load the cursor texture and find its center.
  69. // also, we need to create a SpriteBatch.
  70. protected override void LoadContent()
  71. {
  72. cursorTexture = content.Load<Texture2D>("cursor");
  73. textureCenter = new Vector2(
  74. cursorTexture.Width / 2, cursorTexture.Height / 2);
  75. spriteBatch = new SpriteBatch(GraphicsDevice);
  76. base.LoadContent();
  77. }
  78. #endregion
  79. #region Draw
  80. // Draw is pretty straightforward: we'll Begin the SpriteBatch, Draw the cursor,
  81. // and then End.
  82. public override void Draw(GameTime gameTime)
  83. {
  84. spriteBatch.Begin();
  85. // use textureCenter as the origin of the sprite, so that the cursor is
  86. // drawn centered around Position.
  87. spriteBatch.Draw(cursorTexture, Position, null, Color.White, 0.0f,
  88. textureCenter, 1.0f, SpriteEffects.None, 0.0f);
  89. spriteBatch.End();
  90. base.Draw(gameTime);
  91. }
  92. #endregion
  93. #region Update
  94. // Update gets the current gamepad state and mouse state and uses that data to
  95. // calculate where the cursor's position is on the screen. On xbox, the position
  96. // is clamped to the viewport so that the cursor can't go off the screen. On
  97. // windows, doing something like that would be rude :)
  98. public override void Update(GameTime gameTime)
  99. {
  100. if (gameTime == null)
  101. throw new ArgumentNullException("gameTime");
  102. GamePadState currentState = GamePad.GetState(PlayerIndex.One);
  103. // we'll create a vector2, called delta, which will store how much the
  104. // cursor position should change.
  105. Vector2 delta = currentState.ThumbSticks.Left;
  106. // down on the thumbstick is -1. however, in screen coordinates, values
  107. // increase as they go down the screen. so, we have to flip the sign of the
  108. // y component of delta.
  109. delta.Y *= -1;
  110. // check the dpad: if any of its buttons are pressed, that will change delta
  111. // as well.
  112. if (currentState.DPad.Up == ButtonState.Pressed)
  113. {
  114. delta.Y = -1;
  115. }
  116. if (currentState.DPad.Down == ButtonState.Pressed)
  117. {
  118. delta.Y = 1;
  119. }
  120. if (currentState.DPad.Left == ButtonState.Pressed)
  121. {
  122. delta.X = -1;
  123. }
  124. if (currentState.DPad.Right == ButtonState.Pressed)
  125. {
  126. delta.X = 1;
  127. }
  128. // normalize delta so that we know the cursor can't move faster than
  129. // CursorSpeed.
  130. if (delta != Vector2.Zero)
  131. {
  132. delta.Normalize();
  133. }
  134. #if XBOX360
  135. // modify position using delta, the CursorSpeed constant defined above, and
  136. // the elapsed game time.
  137. position += delta * CursorSpeed *
  138. (float)gameTime.ElapsedGameTime.TotalSeconds;
  139. // clamp the cursor position to the viewport, so that it can't move off the
  140. // screen.
  141. Viewport vp = GraphicsDevice.Viewport;
  142. position.X = MathHelper.Clamp(position.X, vp.X, vp.X + vp.Width);
  143. position.Y = MathHelper.Clamp(position.Y, vp.Y, vp.Y + vp.Height);
  144. #else
  145. MouseState mouseState = Mouse.GetState();
  146. position.X = mouseState.X;
  147. position.Y = mouseState.Y;
  148. if (Game.IsActive)
  149. {
  150. // modify position using delta, the CursorSpeed constant defined above,
  151. // and the elapsed game time, only if the cursor is on the screen
  152. Viewport vp = GraphicsDevice.Viewport;
  153. if ((vp.X <= position.X) && (position.X <= (vp.X + vp.Width)) &&
  154. (vp.Y <= position.Y) && (position.Y <= (vp.Y + vp.Height)))
  155. {
  156. position += delta * CursorSpeed *
  157. (float)gameTime.ElapsedGameTime.TotalSeconds;
  158. position.X = MathHelper.Clamp(position.X, vp.X, vp.X + vp.Width);
  159. position.Y = MathHelper.Clamp(position.Y, vp.Y, vp.Y + vp.Height);
  160. }
  161. else if (delta.LengthSquared() > 0f)
  162. {
  163. position.X = vp.X + vp.Width / 2;
  164. position.Y = vp.Y + vp.Height / 2;
  165. }
  166. // set the new mouse position using the combination of mouse and gamepad
  167. // data.
  168. Mouse.SetPosition((int)position.X, (int)position.Y);
  169. }
  170. #endif
  171. base.Update(gameTime);
  172. }
  173. #endregion
  174. // CalculateCursorRay Calculates a world space ray starting at the camera's
  175. // "eye" and pointing in the direction of the cursor. Viewport.Unproject is used
  176. // to accomplish this. see the accompanying documentation for more explanation
  177. // of the math behind this function.
  178. public Ray CalculateCursorRay(Matrix projectionMatrix, Matrix viewMatrix)
  179. {
  180. // create 2 positions in screenspace using the cursor position. 0 is as
  181. // close as possible to the camera, 1 is as far away as possible.
  182. Vector3 nearSource = new Vector3(Position, 0f);
  183. Vector3 farSource = new Vector3(Position, 1f);
  184. // use Viewport.Unproject to tell what those two screen space positions
  185. // would be in world space. we'll need the projection matrix and view
  186. // matrix, which we have saved as member variables. We also need a world
  187. // matrix, which can just be identity.
  188. Vector3 nearPoint = GraphicsDevice.Viewport.Unproject(nearSource,
  189. projectionMatrix, viewMatrix, Matrix.Identity);
  190. Vector3 farPoint = GraphicsDevice.Viewport.Unproject(farSource,
  191. projectionMatrix, viewMatrix, Matrix.Identity);
  192. // find the direction vector that goes from the nearPoint to the farPoint
  193. // and normalize it....
  194. Vector3 direction = farPoint - nearPoint;
  195. direction.Normalize();
  196. // and then create a new ray using nearPoint as the source.
  197. return new Ray(nearPoint, direction);
  198. }
  199. }
  200. }