From e1b84249bec2ae013c3d04ecb84a697313a8a7b4 Mon Sep 17 00:00:00 2001 From: neu5 Date: Thu, 18 Jan 2024 07:59:21 +0100 Subject: [PATCH] Fix ts errors #265 (#266) * Fix ts errors #265 * TS errors fixes * Fix TS errors * Fix getting physics engine from the scene --- packages/client/src/utils/RaycastVehicle.ts | 98 ++++++++++++++------- packages/client/src/utils/RaycastWheel.ts | 39 +++++++- packages/client/src/utils/index.ts | 43 +++++++-- 3 files changed, 140 insertions(+), 40 deletions(-) diff --git a/packages/client/src/utils/RaycastVehicle.ts b/packages/client/src/utils/RaycastVehicle.ts index 14285b2..32018ca 100644 --- a/packages/client/src/utils/RaycastVehicle.ts +++ b/packages/client/src/utils/RaycastVehicle.ts @@ -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); @@ -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(); @@ -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; + physicsEngine: PhysicsEngine; + speed: number; + antiRollAxles: Array; + + 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; @@ -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(), @@ -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) @@ -115,7 +133,7 @@ class RaycastVehicle { this.nWheelsOnGround++; } - updateWheelSuspension(wheel) { + updateWheelSuspension(wheel: RaycastWheel) { if (!wheel.inContact) { wheel.prevSuspensionLength = wheel.suspensionLength; wheel.hitDistance = wheel.suspensionRestLength; @@ -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; @@ -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( @@ -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( @@ -175,7 +203,7 @@ class RaycastVehicle { ); } - updateWheelForce(wheel) { + updateWheelForce(wheel: RaycastWheel) { if (!wheel.inContact) return; if (wheel.force !== 0) { const forwardDirectionWorld = Vector3.TransformNormalToRef( @@ -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) @@ -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; diff --git a/packages/client/src/utils/RaycastWheel.ts b/packages/client/src/utils/RaycastWheel.ts index 34347dc..22fe102 100644 --- a/packages/client/src/utils/RaycastWheel.ts +++ b/packages/client/src/utils/RaycastWheel.ts @@ -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(); diff --git a/packages/client/src/utils/index.ts b/packages/client/src/utils/index.ts index 2789341..2b11ed2 100644 --- a/packages/client/src/utils/index.ts +++ b/packages/client/src/utils/index.ts @@ -3,6 +3,7 @@ import { Color3, MeshBuilder, PhysicsBody, + PhysicsEngine, PhysicsMotionType, PhysicsShapeConvexHull, Quaternion, @@ -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"; @@ -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 @@ -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; @@ -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); });