#region File Description //----------------------------------------------------------------------------- // Ship.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Content; using System; #endregion namespace ChaseCameraSample { class Ship { #region Fields private const float MinimumAltitude = 350.0f; /// /// A reference to the graphics device used to access the viewport for touch input. /// private GraphicsDevice graphicsDevice; /// /// Location of ship in world space. /// public Vector3 Position; /// /// Direction ship is facing. /// public Vector3 Direction; /// /// Ship's up vector. /// public Vector3 Up; private Vector3 right; /// /// Ship's right vector. /// public Vector3 Right { get { return right; } } /// /// Full speed at which ship can rotate; measured in radians per second. /// private const float RotationRate = 1.5f; /// /// Mass of ship. /// private const float Mass = 1.0f; /// /// Maximum force that can be applied along the ship's direction. /// private const float ThrustForce = 24000.0f; /// /// Velocity scalar to approximate drag. /// private const float DragFactor = 0.97f; /// /// Current ship velocity. /// public Vector3 Velocity; /// /// Ship world transform matrix. /// public Matrix World { get { return world; } } private Matrix world; #endregion #region Initialization public Ship(GraphicsDevice device) { graphicsDevice = device; Reset(); } /// /// Restore the ship to its original starting state /// public void Reset() { Position = new Vector3(0, MinimumAltitude, 0); Direction = Vector3.Forward; Up = Vector3.Up; right = Vector3.Right; Velocity = Vector3.Zero; } #endregion bool TouchLeft() { MouseState mouseState = Mouse.GetState(); return mouseState.LeftButton == ButtonState.Pressed && mouseState.X <= graphicsDevice.Viewport.Width / 3; } bool TouchRight() { MouseState mouseState = Mouse.GetState(); return mouseState.LeftButton == ButtonState.Pressed && mouseState.X >= 2 * graphicsDevice.Viewport.Width / 3; } bool TouchDown() { MouseState mouseState = Mouse.GetState(); return mouseState.LeftButton == ButtonState.Pressed && mouseState.Y <= graphicsDevice.Viewport.Height / 3; } bool TouchUp() { MouseState mouseState = Mouse.GetState(); return mouseState.LeftButton == ButtonState.Pressed && mouseState.Y >= 2 * graphicsDevice.Viewport.Height / 3; } /// /// Applies a simple rotation to the ship and animates position based /// on simple linear motion physics. /// public void Update(GameTime gameTime) { KeyboardState keyboardState = Keyboard.GetState(); GamePadState gamePadState = GamePad.GetState(PlayerIndex.One); MouseState mouseState = Mouse.GetState(); float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; // Determine rotation amount from input Vector2 rotationAmount = -gamePadState.ThumbSticks.Left; if (keyboardState.IsKeyDown(Keys.Left) || TouchLeft()) rotationAmount.X = 1.0f; if (keyboardState.IsKeyDown(Keys.Right) || TouchRight()) rotationAmount.X = -1.0f; if (keyboardState.IsKeyDown(Keys.Up) || TouchUp()) rotationAmount.Y = -1.0f; if (keyboardState.IsKeyDown(Keys.Down) || TouchDown()) rotationAmount.Y = 1.0f; // Scale rotation amount to radians per second rotationAmount = rotationAmount * RotationRate * elapsed; // Correct the X axis steering when the ship is upside down if (Up.Y < 0) rotationAmount.X = -rotationAmount.X; // Create rotation matrix from rotation amount Matrix rotationMatrix = Matrix.CreateFromAxisAngle(Right, rotationAmount.Y) * Matrix.CreateRotationY(rotationAmount.X); // Rotate orientation vectors Direction = Vector3.TransformNormal(Direction, rotationMatrix); Up = Vector3.TransformNormal(Up, rotationMatrix); // Re-normalize orientation vectors // Without this, the matrix transformations may introduce small rounding // errors which add up over time and could destabilize the ship. Direction.Normalize(); Up.Normalize(); // Re-calculate Right right = Vector3.Cross(Direction, Up); // The same instability may cause the 3 orientation vectors may // also diverge. Either the Up or Direction vector needs to be // re-computed with a cross product to ensure orthagonality Up = Vector3.Cross(Right, Direction); // Determine thrust amount from input float thrustAmount = gamePadState.Triggers.Right; if (keyboardState.IsKeyDown(Keys.Space) || mouseState.LeftButton == ButtonState.Pressed) thrustAmount = 1.0f; // Calculate force from thrust amount Vector3 force = Direction * thrustAmount * ThrustForce; // Apply acceleration Vector3 acceleration = force / Mass; Velocity += acceleration * elapsed; // Apply psuedo drag Velocity *= DragFactor; // Apply velocity Position += Velocity * elapsed; // Prevent ship from flying under the ground Position.Y = Math.Max(Position.Y, MinimumAltitude); // Reconstruct the ship's world matrix world = Matrix.Identity; world.Forward = Direction; world.Up = Up; world.Right = right; world.Translation = Position; } } }