Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am creating a racing game using visual studio 2010 and xna 4.0. I'm trying to create some simple physics so my car sticks to the heightmap I have created within my game world and the model adjusts its height and pitch accordingly. I have added some code that should in theory do just this but my model doesn't adjust to the heightmap and just phases through the taller sections. Would anyone be able to help me out/point me in the right direction?

Here is the class I have been working on, I know it is a lot of code to look through and I apologise in advance but I really can't work out why my model isn't responding as it should. Any help is greatly appreciated.

namespace Turbo_Rally
{
class Heightmap
{
    float[,] heightData;
    Vector3[,] normals;
    public int terrainWidth;
    public int terrainHeight;
    public Vector3 heightmapPosition;
    float terrainScale = 400f;
    float verticalScale = 30f;
    VertexPositionNormalTexture[] vertices;
    int[] faces;

    BasicEffect effect;
    Texture2D texture;
    GraphicsDevice graphics;
    Matrix world;

    public Heightmap(GraphicsDevice gd, Texture2D terrainTexture, Texture2D heightmap)
    {
        graphics = gd;
        texture = terrainTexture;
        terrainWidth = heightmap.Width;
        terrainHeight = heightmap.Height;
        faces = new int[(terrainWidth - 1) * (terrainHeight - 1) * 6];
        vertices = new VertexPositionNormalTexture[terrainWidth * terrainHeight];
        effect = new BasicEffect(graphics);

        buildHeightmap(heightmap);
        heightmapPosition.X = 0;
        heightmapPosition.Y = 0;

        for (int z = 0; z < terrainHeight; z++)
        {
            for (int x = 0; x < terrainWidth; x++)
            {
                vertices[x + z * terrainWidth].Position.X = terrainScale * (x);
                vertices[x + z * terrainWidth].Position.Z = terrainScale * (z);
                vertices[x + z * terrainWidth].Position.Y = heightData[x, z];
                vertices[x + z * terrainWidth].Normal = Vector3.Zero;
                vertices[x + z * terrainWidth].TextureCoordinate.X = (float)x / terrainWidth;
                vertices[x + z * terrainWidth].TextureCoordinate.Y = (float)z / terrainHeight;
            }
        }

        int count = 0;
        for (int z = 0; z < terrainHeight - 1; z++)
        {
            for (int x = 0; x < terrainWidth - 1; x++)
            {
                int lowerLeft = x + z * terrainWidth;
                int lowerRight = (x + 1) + z * terrainWidth;
                int topLeft = x + (z + 1) * terrainWidth;
                int topRight = (x + 1) + (z + 1) * terrainWidth;

                faces[count++] = topLeft;
                faces[count++] = lowerRight;
                faces[count++] = lowerLeft;
                faces[count++] = topLeft;
                faces[count++] = topRight;
                faces[count++] = lowerRight;
            }
        }
    }

    public bool BoundingTest(Vector3 position)
    {
        if (position.X > 0 && position.X < (heightData.GetLength(0) - 1) * terrainScale && position.Z > 0 && position.Z < (heightData.GetLength(1) - 1) * terrainScale)
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    public float GetHeight(Vector3 position)
    {
        //Determining the cell the player is positioned in      
        int left, top;
        left = (int)position.X / (int)terrainScale;
        top = (int)position.Z / (int)terrainScale;

        //Working out our position within the cell
        float xNormalized = (position.X % terrainScale) / terrainScale;
        float zNormalized = (position.Z % terrainScale) / terrainScale;

        //Calculating height
        float topHeight = MathHelper.Lerp(heightData[left, top],
                        heightData[left + 1, top],
                        xNormalized);

        float bottomHeight = MathHelper.Lerp(heightData[left, top + 1],
                        heightData[left + 1, top + 1],
                        xNormalized);

        //Finding exact height
        return MathHelper.Lerp(topHeight, bottomHeight, zNormalized);
    }


    public void buildHeightmap(Texture2D heightMap)
    {
        Color[] heightmapColors = new Color[terrainWidth * terrainHeight];
        heightMap.GetData(heightmapColors);

        heightData = new float[terrainWidth, terrainHeight];
        for (int x = 0; x < terrainWidth; x++)
            for (int y = 0; y < terrainHeight; y++)
            {
                heightData[x, y] = heightmapColors[x + y * terrainWidth].R * verticalScale;
            }
    }

    public void calculateNormals()
    {
        for (int i = 0; i < faces.Length / 3; i++)
        {
            Vector3 firstvec = vertices[faces[i * 3 + 1]].Position - vertices[faces[i * 3]].Position;
            Vector3 secondvec = vertices[faces[i * 3]].Position - vertices[faces[i * 3 + 2]].Position;
            Vector3 normal = Vector3.Cross(firstvec, secondvec);
            normal.Normalize();
            vertices[faces[i * 3]].Normal += normal;
            vertices[faces[i * 3 + 1]].Normal += normal;
            vertices[faces[i * 3 + 2]].Normal += normal;
        }

        normals = new Vector3[terrainWidth, terrainHeight];
        for (int x = 0; x < terrainWidth; x++)
        {
            for (int z = 0; z < terrainHeight; z++)
            {
                normals[x, z] = vertices[x + z * terrainWidth].Normal;
            }
        }
    }

    public Vector3 GetNormal(Vector3 position)
    {
        int left, top;
        left = (int)position.X / (int)terrainScale;
        top = (int)position.Z / (int)terrainScale;

        float xNormalized = (position.X % terrainScale) / terrainScale;
        float zNormalized = (position.Z % terrainScale) / terrainScale;

        Vector3 topNormal = Vector3.Lerp(normals[left, top],
                      normals[left + 1, top],
                      xNormalized);

        Vector3 bottomNormal = Vector3.Lerp(normals[left, top + 1],
                      normals[left + 1, top + 1],
                      xNormalized);

        Vector3 normal = Vector3.Lerp(topNormal, bottomNormal, zNormalized);
        normal.Normalize();
        return (normal);
    }

    public void Draw(Matrix projection, Matrix view)
    {
        effect.Texture = texture;
        effect.TextureEnabled = true;
        effect.EnableDefaultLighting();
        effect.DirectionalLight0.Direction = new Vector3(1, -1, 1);
        effect.DirectionalLight0.Enabled = true;
        effect.DirectionalLight1.Enabled = false;
        effect.DirectionalLight2.Enabled = false;
        effect.AmbientLightColor = new Vector3(0.8f, 0.8f, 0.8f);
        effect.SpecularColor = new Vector3(0, 0, 0);
        effect.Projection = projection;
        effect.World = Matrix.Identity;
        effect.View = view;

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Apply();
            {
                graphics.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, faces, 0, faces.Length / 3);
            }
        }

        RasterizerState rs = new RasterizerState();
        rs.FillMode = FillMode.Solid;
        rs.CullMode = CullMode.None;
        graphics.RasterizerState = rs;
    }
}
}
share|improve this question

1 Answer 1

up vote 1 down vote accepted

Looks like you are forgetting to multiply the final Lerp in GetHeight by the terrainHeight.

Also, based on the comments below, you need to add the following:

in your Update() method for your player model after changing the pos vector:

effect.World = Matrix.CreateTranslation(pos.x, GetHeight(pos), pos.z);

where effect is the Effect that you are using to render the player model and pos is a Vector3 that you are using to store the player models position. Obviously change the names if they are different in your routine.

At this point I would actually recommend that you do a little more reading up about how 3d graphics are created, managed and rendered in xna, specifically the Matrix class. The information I have tried to help you with is fairly basic stuff and if you dont fully understand it then you will have countless problems going forward.

share|improve this answer
    
Thanks but I just tried multiplying the final lerp by the terrainHeight but still no physics, my car is just floating above my terrain and phasing through high sections. –  Phil93 Mar 28 '13 at 17:36
    
Well you haven't included any of your physics code for us to look at or did you expect that xna would take care of that automatically? I would expect that using the GetHeight() method that you could retrieve the height at each of the wheel locations and adjust the rotation/height transform based upon that. –  RobCurr Mar 28 '13 at 18:04
    
Hi again, sorry for taking so long to reply. I've been away for a few days. I've tried to add physics within the class I've posted, it should in theory work but it doesn't. If I had your email address I could send you my program to look at? Sorry I'm not too great with programming, I'm still learning. –  Phil93 Mar 31 '13 at 14:18
    
I don't like to post my email on forums as it leads to spam and besides, I would rather you come to an understanding about how it works than write it for you. Initially what I would do is implement it without physics involved. Essentially, create a routine that adjusts the rotation of the vehicle so that the vehicles wheels are following the surface at the given x/z location. Once you accomplish that then you can move onto adding physical forces to each of the wheels. –  RobCurr Mar 31 '13 at 16:06
    
Yeah good point, thanks for the help by the way. I don't have my model rigged or anything so the orientation doesn't affect the wheels. Just the model as a whole, so if there is an incline the entire model should adjust so it looks like it is going uphill etc. but at the minute I just can't get any of it to work. –  Phil93 Mar 31 '13 at 16:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.