#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;
}
}
}