#region File Description
//-----------------------------------------------------------------------------
// Tank.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.Content;
using Microsoft.Xna.Framework.Graphics;
using XnaGraphicsDemo;
using System;
#endregion
namespace SimpleAnimation
{
///
/// Helper class for drawing a tank model with animated wheels and turret.
///
public class Tank
{
#region Fields
// The XNA framework Model object that we are going to display.
Model tankModel;
// Shortcut references to the bones that we are going to animate.
// We could just look these up inside the Draw method, but it is more
// efficient to do the lookups while loading and cache the results.
ModelBone leftBackWheelBone;
ModelBone rightBackWheelBone;
ModelBone leftFrontWheelBone;
ModelBone rightFrontWheelBone;
ModelBone leftSteerBone;
ModelBone rightSteerBone;
ModelBone turretBone;
ModelBone cannonBone;
ModelBone hatchBone;
// Store the original transform matrix for each animating bone.
Matrix leftBackWheelTransform;
Matrix rightBackWheelTransform;
Matrix leftFrontWheelTransform;
Matrix rightFrontWheelTransform;
Matrix leftSteerTransform;
Matrix rightSteerTransform;
Matrix turretTransform;
Matrix cannonTransform;
Matrix hatchTransform;
// Array holding all the bone transform matrices for the entire model.
// We could just allocate this locally inside the Draw method, but it
// is more efficient to reuse a single array, as this avoids creating
// unnecessary garbage.
Matrix[] boneTransforms;
// Current animation positions.
float wheelRotationValue;
float steerRotationValue;
float turretRotationValue;
float cannonRotationValue;
float hatchRotationValue;
#endregion
#region Properties
///
/// Gets or sets the wheel rotation amount.
///
public float WheelRotation
{
get { return wheelRotationValue; }
set { wheelRotationValue = value; }
}
///
/// Gets or sets the steering rotation amount.
///
public float SteerRotation
{
get { return steerRotationValue; }
set { steerRotationValue = value; }
}
///
/// Gets or sets the turret rotation amount.
///
public float TurretRotation
{
get { return turretRotationValue; }
set { turretRotationValue = value; }
}
///
/// Gets or sets the cannon rotation amount.
///
public float CannonRotation
{
get { return cannonRotationValue; }
set { cannonRotationValue = value; }
}
///
/// Gets or sets the entry hatch rotation amount.
///
public float HatchRotation
{
get { return hatchRotationValue; }
set { hatchRotationValue = value; }
}
#endregion
///
/// Loads the tank model.
///
public void Load(ContentManager content)
{
// Load the tank model from the ContentManager.
tankModel = content.Load("tank");
// Look up shortcut references to the bones we are going to animate.
leftBackWheelBone = tankModel.Bones["l_back_wheel_geo"];
rightBackWheelBone = tankModel.Bones["r_back_wheel_geo"];
leftFrontWheelBone = tankModel.Bones["l_front_wheel_geo"];
rightFrontWheelBone = tankModel.Bones["r_front_wheel_geo"];
leftSteerBone = tankModel.Bones["l_steer_geo"];
rightSteerBone = tankModel.Bones["r_steer_geo"];
turretBone = tankModel.Bones["turret_geo"];
cannonBone = tankModel.Bones["canon_geo"];
hatchBone = tankModel.Bones["hatch_geo"];
// Store the original transform matrix for each animating bone.
leftBackWheelTransform = leftBackWheelBone.Transform;
rightBackWheelTransform = rightBackWheelBone.Transform;
leftFrontWheelTransform = leftFrontWheelBone.Transform;
rightFrontWheelTransform = rightFrontWheelBone.Transform;
leftSteerTransform = leftSteerBone.Transform;
rightSteerTransform = rightSteerBone.Transform;
turretTransform = turretBone.Transform;
cannonTransform = cannonBone.Transform;
hatchTransform = hatchBone.Transform;
// Allocate the transform matrix array.
boneTransforms = new Matrix[tankModel.Bones.Count];
}
///
/// Animates the tank model.
///
///
public void Animate(GameTime gameTime)
{
float time = (float)gameTime.TotalGameTime.TotalSeconds;
SteerRotation = (float)Math.Sin(time * 0.75f) * 0.5f;
TurretRotation = (float)Math.Sin(time * 0.333f) * 1.25f;
CannonRotation = (float)Math.Sin(time * 0.25f) * 0.333f - 0.333f;
HatchRotation = MathHelper.Clamp((float)Math.Sin(time * 2) * 2, -1, 0);
}
///
/// Draws the tank model, using the current animation settings.
///
public void Draw(Matrix world, Matrix view, Matrix projection, LightingMode lightMode, bool textureEnable)
{
// Set the world matrix as the root transform of the model.
tankModel.Root.Transform = world;
// Calculate matrices based on the current animation position.
Matrix wheelRotation = Matrix.CreateRotationX(wheelRotationValue);
Matrix steerRotation = Matrix.CreateRotationY(steerRotationValue);
Matrix turretRotation = Matrix.CreateRotationY(turretRotationValue);
Matrix cannonRotation = Matrix.CreateRotationX(cannonRotationValue);
Matrix hatchRotation = Matrix.CreateRotationX(hatchRotationValue);
// Apply matrices to the relevant bones.
leftBackWheelBone.Transform = wheelRotation * leftBackWheelTransform;
rightBackWheelBone.Transform = wheelRotation * rightBackWheelTransform;
leftFrontWheelBone.Transform = wheelRotation * leftFrontWheelTransform;
rightFrontWheelBone.Transform = wheelRotation * rightFrontWheelTransform;
leftSteerBone.Transform = steerRotation * leftSteerTransform;
rightSteerBone.Transform = steerRotation * rightSteerTransform;
turretBone.Transform = turretRotation * turretTransform;
cannonBone.Transform = cannonRotation * cannonTransform;
hatchBone.Transform = hatchRotation * hatchTransform;
// Look up combined bone matrices for the entire model.
tankModel.CopyAbsoluteBoneTransformsTo(boneTransforms);
// Draw the model.
foreach (ModelMesh mesh in tankModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = boneTransforms[mesh.ParentBone.Index];
effect.View = view;
effect.Projection = projection;
switch (lightMode)
{
case LightingMode.NoLighting:
effect.LightingEnabled = false;
break;
case LightingMode.OneVertexLight:
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = false;
effect.DirectionalLight1.Enabled = false;
effect.DirectionalLight2.Enabled = false;
break;
case LightingMode.ThreeVertexLights:
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = false;
break;
case LightingMode.ThreePixelLights:
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
break;
}
effect.SpecularColor = new Vector3(0.8f, 0.8f, 0.6f);
effect.SpecularPower = 16;
effect.TextureEnabled = textureEnable;
}
mesh.Draw();
}
}
}
}