/// <summary>
        /// Creates and connects all nodes in the grid
        /// </summary>
        private void BuildGrid(Sim.Environment.Terrain terrain)
        {
            // create the nodes at their proper locations
            nodes = new Node[width * length];
            for (int z = 0; z < length; z++) 
            {
                for (int x = 0; x < width; x++) 
                {
                    int i = x + z * width;
                    float y = terrain.CalculateHeight(x * spacing, z * spacing);
                    nodes[i] = new Node(new Vector3(x * spacing, y, z * spacing));

                    if (y < 5) // underwater
                        nodes[i].State = NodeState.Invalid;
                    else if (GMath.AngleOfIncline(terrain.CalculateSurfaceNormal(x * spacing, z * spacing)) < 50)
                        nodes[i].State = NodeState.Invalid;
                }
            }

            // connect adjacent nodes
            for (int z = 0; z < length; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    Node n = nodes[x + z * width];

                    // adjacent nodes exist in all 8 directions if the current node is part of the
                    // interior of the grid; if the node is on an edge, certain spots are empty
                    bool addN = z > 0;
                    bool addS = z < length - 1;
                    bool addW = x > 0;
                    bool addE = x < width - 1;

                    if (addN)
                    {
                        n.AdjacentNodes.Add(nodes[x + (z - 1) * width]);                    // N
                        if (addE) n.AdjacentNodes.Add(nodes[(x + 1) + (z - 1) * width]);    // NE
                        if (addW) n.AdjacentNodes.Add(nodes[(x - 1) + (z - 1) * width]);    // NW
                    }

                    if (addS)
                    {
                        n.AdjacentNodes.Add(nodes[x + (z + 1) * width]);                    // S
                        if (addE) n.AdjacentNodes.Add(nodes[(x + 1) + (z + 1) * width]);    // SE
                        if (addW) n.AdjacentNodes.Add(nodes[(x - 1) + (z + 1) * width]);    // SW
                    }

                    if (addE) n.AdjacentNodes.Add(nodes[(x + 1) + z * width]);              // E
                    if (addW) n.AdjacentNodes.Add(nodes[(x - 1) + z * width]);              // W
                }
            }
        }
        public static void SurfaceNormal(GraphicsDevice g, Vector3 position, Sim.Environment.Terrain t)
        {
            BasicEffect e = Shaders.Primitive;

            g.VertexDeclaration = new VertexDeclaration(g, VertexPositionColor.VertexElements);
            VertexPositionColor[] nVerts = new VertexPositionColor[] { 
                new VertexPositionColor(position, Color.Red),
                new VertexPositionColor(position + t.CalculateSurfaceNormal(position.X,position.Z)*20,Color.Yellow)};
            
            e.Begin();
            e.CurrentTechnique.Passes[0].Begin();
            g.DrawUserPrimitives(PrimitiveType.LineList, nVerts, 0, 1);
            e.CurrentTechnique.Passes[0].End();
            e.End();
        }
        public void Update(Sim.Environment.Terrain t, List<PhysicsBall> pballs)
        {
            float floorHeight = t.CalculateHeight(position.X, position.Z) + radius;
            bool aboveTerrain = position.Y > floorHeight;

            if (aboveTerrain && !rising && !falling)
            {
                if (position.Y - floorHeight > 0.5f) // angle is great enough to slip
                    falling = true;
                else
                    position.Y = floorHeight;

            }

            if (position.Y < floorHeight)
                position.Y = floorHeight;

            if (falling)
            {
                diffuseColor = new Vector3(1, 1, 0);
                info = "Behavior: Falling";
                waitingToJump = false;
                waitToJumpTimer = 0;
                Velocity.Y -= gravity;
                if (position.Y <= floorHeight)
                {
                    Velocity.Y *= -bounceFriction;   // friction takes away some of the energy
                    if (Velocity.Y > 0.09f)
                    {
                        rising = true;
                        Vector3 bounceV = t.CalculateSurfaceNormal(position.X, position.Z) * bounceFriction;
                        Velocity.X += bounceV.X;
                        Velocity.Z += bounceV.Z;
                    }
                    else
                        Velocity.Y = 0;
                    falling = false;
                }
            }
            else if (rising)
            {
                diffuseColor = new Vector3(1, 1, 0);
                info = "Behavior: Rising";
                waitingToJump = false;
                waitToJumpTimer = 0;
                Velocity.Y -= gravity;
                if (Velocity.Y <= 0)
                {
                    rising = false;
                    falling = true;
                }
            }
            else if (Velocity.X == 0 && Velocity.Z == 0)
            {
                info = "Behavior: Waiting to jump";
                waitingToJump = true;
                diffuseColor = new Vector3(1, 0, 0);
            }

            float xzFriction;
            if (aboveTerrain)
                xzFriction = 0;
            else
                xzFriction = slowDown;

            if (Velocity.X < 0)
                Velocity.X = MathHelper.Clamp(Velocity.X + xzFriction, -maxSpeed, 0);
            else if (Velocity.X > 0)
                Velocity.X = MathHelper.Clamp(Velocity.X - xzFriction, 0, maxSpeed);

            if (Velocity.Z < 0)
                Velocity.Z = MathHelper.Clamp(Velocity.Z + xzFriction, -maxSpeed, 0);
            else if (Velocity.Z > 0)
                Velocity.Z = MathHelper.Clamp(Velocity.Z - xzFriction, 0, maxSpeed);

            // should only update if velocity is nonzero
            position += Velocity;

            Rotation.Z -= Velocity.X / radius;
            Rotation.X -= Velocity.Z / radius;

            if (waitingToJump)
            {
                waitToJumpTimer += 16;
                if (waitToJumpTimer > 1500)
                {
                    Vector3 tV = target.Position - position;
                    tV.Normalize();
                    Velocity += tV * new Random().Next(5);
                    info = "Behavior: Jumping!";
                }
            }

            if (Updated != null)
                Updated(this, EventArgs.Empty);
        }