@needle-tools/car-physics
Version:
Car physics for Needle Engine: Create physical cars with ease
2 lines (1 loc) • 21.2 kB
JavaScript
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("@needle-tools/engine"),p=require("three");var C=(o=>(o[o.all=0]="all",o[o.rear=1]="rear",o[o.front=2]="front",o))(C||{}),v=(o=>(o[o.front=0]="front",o[o.rear=1]="rear",o))(v||{}),A=Object.defineProperty,b=(o,e,s,n)=>{for(var i=void 0,r=o.length-1,a;r>=0;r--)(a=o[r])&&(i=a(e,s,i)||i);return i&&A(e,s,i),i};const z=t.getParam("debugwheels");class h extends t.Behaviour{get index(){return this._wheelIndex}wheelModel;axle=v.front;radius=-1;suspensionRestLength=-1;maxSuspensionTravel=-1;suspensionCompression=3;suspensionRelax=5;suspensionStiff=-1;maxSuspensionForce=-1;sideFrictionStiffness=.7;frictionSlip=new p.Vector2(1,20);skidParticle;skidVisualSideThreshold=5;skidVisualBreakThreshold=.1;skidParticleBehaviour;wheelModelRight;wheelModelUp;car;vehicle;_wheelIndex=-1;_activeRadius=-1;_initialQuaternion;async initialize(e,s,n){this.car=e,this.vehicle=s,this._wheelIndex=n;const i=this.wheelModel||this.gameObject;let r=this.radius;if(r<=0&&(r=t.getBoundingBox(i).getSize(t.getTempVector()).y*.5),r<0){console.error("CarWheel: Radius is invalid, please set it manually or make sure the wheel is attached to a model");return}this._activeRadius=Math.max(.01,r),this._initialQuaternion=i.quaternion.clone(),this.wheelModel?.quaternion.identity(),this.gameObject?.quaternion.identity();const a=e.gameObject.worldQuaternion.clone();e.gameObject.worldQuaternion=new p.Quaternion;const l=new p.Quaternion;l.copy(e.gameObject.worldQuaternion).multiply(i.worldQuaternion.clone().invert()),e.gameObject.worldQuaternion=a,this.wheelModelUp=new p.Vector3(0,1,0).clone().applyQuaternion(l),this.wheelModelRight=new p.Vector3(1,0,0).clone().applyQuaternion(l);const S=i.worldPosition,m=this.car.gameObject.worldToLocal(S);m.multiply(this.car.gameObject.worldScale),m.y+=this._activeRadius*.5;const g=t.getTempVector(0,-1,0),y=t.getTempVector(-1,0,0);let d=this.suspensionRestLength;(!d||d<=0)&&(d=this._activeRadius*.5);let f=this.maxSuspensionTravel;(!f||f<=0)&&(f=this._activeRadius*.5);let c=this.suspensionStiff;(!c||c<=0)&&(c=50);let u=this.maxSuspensionForce;(!u||u<=0)&&(u=1e8),z&&console.debug(this.name,{restLength:d,suspensionTravel:f,suspensionStiff:c,maxSupsensionForce:u,radius:this._activeRadius},this),this.vehicle.addWheel(m,g,y,d,this._activeRadius),this.vehicle.setWheelMaxSuspensionTravel(n,f),this.vehicle.setWheelMaxSuspensionForce(n,u),this.vehicle.setWheelSuspensionStiffness(n,c),this.vehicle.setWheelSuspensionCompression(n,this.suspensionCompression),this.vehicle.setWheelSuspensionRelaxation(n,this.suspensionRelax),this.vehicle.setWheelSideFrictionStiffness(n,this.sideFrictionStiffness),this.vehicle.setWheelFrictionSlip(n,this.frictionSlip.y),this.skidParticle&&(this.skidParticleBehaviour=new B,this.skidParticle.addBehaviour(this.skidParticleBehaviour))}applyPhysics(e,s,n){this.car.carDrive==C.front&&this.axle==v.front||this.car.carDrive==C.rear&&this.axle==v.rear||this.car.carDrive==C.all||(e=0),this.vehicle.setWheelEngineForce(this._wheelIndex,e),this.vehicle.setWheelBrake(this._wheelIndex,s),this.axle==v.front&&this.vehicle.setWheelSteering(this._wheelIndex,-n);let a=t.getTempVector(this.car.velocity).clampLength(0,1).dot(this.car.gameObject.worldRight);a=1-Math.abs(a);const l=t.Mathf.lerp(this.frictionSlip.x,this.frictionSlip.y,a);this.vehicle.setWheelFrictionSlip(this._wheelIndex,l)}updateVisuals(){const e=this.wheelModel||this.gameObject,s=this.vehicle.wheelRotation(this._wheelIndex),n=this.vehicle.wheelSteering(this._wheelIndex),i=t.getTempQuaternion().setFromAxisAngle(this.wheelModelUp,n),r=t.getTempQuaternion().setFromAxisAngle(this.wheelModelRight,s),a=i.multiply(r);e.quaternion.copy(a),e.quaternion.multiply(this._initialQuaternion);const l=this.vehicle.wheelContactPoint(this._wheelIndex),S=this.vehicle.wheelIsInContact(this._wheelIndex),m=t.getTempVector();if(l&&(z&&t.Gizmos.DrawWireSphere(l,.02,16777045,0,!1),m.copy(this.car.gameObject.worldUp).multiplyScalar(this._activeRadius),m.add(l),e.worldPosition=m),this.skidParticleBehaviour){const g=Math.abs(this.vehicle.wheelSideImpulse(this._wheelIndex)??0),y=Math.abs(this.vehicle.wheelBrake(this._wheelIndex)??0),d=g>this.skidVisualSideThreshold||y>this.skidVisualBreakThreshold,f=S&&l!=null&&d;if(this.skidParticle&&l){const c=t.getTempVector(l);c.y+=this.skidParticle.main.startSize.constant/4,this.skidParticle.worldPosition=c}this.skidParticleBehaviour.isSkidding=f}if(z){const g=this._activeRadius*.1,y=t.getTempVector(this.car.gameObject.worldRight).multiplyScalar(-1);y.applyEuler(new p.Euler(0,n,0)),t.Gizmos.DrawCircle(m,y,this._activeRadius,255,0,!1);const d=t.getTempVector(m),f=t.getTempVector(m).add(t.getTempVector(y).multiplyScalar(this._activeRadius));t.Gizmos.DrawLine(d,f,16711680,0,!1),t.Gizmos.DrawSphere(f,g,16711680,0,!1);const c=t.getTempVector(this.car.gameObject.worldForward).multiplyScalar(this._activeRadius*1);c.applyEuler(new p.Euler(0,n,0));const u=t.getTempVector(m).add(c);t.Gizmos.DrawLine(m,u,255,0,!1),t.Gizmos.DrawSphere(u,g,255,0,!1)}}}b([t.serializable(p.Object3D)],h.prototype,"wheelModel");b([t.serializable()],h.prototype,"axle");b([t.serializable()],h.prototype,"radius");b([t.serializable()],h.prototype,"suspensionRestLength");b([t.serializable()],h.prototype,"maxSuspensionTravel");b([t.serializable()],h.prototype,"suspensionCompression");b([t.serializable()],h.prototype,"suspensionRelax");b([t.serializable()],h.prototype,"suspensionStiff");b([t.serializable()],h.prototype,"maxSuspensionForce");b([t.serializable()],h.prototype,"sideFrictionStiffness");b([t.serializable(p.Vector2)],h.prototype,"frictionSlip");b([t.serializable(t.ParticleSystem)],h.prototype,"skidParticle");b([t.serializable()],h.prototype,"skidVisualSideThreshold");b([t.serializable()],h.prototype,"skidVisualBreakThreshold");class B extends t.ParticleSystemBaseBehaviour{isSkidding=!1;update(e,s){const n=e;if(this.system.trails?.enabled&&n){this.isSkidding||e.color.setW(0);let i=n.previous?.tail;for(;i&&i.hasPrev();){const r=i;r.data??={},r.data.isSkidding===void 0&&(r.data.isSkidding=this.isSkidding),r.data.isSkidding===!1&&i.data.color?.setW(0),i=i.prev}}}}var D=Object.defineProperty,R=(o,e,s,n)=>{for(var i=void 0,r=o.length-1,a;r>=0;r--)(a=o[r])&&(i=a(e,s,i)||i);return i&&D(e,s,i),i};const T=t.getParam("debugcar");class x extends t.Behaviour{carDrive=C.all;mass=500;maxSteer=40;steerSmoothingFactor=.1;accelerationForce=12;breakForce=12;topSpeed=25;wheels=[];steerImpulse(e){this._steerInput+=e,this._steerInput=t.Mathf.clamp(this._steerInput,-1,1)}get currentSteer(){return this._currentSteer}set currentSteer(e){this._currentSteer=e}accelerationImpulse(e){this._currAcc+=e}breakImpulse(e){this._currBreak+=e}get rigidbody(){return this._rigidbody}get rapierRigidbody(){return this.context.physics.engine?.getBody(this._rigidbody)}get vehicle(){return this._vehicle}get velocity(){return this._rigidbody?.getVelocity()}get currentSpeed(){return this._vehicle?.currentVehicleSpeed()||0}get currentSpeedInKmh(){return this.currentSpeed*3.6}get maxSpeedInKmh(){return this.topSpeed*3.6}get currentSpeed01(){return this._vehicle?this._vehicle.currentVehicleSpeed()/this.topSpeed:0}get airtime(){return this._airtime}set airtime(e){this._airtime=e}_vehicle;_rigidbody;_currentSteer=0;_currAcc=0;_currBreak=0;_steerInput=0;_airtime=0;awake(){if(this._rigidbody||(this._rigidbody=this.gameObject.addComponent(t.Rigidbody)),!this.gameObject.getComponentInChildren(t.BoxCollider)){const e=t.BoxCollider.add(this.gameObject),s=new p.Object3D;s.addComponent(e),this.gameObject.add(s),s.position.copy(e.center),e.center.set(0,0,0),e.center.y+=e.size.y*.1,e.size.x*=.85,e.size.y*=.7,e.size.z*=.85,e.updateProperties()}}_physicsRoutine;async onEnable(){if(this.mass<=0&&(this.mass=1),this._rigidbody=this.gameObject.getOrAddComponent(t.Rigidbody),this._rigidbody.mass=this.mass,this._rigidbody.autoMass=this.mass<=0,await this.context.physics.engine?.initialize().then(()=>t.delayForFrames(1)),!this.activeAndEnabled)return;const e=this.context.physics.engine?.world;if(!e){console.error("[CarPhysics] Physics world not found");return}if(!this.rapierRigidbody){console.error("[CarPhysics] Rigidbody not found");return}if(this._vehicle||(this._vehicle=e.createVehicleController(this.rapierRigidbody)),this._vehicle.indexUpAxis=1,this._vehicle.setIndexForwardAxis=2,this.wheels.length===0&&this.wheels.push(...this.gameObject.getComponentsInChildren(h).filter(s=>s.activeAndEnabled)),this.wheels.length<=0){console.debug(`[CarPhysics] No wheels found on ${this.gameObject.name}, trying to find them`);const s=L(this);s.length>0&&(console.debug(`[CarPhysics] Found ${s.length} wheels: ${s.map(n=>`${n.name} (${v[n.axle]})`).join(", ")}`),this.wheels.push(...s))}this.wheels.length<=0&&console.warn(`[CarPhysics] No wheels found on ${this.gameObject.name}`),T&&console.log(`[CarPhysics] ${this.name} has ${this.wheels.length} wheels:`,this.wheels),this.wheels.forEach((s,n)=>{s.initialize(this,this._vehicle,n)}),this._physicsRoutine=this.startCoroutine(this.physicsLoop(),t.FrameEvent.PostPhysicsStep)}onDisable(){this._vehicle&&this.context.physics.engine?.world?.removeVehicleController(this._vehicle),this._vehicle?.free(),this._vehicle=null,this._physicsRoutine&&this.stopCoroutine(this._physicsRoutine)}onBeforeRender(){if(!this._vehicle)return;if(this.steerSmoothingFactor>0){const s=this.context.time.deltaTime/this.steerSmoothingFactor;this._currentSteer=t.Mathf.lerp(this._currentSteer,this._steerInput,t.Mathf.clamp01(s))}else this._currentSteer=this._steerInput;this.applyPhysics(),this._steerInput=0,this._currAcc=0,this._currBreak=0;let e=!1;if(this.wheels.forEach(s=>{s.updateVisuals(),e||(e||=this._vehicle.wheelIsInContact(s.index))}),e?this._airtime=0:this._airtime+=this.context.time.deltaTime,T){const s=this._vehicle.chassis(),n=s.translation(),i=t.getTempVector(n).add(t.getTempVector(0,2,0)),r=`vel: ${this._vehicle.currentVehicleSpeed().toFixed(2)}`;t.Gizmos.DrawLabel(i,r,.1,0,16777215,0),this.wheels.forEach(a=>{const l=this._vehicle.wheelChassisConnectionPointCs(a.index);l&&t.Gizmos.DrawLine(t.getTempVector(n),t.getTempVector(l).applyQuaternion(s.rotation()).add(n),255,0,!1)})}}teleport(e,s,n=!0){!this.rapierRigidbody||!this._vehicle||(e&&this.rapierRigidbody.setTranslation(e,!0),s&&this.rapierRigidbody.setRotation(s,!0),n&&this._rigidbody.setVelocity(0,0,0))}*physicsLoop(){for(;;){if(this._vehicle){const e=this.context.time.deltaTime;this._vehicle?.updateVehicle(e)}yield null}}applyPhysics(){this._currAcc=t.Mathf.clamp(this._currAcc,-1,1);let e=this._currAcc===0?.2:0,s=0;const n=this._rigidbody.getVelocity(),i=this._vehicle.currentVehicleSpeed(),r=i>this.topSpeed,a=this.context.time.deltaTime*this.mass*this.currentSpeed01*20;this._rigidbody.applyImpulse(t.getTempVector(0,-a,0)),this._currAcc<0&&i>.05&&n.dot(this.gameObject.worldForward)>0&&(e=this.breakForce*-this._currAcc),e+=Math.max(0,this._currBreak)*this.breakForce,this._currAcc!=0&&!r&&(s=this.accelerationForce/this.context.time.deltaTime*this._currAcc);const m=t.Mathf.lerp(this.maxSteer,this.maxSteer*.5,this.currentSpeed01),g=this._currentSteer*m*t.Mathf.Deg2Rad;this.wheels.forEach(y=>{y.applyPhysics(s,e,g)})}}R([t.serializable()],x.prototype,"carDrive");R([t.serializable()],x.prototype,"mass");R([t.serializable()],x.prototype,"maxSteer");R([t.serializable()],x.prototype,"steerSmoothingFactor");R([t.serializable()],x.prototype,"accelerationForce");R([t.serializable()],x.prototype,"breakForce");R([t.serializable()],x.prototype,"topSpeed");R([t.serializable(h)],x.prototype,"wheels");function L(o){const e=new Array;if(s(o.gameObject),e.length<=0){const n=o.gameObject.worldPosition,i=o.gameObject.worldQuaternion;o.gameObject.worldPosition=new p.Vector3,o.gameObject.worldQuaternion=new p.Quaternion;const r=t.getBoundingBox(o.gameObject);o.gameObject.worldQuaternion=i,o.gameObject.worldPosition=n;const a=r.max.y-r.min.y,l=Math.max(r.max.x-r.min.x,r.max.z-r.min.z),S=a/l,g=r.getSize(new p.Vector3).length()*.1,y=r.min.y;let d=(r.max.x-r.min.x)*.1,f=(r.max.z-r.min.z)*.1;S>1&&(d*=-S*1.5,f*=-S*1.5);const c=new p.Object3D;c.position.set(r.min.x+d,y,r.max.z-f),c.name="WheelFrontLeft",e.push(c.addComponent(h,{axle:v.front,radius:g})),o.gameObject.add(c);const u=new p.Object3D;u.position.set(r.max.x-d,y,r.max.z-f),u.name="WheelFrontRight",e.push(u.addComponent(h,{axle:v.front,radius:g})),o.gameObject.add(u);const w=new p.Object3D;w.position.set(r.min.x+d,y,r.min.z+f),w.name="WheelRearLeft",e.push(w.addComponent(h,{axle:v.rear,radius:g})),o.gameObject.add(w);const _=new p.Object3D;_.position.set(r.max.x-d,y,r.min.z+f),_.name="WheelRearRight",e.push(_.addComponent(h,{axle:v.rear,radius:g})),o.gameObject.add(_)}return e;function s(n){for(const i of n.children){const r=i.name.toLowerCase();if(r.includes("wheel")&&!i.getComponent(h)){const a=r.includes("front")||r.includes("fl")||r.includes("fr"),l=i.addComponent(h,{axle:a?v.front:v.rear});e.push(l)}}for(const i of n.children){if(e.length>0)break;i instanceof p.Object3D&&s(i)}}}var E=Object.defineProperty,O=(o,e,s,n)=>{for(var i=void 0,r=o.length-1,a;r>=0;r--)(a=o[r])&&(i=a(e,s,i)||i);return i&&E(e,s,i),i};class P extends t.Behaviour{carPhysics;autoReset=!0;manualReset=!0;onReset=new t.EventList;reset(){this.carPhysics?.teleport(this.posOnStart,this.rotOnStart,!0),this.context.mainCamera.getComponent(t.OrbitControls)?.setCameraTargetPosition(this.camStartPos,!0),this.onReset?.invoke()}posOnStart;rotOnStart;camStartPos;start(){this.posOnStart=this.gameObject.worldPosition.clone(),this.rotOnStart=this.gameObject.worldQuaternion.clone(),this.camStartPos=this.context.mainCamera.position.clone()}onEnable(){this.carPhysics||=this.gameObject.getComponent(x),window.addEventListener("blur",this.onBlur)}onDisable(){window.removeEventListener("blur",this.onBlur)}onBeforeRender(){this.handleInput(),this.manualReset&&this.context.input.isKeyDown("r")&&this.reset(),this.autoReset&&(this.resetWhenRolledOver(),this.resetWhenFallingoff())}onBlur=e=>{if(!this.context.application.hasFocus){const s=navigator.getGamepads()?.[0];s&&s.vibrationActuator?.playEffect("dual-rumble",{startDelay:0,duration:0,weakMagnitude:1,strongMagnitude:1})}};_lastResetTime=-1;resetWhenFallingoff(){this.carPhysics&&this.carPhysics.airtime>5&&this.context.time.realtimeSinceStartup-this._lastResetTime>5&&(this._lastResetTime=this.context.time.realtimeSinceStartup,this.reset())}rolledOverDuration=0;resetWhenRolledOver(){if(!this.carPhysics)return;const e=this.gameObject.worldUp.dot(t.getTempVector(0,1,0))<.65,n=this.carPhysics.rigidbody.getVelocity().length()<.1;e&&n?this.rolledOverDuration+=this.context.time.deltaTime:this.rolledOverDuration=0,this.rolledOverDuration>1&&this.rescueVehicle()}async rescueVehicle(){if(!this.carPhysics)return;const e=this.gameObject.worldPosition;e.y+=1;const s=this.gameObject.worldForward;s.y=0,s.normalize();const n=t.getTempQuaternion().setFromUnitVectors(t.getTempVector(0,0,-1),s);this.carPhysics.teleport(e,n)}_lastVehicleVelocity=0;_lastHeroRumbleTime=-1;_currentSteer=0;_currentSteerAccum=0;handleInput(){if(!this.carPhysics?.vehicle)return;let e=0,s=0,n=0;if(this.context.xr){s+=this.context.xr.rightController?.getButton("a-button")?.value||0,s-=this.context.xr.leftController?.getButton("x-button")?.value||0;const r=this.context.xr.rightController?.getButton("xr-standard-squeeze")?.value||0,a=this.context.xr.leftController?.getButton("xr-standard-squeeze")?.value||0;if(r>.5&&a>.5){const l=this.context.xr.leftController.gripPosition.y-this.context.xr.rightController.gripPosition.y;e=t.Mathf.clamp(l,-2,2)}}else this.context.input.isKeyPressed("a")||this.context.input.isKeyPressed("ArrowLeft")?e-=1:(this.context.input.isKeyPressed("d")||this.context.input.isKeyPressed("ArrowRight"))&&(e+=1),(this.context.input.isKeyPressed("s")||this.context.input.isKeyPressed("ArrowDown"))&&(s-=1),(this.context.input.isKeyPressed("w")||this.context.input.isKeyPressed("ArrowUp"))&&(s+=1),this.context.input.isKeyPressed(" ")&&(n+=1);const i=navigator.getGamepads()?.[0];if(i?.connected){const r=i.axes[0],a=i.axes[1];if(Math.abs(r)>.01){const c=r<0?-1:1;e+=Math.pow(r,2)*c}Math.abs(a)>.01&&(s-=a);const l=i.buttons[0],S=i.buttons[1],m=i.buttons[6],g=i.buttons[7];(l.pressed||g.pressed)&&(s+=1),(S.pressed||m.pressed)&&(s-=1),i.buttons[2].pressed&&this.reset();const d=this.carPhysics.velocity.length();if(this.context.time.realtimeSinceStartup-this._lastHeroRumbleTime>.3){d>.01&&i.vibrationActuator?.playEffect("dual-rumble",{startDelay:0,duration:this.context.time.deltaTime,weakMagnitude:.1,strongMagnitude:.1});const c=this.carPhysics.wheels,u=200;let w=0;for(const _ of c){const k=this.carPhysics.vehicle.wheelSuspensionForce(_.index);if(k&&k<u){const F=1-k/u;w=Math.max(w,F)}}if(w>0){const _=Math.pow(w,2);i.vibrationActuator?.playEffect("dual-rumble",{startDelay:0,duration:w*500,weakMagnitude:_*1,strongMagnitude:_*1})}}if(d){const c=this._lastVehicleVelocity;this._lastVehicleVelocity=d;const u=c-d;u>1&&(this._lastHeroRumbleTime=this.context.time.realtimeSinceStartup,i.vibrationActuator?.playEffect("dual-rumble",{startDelay:0,duration:150,weakMagnitude:t.Mathf.clamp01(u/3),strongMagnitude:t.Mathf.clamp01(u/3)}))}}e*=Math.max(.2,Math.min(1,2*Math.abs(this.carPhysics.currentSteer))),this._currentSteer=t.Mathf.lerp(this._currentSteer,e,this.context.time.deltaTime/.12),this.carPhysics.steerImpulse(this._currentSteer),this.carPhysics.breakImpulse(n),this.carPhysics.accelerationImpulse(s)}}O([t.serializable(x)],P.prototype,"carPhysics");O([t.serializable()],P.prototype,"autoReset");O([t.serializable()],P.prototype,"manualReset");O([t.serializable(t.EventList)],P.prototype,"onReset");var W=Object.defineProperty,Q=(o,e,s,n)=>{for(var i=void 0,r=o.length-1,a;r>=0;r--)(a=o[r])&&(i=a(e,s,i)||i);return i&&W(e,s,i),i};class I extends t.Behaviour{carPhysics;steerLeftState=0;steerRightState=0;throttleState=0;breakState=0;update(){this.throttleInput(),this.steerInput()}throttleInput(){this.carPhysics?.accelerationImpulse(t.Mathf.clamp(this.throttleState+this.breakState,-1,1))}steerInput(){this.carPhysics?.steerImpulse(t.Mathf.clamp(this.steerLeftState+this.steerRightState,-1,1))}steerLeftPress(){this.steerLeftState=-1}steerLeftRelease(){this.steerLeftState=0}steerRightPress(){this.steerRightState=1}steerRightRelease(){this.steerRightState=0}throttlePress(){this.throttleState=1}throttleRelease(){}brakePress(){this.throttleState=0,this.breakState=-1}brakeRelease(){this.breakState=0}}Q([t.serializable(x)],I.prototype,"carPhysics");var $=Object.defineProperty,V=(o,e,s,n)=>{for(var i=void 0,r=o.length-1,a;r>=0;r--)(a=o[r])&&(i=a(e,s,i)||i);return i&&$(e,s,i),i};class j extends t.Behaviour{cameraRig=null;cars;awake(){this.cars??=[]}start(){this.cars?.length||(this.cars=[...t.GameObject.findObjectsOfType(P)]),this.cars.length>0&&this.selectCarByIndex(0)}onEnable(){this.context.input.addEventListener("keyup",this.onKey),this.context.domElement.addEventListener("click",this.onClick)}onDisable(){this.context.input.removeEventListener("keyup",this.onKey),this.context.domElement.removeEventListener("click",this.onClick)}selectCar(e){this.cars||(this.cars=[]);let s=this.cars.indexOf(e);s===-1&&(this.cars.push(e),s=this.cars.length-1),this.selectCarByIndex(s)}gamepadButtonDown=!1;update(){const e=navigator.getGamepads()?.[0];if(e)if(e.buttons?.[3]?.pressed){if(!this.gamepadButtonDown){this.gamepadButtonDown=!0;const n=this.cars.find(i=>i.activeAndEnabled);if(n){const r=((n?this.cars.indexOf(n):-1)+1)%this.cars.length;this.selectCarByIndex(r)}}}else this.gamepadButtonDown&&(this.gamepadButtonDown=!1)}onKey=e=>{const s=parseInt(e.key)-1;s>=0&&s<this.cars.length&&this.selectCarByIndex(s)};onClick=e=>{if(!this.cars?.length||e instanceof MouseEvent&&e.button!=0)return;const s=this.context.physics.raycast();if(s.length){const n=s[0]?.object.getComponentInParent(P),i=n?this.cars.indexOf(n):-1;i>=0&&this.selectCarByIndex(i)}};selectCarByIndex(e){for(const n of this.cars)n&&(n.enabled=!1);const s=this.cars[e];if(s){s.enabled=!0;const n=t.findObjectOfType(I);n&&(n.carPhysics=s.gameObject.getComponentInChildren(x)||void 0);const i=s.gameObject.getComponentInChildren(t.Camera);if(i)this.context.setCurrentCamera(i);else if(this.cameraRig){this.context.setCurrentCamera(this.cameraRig);const r=this.cameraRig.gameObject.getComponentInParent(t.SmoothFollow);r&&(r.target=s.gameObject)}}}}V([t.serializable(t.Camera)],j.prototype,"cameraRig");V([t.serializable(P)],j.prototype,"cars");var K=Object.defineProperty,q=(o,e,s,n)=>{for(var i=void 0,r=o.length-1,a;r>=0;r--)(a=o[r])&&(i=a(e,s,i)||i);return i&&K(e,s,i),i};class M extends t.Behaviour{url="https://stream.laut.fm/gta-classics";_audio=null;onEnable(){this.url&&(this._audio=new Audio(this.url),this._audio.autoplay=!0,t.Application.registerWaitForInteraction(()=>{this.enabled&&this._audio?.play()}))}onDisable(){this._audio?.pause()}}q([t.serializable()],M.prototype,"url");exports.CarAxle=v;exports.CarController=P;exports.CarDrive=C;exports.CarPhysics=x;exports.CarRadio=M;exports.CarSelection=j;exports.CarWheel=h;exports.SkidTrailBehaviour=B;