//----------------------------------------------------------------------------- // Tank.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XnaGraphicsDemo; using System; namespace SimpleAnimation { /// /// Helper class for drawing a tank model with animated wheels and turret. /// public class Tank { // 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; /// /// Gets or sets the wheel rotation amount. /// public float WheelRotation { /// /// Gets the wheel rotation value. /// /// The current wheel rotation value. get { return wheelRotationValue; } /// /// Sets the wheel rotation value. /// /// The new wheel rotation value. set { wheelRotationValue = value; } } /// /// Gets or sets the steering rotation amount. /// /// /// Gets or sets the wheel rotation amount for animation. /// public float SteerRotation { /// /// Gets the steer rotation value. /// /// The current steer rotation value. get { return steerRotationValue; } /// /// Sets the steer rotation value. /// /// The new steer rotation value. set { steerRotationValue = value; } } /// /// Gets or sets the steering rotation amount for animation. /// /// /// Gets or sets the turret rotation amount. /// public float TurretRotation { /// /// Gets the turret rotation value. /// /// The current turret rotation value. get { return turretRotationValue; } /// /// Sets the turret rotation value. /// /// The new turret rotation value. set { turretRotationValue = value; } } /// /// /// Gets or sets the cannon rotation amount for animation. /// /// Gets or sets the cannon rotation amount. /// public float CannonRotation { /// /// Gets the cannon rotation value. /// /// The current cannon rotation value. get { return cannonRotationValue; } /// /// Sets the cannon rotation value. /// /// The new cannon rotation value. set { cannonRotationValue = value; } /// /// Gets or sets the entry hatch rotation amount for animation. /// } /// /// Gets or sets the entry hatch rotation amount. /// public float HatchRotation { /// /// Gets the hatch rotation value. /// /// The current hatch rotation value. get { return hatchRotationValue; } /// /// Sets the hatch rotation value. /// /// The new hatch rotation value. set { hatchRotationValue = value; } } /// /// Loads the tank model and caches bone references and transforms. /// /// The content manager to load the model from. 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 by updating rotation values based on elapsed time. /// /// The current game time. 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 and lighting mode. /// /// The world matrix for the tank. /// The view matrix. /// The projection matrix. /// The lighting mode to use. /// Whether to enable texturing. 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(); } } } }