Skip to content

Commit

Permalink
Fix ts errors #265 (#266)
Browse files Browse the repository at this point in the history
* Fix ts errors #265

* TS errors fixes

* Fix TS errors

* Fix getting physics engine from the scene
  • Loading branch information
neu5 authored Jan 18, 2024
1 parent 32f575e commit e1b8424
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 40 deletions.
98 changes: 67 additions & 31 deletions packages/client/src/utils/RaycastVehicle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {
Vector3,
} from "@babylonjs/core";

const getBodyVelocityAtPoint = (body, point) => {
import type { RaycastWheel } from "./RaycastWheel";
import type { PhysicsBody, PhysicsEngine, Scene } from "@babylonjs/core";

const getBodyVelocityAtPoint = (body: PhysicsBody, point: Vector3) => {
const r = point.subtract(body.transformNode.position);
const angularVelocity = body.getAngularVelocity();
Vector3.Cross(angularVelocity, r);
Expand All @@ -15,7 +18,7 @@ const getBodyVelocityAtPoint = (body, point) => {
return res;
};

const clampNumber = (num, a, b) =>
const clampNumber = (num: number, a: number, b: number) =>
Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));

const tmp1 = new Vector3();
Expand All @@ -30,10 +33,20 @@ rightAxisLocal.normalize();
const raycastResult = new PhysicsRaycastResult();

class RaycastVehicle {
constructor(body, scene) {
body: PhysicsBody;
nWheelsOnGround: number;
numberOfFramesToPredict: number;
predictionRatio: number;
scene: Scene;
wheels: Array<RaycastWheel>;
physicsEngine: PhysicsEngine;
speed: number;
antiRollAxles: Array<any>;

constructor(body: PhysicsBody, physicsEngine: PhysicsEngine, scene: Scene) {
this.body = body;
this.scene = scene;
this.physicsEngine = body._physicsEngine;
this.physicsEngine = physicsEngine;
this.wheels = [];
this.numberOfFramesToPredict = 60;
this.predictionRatio = 0.6;
Expand All @@ -42,25 +55,25 @@ class RaycastVehicle {
this.antiRollAxles = [];
}

addWheel(wheel) {
addWheel(wheel: RaycastWheel) {
this.wheels.push(wheel);
}

removeWheel(wheel, index) {
removeWheel(wheel: RaycastWheel, index: number) {
if (index) this.wheels.splice(index, 1);
this.wheels.splice(this.wheels.indexOf(wheel), 1);
}

addAntiRollAxle(axle) {
addAntiRollAxle(axle: { wheelA: number; wheelB: number; force: number }) {
this.antiRollAxles.push(axle);
}

removeAntiRollAxle(axle, index) {
removeAntiRollAxle(axle: Vector3, index: number) {
if (index) this.antiRollAxles.splice(index, 1);
this.antiRollAxles.splice(this.antiRollAxles.indexOf(axle), 1);
}

updateWheelTransform(wheel) {
updateWheelTransform(wheel: RaycastWheel) {
Vector3.TransformCoordinatesToRef(
wheel.positionLocal,
this.body.transformNode.getWorldMatrix(),
Expand All @@ -82,21 +95,26 @@ class RaycastVehicle {
this.speed = tmp1.z;
}

updateWheelSteering(wheel) {
updateWheelSteering(wheel: RaycastWheel) {
Quaternion.RotationAxisToRef(
wheel.suspensionAxisLocal.negateToRef(tmp1),
wheel.steering,
tmpq1
);
this.body.transformNode.rotationQuaternion.multiplyToRef(
tmpq1,
if (
this.body.transformNode.rotationQuaternion &&
wheel.transform.rotationQuaternion
);
wheel.transform.rotationQuaternion.normalize();
) {
this.body.transformNode.rotationQuaternion.multiplyToRef(
tmpq1,
wheel.transform.rotationQuaternion
);
wheel.transform.rotationQuaternion.normalize();
}
wheel.transform.computeWorldMatrix(true);
}

updateWheelRaycast(wheel) {
updateWheelRaycast(wheel: RaycastWheel) {
tmp1
.copyFrom(wheel.suspensionAxisWorld)
.scaleInPlace(wheel.suspensionRestLength)
Expand All @@ -115,7 +133,7 @@ class RaycastVehicle {
this.nWheelsOnGround++;
}

updateWheelSuspension(wheel) {
updateWheelSuspension(wheel: RaycastWheel) {
if (!wheel.inContact) {
wheel.prevSuspensionLength = wheel.suspensionLength;
wheel.hitDistance = wheel.suspensionRestLength;
Expand All @@ -135,9 +153,15 @@ class RaycastVehicle {
const compressionForce = wheel.suspensionForce * compressionRatio;
force += compressionForce;

const rate =
(wheel.prevSuspensionLength - wheel.suspensionLength) /
this.scene.getPhysicsEngine().getTimeStep();
const physicsEngine = this.scene.getPhysicsEngine();
let rate = 0;

if (physicsEngine !== null) {
rate =
(wheel.prevSuspensionLength - wheel.suspensionLength) /
physicsEngine.getTimeStep();
}

wheel.prevSuspensionLength = wheel.suspensionLength;

const dampingForce = rate * wheel.suspensionForce * wheel.suspensionDamping;
Expand All @@ -152,7 +176,7 @@ class RaycastVehicle {
this.body.applyForce(suspensionForce, wheel.hitPoint);
}

updateWheelSideForce(wheel) {
updateWheelSideForce(wheel: RaycastWheel) {
if (!wheel.inContact) return;
const tireWorldVel = getBodyVelocityAtPoint(this.body, wheel.positionWorld);
const steeringDir = Vector3.TransformNormalToRef(
Expand All @@ -162,8 +186,12 @@ class RaycastVehicle {
);
const steeringVel = Vector3.Dot(steeringDir, tireWorldVel);
const desiredVelChange = -steeringVel;
const desiredAccel =
desiredVelChange / this.scene.getPhysicsEngine().getTimeStep();
const physicsEngine = this.scene.getPhysicsEngine();
let desiredAccel = 0;

if (physicsEngine) {
desiredAccel = desiredVelChange / physicsEngine.getTimeStep();
}
this.body.applyForce(
steeringDir.scaleInPlace(wheel.sideForce * desiredAccel),
Vector3.LerpToRef(
Expand All @@ -175,7 +203,7 @@ class RaycastVehicle {
);
}

updateWheelForce(wheel) {
updateWheelForce(wheel: RaycastWheel) {
if (!wheel.inContact) return;
if (wheel.force !== 0) {
const forwardDirectionWorld = Vector3.TransformNormalToRef(
Expand All @@ -190,17 +218,20 @@ class RaycastVehicle {
}
}

updateWheelRotation(wheel) {
updateWheelRotation(wheel: RaycastWheel) {
wheel.rotation += this.speed * wheel.rotationMultiplier * wheel.radius;
Quaternion.RotationAxisToRef(wheel.axleAxisLocal, wheel.rotation, tmpq1);
wheel.transform.rotationQuaternion.multiplyToRef(
tmpq1,
wheel.transform.rotationQuaternion
);
wheel.transform.rotationQuaternion.normalize();

if (wheel.transform.rotationQuaternion) {
wheel.transform.rotationQuaternion.multiplyToRef(
tmpq1,
wheel.transform.rotationQuaternion
);
wheel.transform.rotationQuaternion.normalize();
}
}

updateWheelTransformPosition(wheel) {
updateWheelTransformPosition(wheel: RaycastWheel) {
wheel.transform.position.copyFrom(wheel.positionWorld);
wheel.transform.position.addInPlace(
wheel.suspensionAxisWorld.scale(wheel.hitDistance - wheel.radius)
Expand All @@ -213,7 +244,12 @@ class RaycastVehicle {
const gravity = tmp1
.copyFrom(this.physicsEngine.gravity)
.scaleInPlace(this.body.getGravityFactor());
const frameTime = this.scene.getPhysicsEngine().getTimeStep();

const physicsEngine = this.scene.getPhysicsEngine();
let frameTime = 0;
if (physicsEngine) {
frameTime = physicsEngine.getTimeStep();
}
const predictTime = this.numberOfFramesToPredict * frameTime;

const predictedPosition = tmp2;
Expand Down
39 changes: 38 additions & 1 deletion packages/client/src/utils/RaycastWheel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
import { Quaternion, TransformNode, Vector3 } from "@babylonjs/core";

class RaycastWheel {
constructor(options) {
positionLocal: Vector3;
positionWorld: Vector3;
suspensionAxisLocal: Vector3;
suspensionAxisWorld: Vector3;
axleAxisLocal: Vector3;
forwardAxisLocal: Vector3;
sideForce: number;
sideForcePositionRatio: number;
radius: number;
suspensionRestLength: number;
prevSuspensionLength: number;
suspensionLength: number;
suspensionForce: number;
suspensionDamping: number;
rotationMultiplier: number;
hitDistance: number;
hitNormal: Vector3;
hitPoint: Vector3;
inContact: boolean;
steering: number;
rotation: number;
force: number;
transform: TransformNode;

constructor(options: {
positionLocal: Vector3;
positionWorld?: Vector3;
suspensionAxisLocal: Vector3;
axleAxisLocal: Vector3;
forwardAxisLocal: Vector3;
sideForce?: number;
sideForcePositionRatio: number;
radius?: number;
suspensionRestLength?: number;
suspensionForce?: number;
suspensionDamping?: number;
rotationMultiplier?: number;
}) {
this.positionLocal = options.positionLocal.clone();
this.positionWorld = options.positionLocal.clone();
this.suspensionAxisLocal = options.suspensionAxisLocal.clone();
Expand Down
43 changes: 35 additions & 8 deletions packages/client/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Color3,
MeshBuilder,
PhysicsBody,
PhysicsEngine,
PhysicsMotionType,
PhysicsShapeConvexHull,
Quaternion,
Expand All @@ -11,7 +12,12 @@ import {
Vector3,
} from "@babylonjs/core";

import type { Scene, ShadowGenerator } from "@babylonjs/core";
import type {
InstancedMesh,
Mesh,
Scene,
ShadowGenerator,
} from "@babylonjs/core";
import type { GameQuaternion, Position } from "@neu5/types/src";

import { RaycastVehicle } from "./RaycastVehicle";
Expand Down Expand Up @@ -196,21 +202,31 @@ const addVehicle = ({
});
chassisPhysicsShape.filterMembershipMask = 2;

const wheelMesh = MeshBuilder.CreateCylinder("WheelMesh", {
let wheelMesh = MeshBuilder.CreateCylinder("WheelMesh", {
height: 0.3,
diameter: 0.4,
});
}) as Mesh | InstancedMesh;
const wheelMeshes = [
wheelMesh,
wheelMesh.createInstance(1),
wheelMesh.createInstance(2),
wheelMesh.createInstance(3),
wheelMesh.createInstance("1"),
wheelMesh.createInstance("2"),
wheelMesh.createInstance("3"),
];
wheelMeshes.forEach((mesh) => {
mesh.rotationQuaternion = new Quaternion();
});

const vehicle = new RaycastVehicle(chassisPhysicsBody, scene);
const physicsEngine = scene.getPhysicsEngine();
let vehicle: RaycastVehicle | null = null;

if (physicsEngine instanceof PhysicsEngine) {
vehicle = new RaycastVehicle(chassisPhysicsBody, physicsEngine, scene);
}

if (vehicle === null) {
return;
}

vehicle.numberOfFramesToPredict = 20; //Number of frames to predict future upwards orientation if airborne
vehicle.predictionRatio = 1; //[0-1]How quickly to correct angular velocity towards future orientation. 0 = disabled

Expand Down Expand Up @@ -260,6 +276,11 @@ const addVehicle = ({
steerValue += steerDirection * steeringIncrement;
steerValue = Math.min(Math.max(steerValue, -maxSteerValue), maxSteerValue);
steerValue *= 1 - (1 - Math.abs(steerDirection)) * steerRecover;

if (vehicle === null) {
return;
}

vehicle.wheels[2].steering = steerValue;
vehicle.wheels[3].steering = steerValue;

Expand All @@ -272,7 +293,13 @@ const addVehicle = ({
if (!wheelMeshes[index]) return;
wheelMesh = wheelMeshes[index];
wheelMesh.position.copyFrom(wheel.transform.position);
wheelMesh.rotationQuaternion.copyFrom(wheel.transform.rotationQuaternion);

if (wheelMesh.rotationQuaternion && wheel.transform.rotationQuaternion) {
wheelMesh.rotationQuaternion.copyFrom(
wheel.transform.rotationQuaternion
);
}

wheelMesh.rotate(Axis.Z, Math.PI / 2, Space.LOCAL);
});

Expand Down

0 comments on commit e1b8424

Please sign in to comment.