I have tried multiple different ways to get a Havok simulation to run consistently between clients. I have the delta being applied to all the forces and have even tried dynamic time scaling on the simulation.
This thread: Ensure that the forces being applied with Havok are the same for different clients without relying on deltaTime? was posted about it in the past but for some reason I can not get things to run consistent.
I was hoping people could take a quick glance at the sections of code responsible for the application of the forces and delta time and see if they notice a problem with the setup.
Input Handling:
private _handleInputs(delta: number) {
this._isBreaking = false;
// if (this._player.state !== GoKartPlayerStates.RACING) {
// return;
// }
if (this._inputs.forward && !this._inputs.back) {
if (this._forwardForce >= 0) {
this._forwardForce = Math.min(
this._forwardForce + this._accelerationForce * delta,
this._maxForwardForce,
);
} else {
this._forwardForce *= this._breakingFactor;
this._isBreaking = true;
}
} else if (!this._inputs.forward && this._inputs.back) {
if (this._forwardForce <= 0) {
this._forwardForce = Math.max(
this._forwardForce - this._accelerationForce * delta,
this._maxForwardForce * -0.5,
);
} else {
this._forwardForce *= this._breakingFactor;
this._isBreaking = true;
}
} else {
this._forwardForce *= this._decelerationFactor;
}
if (Math.abs(this._forwardForce) < this._eps) {
this._forwardForce = 0;
}
if (this._inputs.left && !this._inputs.right) {
this._turningForce = Math.max(
this._turningForce - this._turningAcceleration * delta,
-this._maxTurningForce,
);
} else if (!this._inputs.left && this._inputs.right) {
this._turningForce = Math.min(
this._turningForce + this._turningAcceleration * delta,
this._maxTurningForce,
);
} else {
this._turningForce *= this._turningDecelerationFactor;
}
if (Math.abs(this._turningForce) < this._eps * 0.1) {
this._turningForce = 0;
}
}
Force Application:
private _handleForces(delta) {
this._isSkidding = false;
if (this._isGrounded) {
const vel = this.body.getLinearVelocity();
const nVel = vel.clone().normalize();
const nSpeed = vel.length() / this._maxSpeed;
let turnDampen = Math.max(0, Math.min(1, nSpeed));
if (turnDampen > 0.5) {
turnDampen = Math.pow(Math.sin(turnDampen * 3.14), 1.4) + 0.5;
turnDampen = Math.min(1, turnDampen);
} else if (turnDampen > 0.0125) {
turnDampen = Math.pow(Math.sin(turnDampen * 3.14), 0.5);
} else {
turnDampen = 0;
}
const dragFactor =
nVel.length() === 0
? 0
: 1.0 - Math.abs(Vector3.Dot(nVel, this.chassis.forward));
if (dragFactor > 0.005 / nSpeed) {
this._isSkidding = true;
}
this.body.setLinearDamping(Scalar.Lerp(5, 15, dragFactor * dragFactor));
const alignQuat = Quaternion.FromLookDirectionLH(
this.chassis.forward.scale(-1),
this._rayCasts.center.results.hitNormalWorld,
);
this.chassis.rotationQuaternion = Quaternion.Slerp(
// @ts-expect-error is always set
this.chassis.rotationQuaternion,
alignQuat,
10 * delta,
);
const dir = Math.sign(this.currentVelZ);
this.chassis.rotate(
this.chassis.up,
this._turningForce * delta * turnDampen * dir,
Space.LOCAL,
);
const force = this.chassis.forward.scale(this._forwardForce);
this.body.applyForce(force, this.chassis.position);
const newVel = this.body.getLinearVelocity();
if (newVel.length() > this._maxSpeed) {
this.body.setLinearVelocity(newVel.normalize().scale(this._maxSpeed));
}
} else {
this._isSkidding = false;
this.body.setLinearDamping(0);
const alignQuat = Quaternion.FromLookDirectionLH(
this.chassis.forward.scale(-1),
this._rayCasts.centerAirborn.results.hitNormalWorld,
);
this.chassis.rotationQuaternion = Quaternion.Slerp(
// @ts-expect-error is always set
this.chassis.rotationQuaternion,
alignQuat,
6 * delta,
);
}
}
I know its hard to debug when just looking at code, but I’m hoping someone sees something sticking out.
Would using the fact I’m using deltaSeconds vs deltaTime be the reason this is not working? If I switch if over to deltaTime instead the whole system freaks out.