I've now got my world running Bullet physics and it's looking pretty good (yay) but there is 1 issue that I am noticing - inconsistencies with the kinematic character controller. This has displayed itself in two ways.
1) Jump - the speed of the fall of the jump seems to be based on framerate. The higher my framerate the faster I drop back down. I have played around a little with the timestep stuff but haven't seen any change.
2) Character movement speed - for some reason the first world I log into seems to have an effect on the characters movement speed. If I log into world A first my character goes twice as fast as he should, but if I log into world B first the speed seems right. What is extra odd though is that if I teleport to the other world then my characters speed stays consistent with whatever world I logged into first. It's only when I first start up the client and initialise the physics system that the speed changes.
I can understand people may have trouble understanding this world idea, so to elaborate a bit: When changing worlds the physics system isn't changed, and neither is the character. All that occurs is that all the objects in the scene get cleared away then new ones are loaded. The character may be moved to a new position, and that is achieved by using the Warp() function.
There is a slight fps difference between the worlds when first logging in (one has more objects than the other) but that shouldn't make a difference should it?
Anyway I know it's always easier to see some code to go with it so here is my world initialisation code:
Code:
collisionShapes = new AlignedCollisionShapeArray();
collisionObjects = new AlignedCollisionObjectArray();
configuration = new DefaultCollisionConfiguration();
dispatcher = new CollisionDispatcher(configuration);
broadphase = new DbvtBroadphase();
solver = new SequentialImpulseConstraintSolver();
world = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, configuration);
ghostCallback = new GhostPairCallback();
world.Broadphase.OverlappingPairCache.SetInternalGhostPairCallback(ghostCallback);
//float timeStep = 1.0f / (3 * 20);
//world.DispatchInfo.TimeStep = timeStep;
world.DispatchInfo.AllowedCcdPenetration = 0.0001f;
//world.Gravity = new Vector3(0, gravity, 0);
mobControllers = new Dictionary<SceneNode, BulletSharpMobState>();
initialized = true;
Character controller creation code:
Code:
ConvexShape capsule = new CapsuleShape(radius, modelHeight - radius * 2);
ghostObject = new PairCachingGhostObject();
Vector3 position = new Vector3(characterNode.Position.x / scaleFactor, (characterNode.Position.y.Ceiling() + 1500) / scaleFactor, characterNode.Position.z / scaleFactor);
Matrix4 worldTransform = Matrix4.Compose(position, Vector3.UnitScale, Quaternion.Identity);
ghostObject.WorldTransform = worldTransform;
ghostObject.CollisionShape = capsule;
ghostObject.CollisionFlags = CollisionFlags.CharacterObject;
playerController = new KinematicCharacterController(ghostObject, capsule, 350f / scaleFactor, 1);
//playerController.SetFallSpeed(0);
playerController.SetJumpSpeed(8);
playerController.SetMaxJumpHeight(1);
characterToLoad = null;
BulletSharpMobState mobMovementState = new BulletSharpMobState(playerController, mobNodePositionUpdate, modelHeight / 2, userData);
mobMovementState.JumpEvent += jumpHandler;
mobMovementState.FallEvent += fallHandler;
mobControllers.Add(characterNode, mobMovementState);
world.AddCollisionObject(ghostObject, CollisionFilterGroups.CharacterFilter, CollisionFilterGroups.StaticFilter | CollisionFilterGroups.DefaultFilter);
world.AddAction(playerController);
collisionShapes.Add(capsule);
collisionObjects.Add(ghostObject);
And the code to handle movement requests and step the simulation (this is called each frame):
Code:
playerController.SetWalkDirection(desiredDisplacement);
float timeStep = 1.0f / (3 * 20);
//world.StepSimulation(timeSinceLastFrame / 1000, 1, timeStep);
world.StepSimulation(timeSinceLastFrame / 1000);
// Check if player is on ground
mobControllers[sceneNode].OnGround = playerController.OnGround;
// Get the players current position
Matrix4 worldTransform = (Matrix4)playerController.GhostObject.WorldTransform;
pos = worldTransform.Translation;
The commented out parts show you things I have tried. Thanks in advance for any help getting this sorted.
Andrew.