using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; namespace SunBurnPhysics { /// /// First person camera component for the demos, rotated by mouse. /// public class Camera : GameComponent { private Matrix view; private Matrix projection; private Vector3 position = new Vector3(0,0, 10); private Vector2 angles = Vector2.Zero; private readonly int widthOver2; private readonly int heightOver2; private float fieldOfView = MathHelper.PiOver4; private float aspectRatio; private float nearPlaneDistance = 0.1f; private float farPlaneDistance = 10000.0f; private MouseState prevMouseState; /// /// Initializes new camera component. /// /// Game to which attach this camera. public Camera(Game game) : base(game) { widthOver2 = game.Window.ClientBounds.Width / 2; heightOver2 = game.Window.ClientBounds.Height / 2; aspectRatio = (float)game.Window.ClientBounds.Width / (float)game.Window.ClientBounds.Height; UpdateProjection(); Mouse.SetPosition(widthOver2, heightOver2); } /// /// Gets camera view matrix. /// public Matrix View { get { return view; } } /// /// Gets or sets camera projection matrix. /// public Matrix Projection { get { return projection; } } /// /// Gets or sets camera position. /// public Vector3 Position { get { return position; } set { position = value; UpdateView(); } } /// /// Gets or sets camera field of view. /// public float FieldOfView { get { return fieldOfView; } set { fieldOfView = value; UpdateProjection(); } } /// /// Gets or sets camera aspect ratio. /// public float AspectRatio { get { return aspectRatio; } set { aspectRatio = value; UpdateProjection(); } } /// /// Gets or sets camera near plane distance. /// public float NearPlaneDistance { get { return nearPlaneDistance; } set { nearPlaneDistance = value; UpdateProjection(); } } /// /// Gets or sets camera far plane distance. /// public float FarPlaneDistance { get { return farPlaneDistance; } set { farPlaneDistance = value; UpdateProjection(); } } /// /// Gets or sets camera's target. /// public Vector3 Target { get { Matrix cameraRotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y); return position + Vector3.Transform(Vector3.Forward, cameraRotation); } set { Vector3 forward = Vector3.Normalize(position - value); Vector3 right = Vector3.Normalize(Vector3.Cross(forward, Vector3.Up)); Vector3 up = Vector3.Normalize(Vector3.Cross(right, forward)); Matrix test = Matrix.Identity; test.Forward = forward; test.Right = right; test.Up = up; angles.X = (float)Math.Asin(test.M32); angles.Y = -(float)Math.Asin(test.M13); } } /// /// Updates camera with input and updates view matrix. /// /// public override void Update(GameTime gameTime) { if (Enabled) { ProcessInput((float)gameTime.ElapsedGameTime.TotalSeconds * 50.0f); UpdateView(); base.Update(gameTime); } } private void ProcessInput(float amountOfMovement) { Vector3 moveVector = new Vector3(); KeyboardState keys = Keyboard.GetState(); if (keys.IsKeyDown(Keys.D)) moveVector.X += amountOfMovement; if (keys.IsKeyDown(Keys.A)) moveVector.X -= amountOfMovement; if (keys.IsKeyDown(Keys.S)) moveVector.Z += amountOfMovement; if (keys.IsKeyDown(Keys.W)) moveVector.Z -= amountOfMovement; Matrix cameraRotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y); position += Vector3.Transform(moveVector, cameraRotation); MouseState currentMouseState = Mouse.GetState(); if (currentMouseState.RightButton == ButtonState.Pressed && prevMouseState.RightButton == ButtonState.Released) { Mouse.SetPosition(widthOver2, heightOver2); } else if (currentMouseState.RightButton == ButtonState.Pressed) { if (currentMouseState.X != widthOver2) angles.Y -= amountOfMovement / 80.0f * (currentMouseState.X - widthOver2); if (currentMouseState.Y != heightOver2) angles.X -= amountOfMovement / 80.0f * (currentMouseState.Y - heightOver2); if (angles.X > 1.4) angles.X = 1.4f; if (angles.X < -1.4) angles.X = -1.4f; if (angles.Y > Math.PI) angles.Y -= 2 * (float)Math.PI; if (angles.Y < -Math.PI) angles.Y += 2 * (float)Math.PI; Mouse.SetPosition(widthOver2, heightOver2); } prevMouseState = currentMouseState; } private void UpdateProjection() { projection = Matrix.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance); } private void UpdateView() { Matrix cameraRotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y); Vector3 targetPos = position + Vector3.Transform(Vector3.Forward, cameraRotation); Vector3 upVector = Vector3.Transform(Vector3.Up, cameraRotation); view = Matrix.CreateLookAt(position, targetPos, upVector); } } }