Hi, my charcter controller wont seem to work no matter what i do, it will fly off in to the sky doing circles when i go on uneven terrain. it seems a bit more stable on flat terrain.

heres some of my code

Charatcher controller.

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using qkGames;
using JigLibX.Physics;
using Microsoft.Xna.Framework;
using JigLibX.Collision;
using Microsoft.Xna.Framework.Graphics;
using JigLibX.Geometry;
using JigLibX.Math;
using Microsoft.Xna.Framework.Input;
namespace qkGames
{
class CharacterObject : PhysicsObject
{
public Character CharacterBody {get; set;}
public CharacterObject(Vector3 position)
: base()
{
Body = new Character();
CollisionSkin = new CollisionSkin(Body);
//public Vector3 DesiredVelocity { get; set; }
Capsule capsule = new Capsule(Vector3.Zero, Matrix.CreateRotationX(MathHelper.PiOver2), 1.0f, 1.0f);
CollisionSkin.AddPrimitive(capsule, (int)MaterialTable.MaterialID.NotBouncyNormal, new MaterialProperties(0.0f, 0.0f, 0.0f));
Body.CollisionSkin = this.CollisionSkin;
Vector3 com = SetMass(1.0f);
Body.MoveTo(position + com, Matrix.Identity);
CollisionSkin.ApplyLocalTransform(new Transform(-com, Matrix.Identity));
//Body.BodyInertia(0.0f, 0.0f, 0.0f);
//Body.SetBodyInvInertia(0.0f, 0.0f, 0.0f);
CharacterBody = Body as Character;
Body.AllowFreezing = false;
Body.EnableBody();
}
// public override void ApplyEffects(BasicEffect effect)
//{
//throw new NotImplementedException();
//}
}
class ASkinPredicate : CollisionSkinPredicate1
{
public override bool ConsiderSkin(CollisionSkin skin0)
{
if (!(skin0.Owner is Character))
return true;
else
return false;
}
}
class Character : Body
{
public Character() : base()
{
}
public Vector3 DesiredVelocity { get; set; }
private bool doJump = false;
public void DoJump()
{
doJump = true;
}
public override void AddExternalForces(float dt)
{
ClearForces();
if (doJump)
{
foreach (CollisionInfo info in CollisionSkin.Collisions)
{
Vector3 N = info.DirToBody0;
if (this == info.SkinInfo.Skin1.Owner)
Vector3.Negate(ref N, out N);
if (Vector3.Dot(N, Orientation.Up) > 0.7f)
{
Vector3 vel = Velocity; vel.Y = 5.0f;
Velocity = vel;
break;
}
}
}
Vector3 deltaVel = DesiredVelocity - Velocity;
bool running = true;
if (DesiredVelocity.LengthSquared() < JiggleMath.Epsilon) running = false;
else deltaVel.Normalize();
deltaVel.Y = 0.0f;
// start fast, slow down slower
if (running) deltaVel *= 10.0f;
else deltaVel *= 2.0f;
float forceFactor = 1000.0f;
AddBodyForce(deltaVel * Mass * dt * forceFactor);
doJump = false;
AddGravityToExternalForce();
}
}
}
```

And heres my terrain class

```
using System;
using JigLibX.Geometry;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace qkGames
{
public class Terrain : Component, I3DComponent
{
// Height representation
public float[,] heightData;
// Physics height representation
HeightMapInfo heightMapInfo;
// Physics object
HeightMapObject heightMapObject;
// Terrain texture
// Texture2D texture;
public TerrainMaterial Material;
// Vertex and index buffers
VertexDeclaration myVertexDeclaration;
VertexBuffer terrainVertexBuffer;
IndexBuffer terrainIndexBuffer;
// Effect
BasicEffect basicEffect;
// I3DComponent values
Vector3 position = Vector3.Zero;
Matrix rotation = Matrix.Identity;
Vector3 scale = new Vector3(1, 1, -1);
BoundingBox boundingBox = new BoundingBox(new Vector3(-1), new Vector3(1));
public Vector3 Position { get { return position; } set { position = value; } }
public Vector3 EulerRotation
{
get { return MathUtil.MatrixToVector3(Rotation); }
set { this.Rotation = MathUtil.Vector3ToMatrix(value); }
}
public Matrix Rotation { get { return rotation; } set { rotation = value; } }
public Vector3 Scale { get { return scale; } set { scale = value; } }
public BoundingBox BoundingBox { get { return boundingBox; } }
// Constructors
public Terrain(Texture2D HeightMap, Texture2D Texture)
: base()
{
Setup(HeightMap, Texture);
}
public Terrain(Texture2D HeightMap, Texture2D Texture, GameScreen Parent)
: base(Parent)
{
Setup(HeightMap, Texture);
}
void Setup(Texture2D Heightmap, Texture2D Texture)
{
// Load height data
heightData = CreateTerrain(Heightmap);
// Create vertex and index buffers
myVertexDeclaration = new VertexDeclaration(Engine.GraphicsDevice,
VertexPositionNormalTexture.VertexElements);
VertexPositionNormalTexture[] terrainVertices = CreateVertices();
int[] terrainIndices = CreateIndices();
terrainVertices = GenerateNormalsForTriangleStrip(terrainVertices,
terrainIndices);
CreateBuffers(terrainVertices, terrainIndices);
// Setup effect
Material = new TerrainMaterial(Texture);
}
// Sets up terrain, texture, etc
private float[,] CreateTerrain(Texture2D heightMap)
{
// Minimum and maximum heights for terrain
float minimumHeight = 0;
float maximumHeight = 255;
// Width and height of terrain (from heightmap)
int width = heightMap.Width;
int height = heightMap.Height;
// Setup bounding box with width and height
boundingBox = new BoundingBox(
new Vector3(-width / 2, maximumHeight - minimumHeight, -height / 2),
new Vector3(width / 2, maximumHeight - minimumHeight, height / 2));
// Get data from heightmap
Color[] heightMapColors = new Color[width * height];
heightMap.GetData<Color>(heightMapColors);
// Setup height data from heightmap data
float[,] heightData = new float[width, height];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
heightData[x, y] = heightMapColors[x + y * width].R;
if (heightData[x, y] < minimumHeight)
minimumHeight = heightData[x, y];
if (heightData[x, y] > maximumHeight)
maximumHeight = heightData[x, y];
}
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
heightData[x, y] = (heightData[x, y] - minimumHeight)
/ (maximumHeight - minimumHeight) * 30.0f;
// Setup physics
heightMapInfo = new HeightMapInfo(heightData, 1);
if (heightMapObject != null)
{
heightMapObject.DisableComponent();
heightMapObject = null;
}
heightMapObject = new HeightMapObject(heightMapInfo, new Vector2(
heightMapInfo.Width / 2,
-heightMapInfo.Height / 2 + heightMapInfo.Height));
return heightData;
}
// Set up vertices
private VertexPositionNormalTexture[] CreateVertices()
{
// Get width and height and create new vertex array
int width = heightData.GetLength(0);
int height = heightData.GetLength(1);
VertexPositionNormalTexture[] terrainVertices =
new VertexPositionNormalTexture[width * height];
// Calculate position, normal, and texcoords for vertices
int i = 0;
for (int z = 0; z < height; z++)
for (int x = 0; x < width; x++)
{
Vector3 position = new Vector3(x, heightData[x, z], -z);
Vector3 normal = new Vector3(0, 0, 1);
Vector2 texCoord = new Vector2((float)x / 30.0f,
(float)z / 30.0f);
terrainVertices[i++] = new VertexPositionNormalTexture(
position, normal, texCoord);
}
return terrainVertices;
}
// Set up indices
private int[] CreateIndices()
{
// Get width and height and create new index array
int width = heightData.GetLength(0);
int height = heightData.GetLength(1);
int[] terrainIndices = new int[(width) * 2 * (height - 1)];
// Calculate indices for triangle
int i = 0;
int z = 0;
while (z < height - 1)
{
for (int x = 0; x < width; x++)
{
terrainIndices[i++] = x + z * width;
terrainIndices[i++] = x + (z + 1) * width;
}
z++;
if (z < height - 1)
{
for (int x = width - 1; x >= 0; x--)
{
terrainIndices[i++] = x + (z + 1) * width;
terrainIndices[i++] = x + z * width;
}
}
z++;
}
return terrainIndices;
}
// Generates normals for a group of triangles
private VertexPositionNormalTexture[] GenerateNormalsForTriangleStrip(
VertexPositionNormalTexture[] vertices, int[] indices)
{
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal = new Vector3(0, 0, 0);
bool swappedWinding = false;
for (int i = 2; i < indices.Length; i++)
{
Vector3 firstVec = vertices[indices[i - 1]].Position
- vertices[indices[i]].Position;
Vector3 secondVec = vertices[indices[i - 2]].Position
- vertices[indices[i]].Position;
Vector3 normal = Vector3.Cross(firstVec, secondVec);
normal.Normalize();
if (swappedWinding)
normal *= -1;
if (!float.IsNaN(normal.X))
{
vertices[indices[i]].Normal += normal;
vertices[indices[i - 1]].Normal += normal;
vertices[indices[i - 2]].Normal += normal;
}
swappedWinding = !swappedWinding;
}
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal.Normalize();
return vertices;
}
// Sets up vertex and index buffers used for drawing
private void CreateBuffers(VertexPositionNormalTexture[] vertices,
int[] indices)
{
terrainVertexBuffer = new VertexBuffer(Engine.GraphicsDevice,
VertexPositionNormalTexture.SizeInBytes * vertices.Length,
BufferUsage.WriteOnly);
terrainVertexBuffer.SetData(vertices);
terrainIndexBuffer = new IndexBuffer(Engine.GraphicsDevice,
typeof(int), indices.Length, BufferUsage.WriteOnly);
terrainIndexBuffer.SetData(indices);
}
// Draw the terrain
public override void Draw()
{
// Require the camera
Camera camera = Engine.Services.GetService<Camera>();
if (camera == null)
throw new Exception("The engine services does not contain a "
+ "camera service. The terrain requires a camera to draw.");
// Set effect values
Material.Prepare3DDraw(MathUtil.CreateWorldMatrix(position, rotation, scale));
// Get width and height
int width = heightData.GetLength(0);
int height = heightData.GetLength(1);
// Terrain uses different vertex winding than normal models,
//so set the new one
Engine.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace;
// Start the effect
Material.Effect.Begin();
// For each pass..
foreach (EffectPass pass in Material.Effect.CurrentTechnique.Passes)
{
// Begin the pass
pass.Begin();
// Draw the terrain vertices and indices
Engine.GraphicsDevice.Vertices[0].SetSource(terrainVertexBuffer, 0,
VertexPositionNormalTexture.SizeInBytes);
Engine.GraphicsDevice.Indices = terrainIndexBuffer;
Engine.GraphicsDevice.VertexDeclaration = myVertexDeclaration;
Engine.GraphicsDevice.DrawIndexedPrimitives(
Microsoft.Xna.Framework.Graphics.PrimitiveType.TriangleStrip,
0, 0, width * height, 0, width * 2 * (height - 1) - 2);
// End the pass
pass.End();
}
// End the effect
Material.Effect.End();
// Set the vertex winding back
Engine.GraphicsDevice.RenderState.CullMode =
CullMode.CullCounterClockwiseFace;
}
}
}
```

And the update method of my main game

```
public override void Update()
{
//physics.UpdatePhysics = true;
KeyboardDevice keyboard = Engine.Services.GetService<KeyboardDevice>();
MouseDevice mouse = Engine.Services.GetService<MouseDevice>();
Camera cam = (Camera)Engine.Services.GetService<Camera>();
Physics physics = Engine.Services.GetService<Physics>();
// Vector3 inputModifier = new Vector3(
// (keyboard.IsKeyDown(Keys.A) ? -1 : 0) + (keyboard.IsKeyDown(Keys.D) ? 1 : 0),
// (keyboard.IsKeyDown(Keys.Q) ? -1 : 0) + (keyboard.IsKeyDown(Keys.E) ? 1 : 0),
// (keyboard.IsKeyDown(Keys.W) ? -1 : 0) + (keyboard.IsKeyDown(Keys.S) ? 1 : 0)
// );
//cam.IsMousePinned = true;
//cam.EnableKeyboardInput = false;
cam.Position = character.Body.Position + Vector3.Up;
//this.IsMouseVisible = false;
Vector3 moveVector = new Vector3();
float amountOfMovement = 0.5f;
if (keyboard.IsKeyDown(Keys.D))
moveVector += Vector3.Right;
//character.Body.MoveTo(moveVector, cameraRotation);
if (keyboard.IsKeyDown(Keys.A))
moveVector += Vector3.Left;
if (keyboard.IsKeyDown(Keys.S))
moveVector += Vector3.Backward;
if (keyboard.IsKeyDown(Keys.W))
moveVector += Vector3.Forward;
Matrix cameraRotation = Matrix.CreateRotationX(cam.Angles.X) *
Matrix.CreateRotationY(cam.Angles.Y);
moveVector = Vector3.Transform(moveVector, cameraRotation);
JiggleMath.NormalizeSafe(ref moveVector);
moveVector *= amountOfMovement;
//character.Body.MoveTo(moveVector, Matrix.Identity);
character.CharacterBody.DesiredVelocity = moveVector;
if (keyboard.IsKeyDown(Keys.Space))
character.CharacterBody.DoJump();
cam.RotateTranslate(new Vector3(mouse.Delta.Y * -.002f, mouse.Delta.X * -.002f, 0), Vector3.Zero * .05f);
```

and my camera class incase it will help

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
namespace qkGames
{
public class Camera : Component, I3DComponent
{
//basic camera class
Vector3 rotation;
Vector3 translation;
//internal values
Vector3 position = Vector3.Zero;
Matrix rotationMatrix = Matrix.Identity;
Vector3 target = new Vector3(0, 0, -1);
Vector3 up = Vector3.Up;
Matrix view;
Matrix projection;
private Vector2 angles = Vector2.Zero;
//camera look at
public Vector2 Angles { get { return angles; } }
public virtual Vector3 Target
{ get { return target; } set {
Vector3 forward = Vector3.Normalize(position - value);
Vector3 right = Vector3.Normalize(Vector3.Cross(forward, Vector3.Up));
Vector3 up = Vector3.Normalize(Vector3.Cross(right, forward));
Matrix test = Matrix.Identity;
test.Forward = forward;
test.Right = right;
test.Up = up;
angles.X = -(float)Math.Asin(test.M32);
angles.Y = -(float)Math.Asin(test.M13);
target = value; } }
// the view and proj matrixes commonly used for renderin
public virtual Matrix View
{ get { return view; } set { view = value; } }
public virtual Matrix Projection
{ get { return projection; } set { projection = value; } }
public virtual Vector3 Up
{ get { return up; } set { up = value; } }
public virtual Vector3 Position { get { return position; } set { position = value; } }
public virtual Vector3 Scale { get { return Vector3.One; } set { } }
public Vector3 EulerRotation
{
get { return MathUtil.MatrixToVector3(rotationMatrix); }
set { rotationMatrix = MathUtil.Vector3ToMatrix(value); }
}
//the rotation matrix used by camera an up
public virtual Matrix Rotation
{ get { return rotationMatrix; } set { rotationMatrix = value; } }
public virtual BoundingBox BoundingBox
{ get { return new BoundingBox(position - Vector3.One, position + Vector3.One); } }
//Constructors
public Camera(GameScreen Parent) : base(Parent) { }
public Camera() : base() { }
//update camera
public void RotateTranslate(Vector3 Rotation, Vector3 Trans)
{
translation += Trans;
rotation += Rotation;
}
public override void Update()
{
//calc the direction from the postition to the target and normalise
Vector3 newForward = Target - position;
newForward.Normalize();
//set the rotation matrix and forward to this vector
Matrix rotationMatrixCopy = this.Rotation;
rotationMatrixCopy.Forward = newForward;
//save a copy of up
Vector3 referenceVector = Vector3.Up;
//incase camera is pointed perfectly on y axis
if (rotationMatrixCopy.Forward.Y == referenceVector.Y || rotationMatrixCopy.Forward.Y == -referenceVector.Y)
referenceVector = Vector3.Backward;
//calc the parts of rotation matrix
rotationMatrixCopy.Right = Vector3.Cross(this.Rotation.Forward,
referenceVector);
rotationMatrixCopy.Up = Vector3.Cross(this.Rotation.Right,
this.Rotation.Forward);
this.Rotation = rotationMatrixCopy;
//use rotation to find new up
up = rotationMatrixCopy.Up;
//recalc view and proj
View = Matrix.CreateLookAt(position, Target, Up);
Projection = MathUtil.CreateProjectionMatrix();
}
}
}
```