#region File Description
//-----------------------------------------------------------------------------
// Cursor.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
#endregion
namespace PickingSample
{
///
/// Cursor is a DrawableGameComponent that draws a cursor on the screen.
///
public class Cursor : DrawableGameComponent
{
#region Fields and Properties
// this constant controls how fast the gamepad moves the cursor. this constant
// is in pixels per second.
const float CursorSpeed = 400.0f;
// this spritebatch is created internally, and is used to draw the cursor.
SpriteBatch spriteBatch;
// this is the sprite that is drawn at the current cursor position.
// textureCenter is used to center the sprite when drawing.
Texture2D cursorTexture;
Vector2 textureCenter;
// Position is the cursor position, and is in screen space.
private Vector2 position;
public Vector2 Position
{
get { return position; }
}
#endregion
#region Initialization
public Cursor(Game game)
: base(game)
{
}
// LoadContent needs to load the cursor texture and find its center.
// also, we need to create a SpriteBatch.
protected override void LoadContent()
{
cursorTexture = Game.Content.Load("cursor");
textureCenter = new Vector2(cursorTexture.Width / 2, cursorTexture.Height / 2);
spriteBatch = new SpriteBatch(GraphicsDevice);
// we want to default the cursor to start in the center of the screen
Viewport vp = GraphicsDevice.Viewport;
position.X = vp.X + (vp.Width / 2);
position.Y = vp.Y + (vp.Height / 2);
base.LoadContent();
}
#endregion
#region Update
public override void Update(GameTime gameTime)
{
// We use different input on each platform:
// On Xbox, we use the GamePad's DPad and left thumbstick to move the cursor around the screen.
// On Windows, we directly map the cursor to the location of the mouse.
// On Windows Phone, we use the primary touch point for the location of the cursor.
#if XBOX
UpdateXboxInput(gameTime);
#elif WINDOWS
UpdateWindowsInput();
#elif WINDOWS_PHONE
UpdateWindowsPhoneInput();
#endif
}
///
/// Handles input for Xbox 360.
///
private void UpdateXboxInput(GameTime gameTime)
{
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
// we'll create a vector2, called delta, which will store how much the
// cursor position should change.
Vector2 delta = currentState.ThumbSticks.Left;
// down on the thumbstick is -1. however, in screen coordinates, values
// increase as they go down the screen. so, we have to flip the sign of the
// y component of delta.
delta.Y *= -1;
// check the dpad: if any of its buttons are pressed, that will change delta as well.
if (currentState.DPad.Up == ButtonState.Pressed)
{
delta.Y = -1;
}
if (currentState.DPad.Down == ButtonState.Pressed)
{
delta.Y = 1;
}
if (currentState.DPad.Left == ButtonState.Pressed)
{
delta.X = -1;
}
if (currentState.DPad.Right == ButtonState.Pressed)
{
delta.X = 1;
}
// normalize delta so that we know the cursor can't move faster than CursorSpeed.
if (delta != Vector2.Zero)
{
delta.Normalize();
}
// modify position using delta, the CursorSpeed constant defined above, and
// the elapsed game time.
position += delta * CursorSpeed *
(float)gameTime.ElapsedGameTime.TotalSeconds;
// clamp the cursor position to the viewport, so that it can't move off the screen.
Viewport vp = GraphicsDevice.Viewport;
position.X = MathHelper.Clamp(position.X, vp.X, vp.X + vp.Width);
position.Y = MathHelper.Clamp(position.Y, vp.Y, vp.Y + vp.Height);
}
///
/// Handles input for Windows.
///
private void UpdateWindowsInput()
{
MouseState mouseState = Mouse.GetState();
position.X = mouseState.X;
position.Y = mouseState.Y;
}
///
/// Handles input for Windows Phone.
///
private void UpdateWindowsPhoneInput()
{
TouchCollection touches = TouchPanel.GetState();
if (touches.Count > 0)
{
position = touches[0].Position;
}
}
#endregion
#region Draw
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
// use textureCenter as the origin of the sprite, so that the cursor is
// drawn centered around Position.
spriteBatch.Draw(cursorTexture, Position, null, Color.White, 0.0f,
textureCenter, 1.0f, SpriteEffects.None, 0.0f);
spriteBatch.End();
}
#endregion
#region CalculateCursorRay
// CalculateCursorRay Calculates a world space ray starting at the camera's
// "eye" and pointing in the direction of the cursor. Viewport.Unproject is used
// to accomplish this. see the accompanying documentation for more explanation
// of the math behind this function.
public Ray CalculateCursorRay(Matrix projectionMatrix, Matrix viewMatrix)
{
// create 2 positions in screenspace using the cursor position. 0 is as
// close as possible to the camera, 1 is as far away as possible.
Vector3 nearSource = new Vector3(Position, 0f);
Vector3 farSource = new Vector3(Position, 1f);
// use Viewport.Unproject to tell what those two screen space positions
// would be in world space. we'll need the projection matrix and view
// matrix, which we have saved as member variables. We also need a world
// matrix, which can just be identity.
Vector3 nearPoint = GraphicsDevice.Viewport.Unproject(nearSource,
projectionMatrix, viewMatrix, Matrix.Identity);
Vector3 farPoint = GraphicsDevice.Viewport.Unproject(farSource,
projectionMatrix, viewMatrix, Matrix.Identity);
// find the direction vector that goes from the nearPoint to the farPoint
// and normalize it....
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
// and then create a new ray using nearPoint as the source.
return new Ray(nearPoint, direction);
}
#endregion
}
}