Code: Select all
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using BEPUphysics.Vehicle;
using BEPUphysics.Entities.Prefabs;
using BEPUphysics;
using BEPUphysics.CollisionShapes;
using BEPUphysics.CollisionShapes.ConvexShapes;
namespace DrivingSim
{
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;
// Fisica.
Vehicle physics;
public float BackwardSpeed = -13;
public float ForwardSpeed = 30;
public float MaximumTurnAngle = (float)Math.PI / 6;
public float TurnSpeed = MathHelper.Pi;
public Vector3 tankPos;
public Quaternion tankRot;
#endregion
#region Properties
/// <summary>
/// Gets or sets the wheel rotation amount.
/// </summary>
public float WheelRotation
{
get { return wheelRotationValue; }
set { wheelRotationValue = value; }
}
/// <summary>
/// Gets or sets the steering rotation amount.
/// </summary>
public float SteerRotation
{
get { return steerRotationValue; }
set { steerRotationValue = value; }
}
/// <summary>
/// Gets or sets the turret rotation amount.
/// </summary>
public float TurretRotation
{
get { return turretRotationValue; }
set { turretRotationValue = value; }
}
/// <summary>
/// Gets or sets the cannon rotation amount.
/// </summary>
public float CannonRotation
{
get { return cannonRotationValue; }
set { cannonRotationValue = value; }
}
/// <summary>
/// Gets or sets the entry hatch rotation amount.
/// </summary>
public float HatchRotation
{
get { return hatchRotationValue; }
set { hatchRotationValue = value; }
}
#endregion
/// <summary>
/// Loads the tank model.
/// </summary>
public void Load(ContentManager content, Space space)
{
// Load the tank model from the ContentManager.
tankModel = content.Load<Model>("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];
// Inizializza la fisica.
tankPos = new Vector3(0, 0, 0);
tankRot = new Quaternion(0, 0, 0, 0);
/*wheels[0] = new Wheel(new RaycastWheelShape(2, Matrix.Identity));
wheels[1] = new Wheel(new RaycastWheelShape(2, Matrix.Identity));
wheels[2] = new Wheel(new RaycastWheelShape(2, Matrix.Identity));
wheels[3] = new Wheel(new RaycastWheelShape(2, Matrix.Identity));
physics = new Vehicle(new Box(new BEPUphysics.EntityStateManagement.MotionState(), 5, 5, 10), wheels);
space.Add(physics);*/
var bodies = new List<CompoundShapeEntry>()
{
new CompoundShapeEntry(new BoxShape(2.5f, .75f, 4.5f), new Vector3(0, 0, 0), 60),
new CompoundShapeEntry(new BoxShape(2.5f, .3f, 2f), new Vector3(0, .75f / 2 + .3f / 2, .5f), 1)
};
var body = new CompoundBody(bodies, 61);
body.CollisionInformation.LocalPosition = new Vector3(0, .5f, 0);
body.Position = (tankPos);
physics = new Vehicle(body);
#region RaycastWheelShapes
Matrix wheelGraphicRotation = Matrix.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);
physics.AddWheel(new Wheel(
new RaycastWheelShape(.375f, wheelGraphicRotation),
new WheelSuspension(2000, 100f, Vector3.Down, .8f, new Vector3(-1.1f, 0, 1.8f)),
new WheelDrivingMotor(2.5f, 30000, 10000),
new WheelBrake(1.5f, 2, .02f),
new WheelSlidingFriction(4, 5)));
physics.AddWheel(new Wheel(
new RaycastWheelShape(.375f, wheelGraphicRotation),
new WheelSuspension(2000, 100f, Vector3.Down, .8f, new Vector3(-1.1f, 0, -1.8f)),
new WheelDrivingMotor(2.5f, 30000, 10000),
new WheelBrake(1.5f, 2, .02f),
new WheelSlidingFriction(4, 5)));
physics.AddWheel(new Wheel(
new RaycastWheelShape(.375f, wheelGraphicRotation),
new WheelSuspension(2000, 100f, Vector3.Down, .8f, new Vector3(1.1f, 0, 1.8f)),
new WheelDrivingMotor(2.5f, 30000, 10000),
new WheelBrake(1.5f, 2, .02f),
new WheelSlidingFriction(4, 5)));
physics.AddWheel(new Wheel(
new RaycastWheelShape(.375f, wheelGraphicRotation),
new WheelSuspension(2000, 100f, Vector3.Down, .8f, new Vector3(1.1f, 0, -1.8f)),
new WheelDrivingMotor(2.5f, 30000, 10000),
new WheelBrake(1.5f, 2, .02f),
new WheelSlidingFriction(4, 5)));
#endregion
foreach (Wheel wheel in physics.Wheels)
{
wheel.Shape.FreezeWheelsWhileBraking = true;
wheel.Suspension.SolverSettings.MaximumIterations = 1;
wheel.Brake.SolverSettings.MaximumIterations = 1;
wheel.SlidingFriction.SolverSettings.MaximumIterations = 1;
wheel.DrivingMotor.SolverSettings.MaximumIterations = 1;
}
space.Add(physics);
}
/// <summary>
/// Draws the tank model, using the current animation settings.
/// </summary>
public void Draw(Matrix world, Matrix view, Matrix projection)
{
// 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;
effect.EnableDefaultLighting();
}
mesh.Draw();
}
}
public void Update(float dt, KeyboardState keyboardInput)
{
leftBackWheelBone.Transform = physics.Wheels[0].Shape.WorldTransform;
rightBackWheelBone.Transform = physics.Wheels[1].Shape.WorldTransform;
leftFrontWheelBone.Transform = physics.Wheels[2].Shape.WorldTransform;
rightFrontWheelBone.Transform = physics.Wheels[3].Shape.WorldTransform;
tankPos = physics.Body.Position;
tankRot = physics.Body.Orientation;
if (keyboardInput.IsKeyDown(Keys.E))
{
//Drive
physics.Wheels[1].DrivingMotor.TargetSpeed = ForwardSpeed;
physics.Wheels[3].DrivingMotor.TargetSpeed = ForwardSpeed;
}
else if (keyboardInput.IsKeyDown(Keys.D))
{
//Reverse
physics.Wheels[1].DrivingMotor.TargetSpeed = BackwardSpeed;
physics.Wheels[3].DrivingMotor.TargetSpeed = BackwardSpeed;
}
else
{
//Idle
physics.Wheels[1].DrivingMotor.TargetSpeed = 0;
physics.Wheels[3].DrivingMotor.TargetSpeed = 0;
}
if (keyboardInput.IsKeyDown(Keys.Space))
{
//Brake
foreach (Wheel wheel in physics.Wheels)
{
wheel.Brake.IsBraking = true;
}
}
else
{
//Release brake
foreach (Wheel wheel in physics.Wheels)
{
wheel.Brake.IsBraking = false;
}
}
//Use smooth steering; while held down, move towards maximum.
//When not pressing any buttons, smoothly return to facing forward.
float angle;
bool steered = false;
if (keyboardInput.IsKeyDown(Keys.S))
{
steered = true;
angle = Math.Max(physics.Wheels[1].Shape.SteeringAngle - TurnSpeed * dt, -MaximumTurnAngle);
physics.Wheels[1].Shape.SteeringAngle = angle;
physics.Wheels[3].Shape.SteeringAngle = angle;
}
if (keyboardInput.IsKeyDown(Keys.F))
{
steered = true;
angle = Math.Min(physics.Wheels[1].Shape.SteeringAngle + TurnSpeed * dt, MaximumTurnAngle);
physics.Wheels[1].Shape.SteeringAngle = angle;
physics.Wheels[3].Shape.SteeringAngle = angle;
}
if (!steered)
{
//Neither key was pressed, so de-steer.
if (physics.Wheels[1].Shape.SteeringAngle > 0)
{
angle = Math.Max(physics.Wheels[1].Shape.SteeringAngle - TurnSpeed * dt, 0);
physics.Wheels[1].Shape.SteeringAngle = angle;
physics.Wheels[3].Shape.SteeringAngle = angle;
}
else
{
angle = Math.Min(physics.Wheels[1].Shape.SteeringAngle + TurnSpeed * dt, 0);
physics.Wheels[1].Shape.SteeringAngle = angle;
physics.Wheels[3].Shape.SteeringAngle = angle;
}
}
}
}
}