/// <summary> /// This function is called when the game is Updating in response to user input. /// It'll move the tank around the heightmap, and update all of the tank's /// necessary state. /// </summary> public void Update(float elapsed, float turnAmount, Vector3 movement, HeightMapInfo heightMapInfo, Vector2 turretVector) { facingDirection += turnAmount * TankTurnSpeed * elapsed; // next, we'll create a rotation matrix from the direction the tank is // facing, and use it to transform the vector. Vector3 velocity = Vector3.Transform(movement, orientation); velocity *= TankVelocity; turretRotationValue = turretVector.X; cannonRotationValue = turretVector.Y; // Now we know how much the user wants to move. We'll construct a temporary // vector, newPosition, which will represent where the user wants to go. If // that value is on the heightmap, we'll allow the move. Vector3 newPosition = position + velocity * elapsed; if (heightMapInfo.IsOnHeightmap(newPosition)) { // now that we know we're on the heightmap, we need to know the correct // height and normal at this position. heightMapInfo.GetHeightAndNormal(newPosition, out newPosition.Y, out normal); // As discussed in the doc, we'll use the normal of the heightmap // and our desired forward direction to recalculate our orientation // matrix. It's important to normalize, as well. // now we need to roll the tank's wheels "forward." to do this, we'll // calculate how far they have rolled, and from there calculate how much // they must have rotated. float distanceMoved = Vector3.Distance(position, newPosition); float theta = distanceMoved / TankWheelRadius; int rollDirection = movement.Z > 0 ? 1 : -1; wheelRotationValue += theta * rollDirection; // once we've finished all computations, we can set our position to the // new position that we calculated. position = newPosition; } orientation = Matrix.CreateRotationY(FacingDirection); orientation.Up = normal; orientation.Right = Vector3.Cross(orientation.Forward, orientation.Up); orientation.Right = Vector3.Normalize(orientation.Right); orientation.Forward = Vector3.Cross(orientation.Up, orientation.Right); orientation.Forward = Vector3.Normalize(orientation.Forward); }
void SetUpTerrain() { #region Loading Height Data Texture2D heightMap = Content.Load <Texture2D>("Land"); float minimumHeight = float.MaxValue; float maximumHeight = float.MinValue; float heightRange = 20; waterHeight = heightRange * 0.10f; terrainWidth = heightMap.Width; terrainLength = heightMap.Height; Color[] heightMapColors = new Color[terrainWidth * terrainLength]; heightMap.GetData(heightMapColors); heightData = new float[terrainWidth, terrainLength]; for (int x = 0; x < terrainWidth; x++) { for (int y = 0; y < terrainLength; y++) { heightData[x, y] = heightMapColors[x + y * terrainWidth].R; if (heightData[x, y] < minimumHeight) { minimumHeight = heightData[x, y]; } if (heightData[x, y] > maximumHeight) { maximumHeight = heightData[x, y]; } } } for (int x = 0; x < terrainWidth; x++) { for (int y = 0; y < terrainLength; y++) { heightData[x, y] = (heightData[x, y] - minimumHeight) / (maximumHeight - minimumHeight) * heightRange; } } #endregion #region Generating Vertices terrainVertices = new VertexMultitextured[terrainWidth * terrainLength]; for (int x = 0; x < terrainWidth; x++) { for (int y = 0; y < terrainLength; y++) { float height = heightData[x, y]; terrainVertices[x + y * terrainWidth].Position = new Vector3(x, height, y); terrainVertices[x + y * terrainWidth].TextureCoordinate.X = (float)x / 30.0f; terrainVertices[x + y * terrainWidth].TextureCoordinate.Y = (float)y / 30.0f; terrainVertices[x + y * terrainWidth].TexWeights.X = MathHelper.Clamp(1.0f - Math.Abs(height - 0) / (heightRange / 4), 0, 1); //sand terrainVertices[x + y * terrainWidth].TexWeights.Y = MathHelper.Clamp(1.0f - Math.Abs(height - heightRange / 3) / (heightRange / 4), 0, 1); //grass terrainVertices[x + y * terrainWidth].TexWeights.Z = MathHelper.Clamp(1.0f - Math.Abs(height - 2 * heightRange / 3) / (heightRange / 4), 0, 1); //rock terrainVertices[x + y * terrainWidth].TexWeights.W = MathHelper.Clamp(1.0f - Math.Abs(height - heightRange) / (heightRange / 4), 0, 1); //snow float total = terrainVertices[x + y * terrainWidth].TexWeights.X; total += terrainVertices[x + y * terrainWidth].TexWeights.Y; total += terrainVertices[x + y * terrainWidth].TexWeights.Z; total += terrainVertices[x + y * terrainWidth].TexWeights.W; terrainVertices[x + y * terrainWidth].TexWeights.X /= total; terrainVertices[x + y * terrainWidth].TexWeights.Y /= total; terrainVertices[x + y * terrainWidth].TexWeights.Z /= total; terrainVertices[x + y * terrainWidth].TexWeights.W /= total; } } #endregion #region Generating Indices terrainIndices = new int[(terrainWidth - 1) * (terrainLength - 1) * 6]; int counter = 0; for (int y = 0; y < terrainLength - 1; y++) { for (int x = 0; x < terrainWidth - 1; x++) { int lowerLeft = x + (y + 1) * terrainWidth; int lowerRight = (x + 1) + (y + 1) * terrainWidth; int topLeft = x + y * terrainWidth; int topRight = (x + 1) + y * terrainWidth; terrainIndices[counter++] = topLeft; terrainIndices[counter++] = lowerRight; terrainIndices[counter++] = lowerLeft; terrainIndices[counter++] = topLeft; terrainIndices[counter++] = topRight; terrainIndices[counter++] = lowerRight; } } #endregion #region Calculating Normals for (int i = 0; i < terrainVertices.Length; i++) { terrainVertices[i].Normal = new Vector3(0, 0, 0); } for (int i = 0; i < terrainIndices.Length / 3; i++) { int index1 = terrainIndices[i * 3]; int index2 = terrainIndices[i * 3 + 1]; int index3 = terrainIndices[i * 3 + 2]; Vector3 side1 = terrainVertices[index1].Position - terrainVertices[index3].Position; Vector3 side2 = terrainVertices[index1].Position - terrainVertices[index2].Position; Vector3 normal = Vector3.Cross(side1, side2); terrainVertices[index1].Normal += normal; terrainVertices[index2].Normal += normal; terrainVertices[index3].Normal += normal; } for (int i = 0; i < terrainVertices.Length; i++) { terrainVertices[i].Normal.Normalize(); float temp = terrainVertices[i].Normal.Y; temp = MathHelper.Clamp((float)Math.Pow(temp, 2), 0, 1); float mag = terrainVertices[i].TexWeights.Length(); terrainVertices[i].TexWeights.Normalize(); terrainVertices[i].TexWeights *= temp; terrainVertices[i].TexWeights += Vector4.UnitZ * (1 - temp); terrainVertices[i].TexWeights *= mag; } #endregion #region Loading Buffers terrainVertexBuffer = new VertexBuffer(GraphicsDevice, VertexMultitextured.VertexDeclaration, terrainVertices.Length, BufferUsage.WriteOnly); terrainVertexBuffer.SetData(terrainVertices); terrainIndexBuffer = new IndexBuffer(GraphicsDevice, typeof(int), terrainIndices.Length, BufferUsage.WriteOnly); terrainIndexBuffer.SetData(terrainIndices); #endregion #region Water VertexPositionTexture[] waterVertices = new VertexPositionTexture[6]; waterVertices[0] = new VertexPositionTexture(new Vector3(0, waterHeight, terrainLength), new Vector2(0, 1)); waterVertices[2] = new VertexPositionTexture(new Vector3(terrainWidth, waterHeight, 0), new Vector2(1, 0)); waterVertices[1] = new VertexPositionTexture(new Vector3(0, waterHeight, 0), new Vector2(0, 0)); waterVertices[3] = new VertexPositionTexture(new Vector3(0, waterHeight, terrainLength), new Vector2(0, 1)); waterVertices[5] = new VertexPositionTexture(new Vector3(terrainWidth, waterHeight, terrainLength), new Vector2(1, 1)); waterVertices[4] = new VertexPositionTexture(new Vector3(terrainWidth, waterHeight, 0), new Vector2(1, 0)); waterVertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionTexture.VertexDeclaration, waterVertices.Length, BufferUsage.WriteOnly); waterVertexBuffer.SetData(waterVertices); effect.Parameters["xFogColor0"].SetValue(new Vector4(new Vector3(0.7f), 1)); effect.Parameters["xFogColor1"].SetValue(Color.WhiteSmoke.ToVector4()); effect.Parameters["xWaterBumpMap"].SetValue(waterBumpMap); effect.Parameters["xWaveLength"].SetValue(0.5f); effect.Parameters["xWaveHeight"].SetValue(0.1f); Vector3 windDirection = new Vector3(1, 0, 0); effect.Parameters["xWindForce"].SetValue(7.0f); effect.Parameters["xWindDirection"].SetValue(windDirection); #endregion Vector3[,] normals = new Vector3[terrainWidth, terrainLength]; for (int x = 0; x < terrainWidth; x++) { for (int y = 0; y < terrainLength; y++) { normals[x, y] = terrainVertices[x + y * terrainWidth].Normal; } } heightMapInfo = new HeightMapInfo(heightData, normals, 1); }