@babylonjs-toolkit/next 9.1.0 → 9.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,7 +40,7 @@ import { Skeleton } from '@babylonjs/core/Bones/skeleton';
40
40
  import { Control } from '@babylonjs/gui/2D/controls/control';
41
41
  import { TextBlock } from '@babylonjs/gui/2D/controls/textBlock';
42
42
  import { Image } from '@babylonjs/gui/2D/controls/image';
43
- import { PhysicsBody, PhysicsShape, PhysicsShapeCapsule, PhysicsRaycastResult, PhysicsMotionType, PhysicsShapeContainer, ShapeCastResult, PhysicsShapeSphere, PhysicsShapeMesh, PhysicsShapeConvexHull, PhysicsShapeBox, PhysicsShapeCylinder, PhysicsMaterialCombineMode, PhysicsShapeType } from '@babylonjs/core/Physics';
43
+ import { PhysicsBody, PhysicsShape, PhysicsShapeCapsule, PhysicsRaycastResult, PhysicsMotionType, PhysicsShapeContainer, ShapeCastResult, PhysicsShapeMesh, PhysicsShapeConvexHull, PhysicsShapeBox, PhysicsShapeSphere, PhysicsShapeCylinder, PhysicsMaterialCombineMode, PhysicsShapeType } from '@babylonjs/core/Physics';
44
44
  import { HavokPlugin } from '@babylonjs/core/Physics/v2/Plugins/havokPlugin';
45
45
  import { GLTFLoader, ArrayItem } from '@babylonjs/loaders/glTF/2.0/glTFLoader';
46
46
  import { Texture } from '@babylonjs/core/Materials/Textures/texture';
@@ -79,7 +79,7 @@ import { UnitySlider } from './unityslider';
79
79
  import { UnityScrollBar } from './unityscrollbar';
80
80
  import { UnityDropdownMenu } from './unitydropdownmenu';
81
81
  export class SceneManager {
82
- static get Version() { return "9.1.0 - R1"; }
82
+ static get Version() { return "9.5.1 - R1"; }
83
83
  static get Copyright() { return "All rights reserved (c) 2024 Mackey Kinard"; }
84
84
  static GetEngine(scene) {
85
85
  let result = null;
@@ -115,16 +115,17 @@ export class SceneManager {
115
115
  }
116
116
  static get PlaygroundCdn() { return "https://cdn.jsdelivr.net/gh/BabylonJS/BabylonToolkit@master/Runtime/"; }
117
117
  static get PlaygroundRepo() { return "https://www.babylontoolkit.com/playground/"; }
118
- static async InitializePlayground(engine, options = null) {
119
- return SceneManager.InitializeRuntime(engine, options);
118
+ static async InitializePlayground(engine, options = null, scene = null, inputOptions = null) {
119
+ return SceneManager.InitializeRuntime(engine, options, scene, inputOptions);
120
120
  }
121
- static async InitializeRuntime(engine, options = null) {
121
+ static async InitializeRuntime(engine, options = null, scene = null, inputOptions = null) {
122
122
  Tools.Log("Babylon.js Toolkit v" + SceneManager.Version);
123
123
  if (AudioSource.IsLegacyEngine())
124
124
  Tools.Log("Legacy audio engine detected");
125
125
  const hardwareScalingLevel = (options != null && options.hardwareScalingLevel != null) ? options.hardwareScalingLevel : WindowManager.GetHardwareScalingLevel();
126
126
  const initSceneFileLoaders = (options != null && options.initSceneFileLoaders != null) ? options.initSceneFileLoaders : true;
127
127
  const loadAsyncRuntimeLibs = (options != null && options.loadAsyncRuntimeLibs != null) ? options.loadAsyncRuntimeLibs : true;
128
+ const enableUserInput = (options != null && options.enableUserInput != null) ? options.enableUserInput : false;
128
129
  const defaultProjectScriptBundle = (SceneManager.PlaygroundCdn + "default.playground.js");
129
130
  const loadProjectScriptBundle = (options != null && options.loadProjectScriptBundle != null) ? options.loadProjectScriptBundle : false;
130
131
  const projectScriptBundleUrl = (options != null && options.projectScriptBundleUrl != null) ? options.projectScriptBundleUrl : defaultProjectScriptBundle;
@@ -135,6 +136,8 @@ export class SceneManager {
135
136
  SceneManager.ShowLoadingScreen(engine, hideLoadingUIWithEngine, defaultLoadingUIMarginTop);
136
137
  if (hardwareScalingLevel != null && hardwareScalingLevel > 0)
137
138
  engine.setHardwareScalingLevel(hardwareScalingLevel);
139
+ if (enableUserInput === true)
140
+ InputController.EnableUserInput(engine, scene, inputOptions);
138
141
  SceneManager.UniversalModuleDefinition = false;
139
142
  try {
140
143
  SceneManager.InitializeSceneLoaderPlugin();
@@ -367,38 +370,6 @@ export class SceneManager {
367
370
  }
368
371
  });
369
372
  }
370
- static NavigateTo(scene, route, options = null, useWindowLocation = false) {
371
- if (useWindowLocation === true) {
372
- if (options?.replace === true) {
373
- window.location.replace(route);
374
- }
375
- else {
376
- window.location.assign(route);
377
- }
378
- return;
379
- }
380
- if (scene.reactNavigationFunction != null) {
381
- const navOptions = { ...options, state: { ...(options?.state || {}), fromApp: true } };
382
- scene.reactNavigationFunction(route, navOptions);
383
- }
384
- else {
385
- console.warn("React navigation hook is not set on the scene.");
386
- }
387
- }
388
- static SetReactNavigationHook(scene, navigateToFunction) {
389
- scene.reactNavigationFunction = navigateToFunction;
390
- }
391
- static DeleteReactNavigationHook(scene) {
392
- if (scene.reactNavigationFunction != null) {
393
- scene.reactNavigationFunction = null;
394
- try {
395
- delete scene.reactNavigationFunction;
396
- }
397
- catch (e) {
398
- console.warn(e);
399
- }
400
- }
401
- }
402
373
  static EnableSceneParsing(enabled) {
403
374
  SceneManager.SceneParsingEnabled = enabled;
404
375
  }
@@ -3211,6 +3182,19 @@ export class ScriptComponent {
3211
3182
  return result;
3212
3183
  }
3213
3184
  }
3185
+ export class GameModeController extends ScriptComponent {
3186
+ constructor(transform, scene, properties = {}, alias = null) {
3187
+ super(transform, scene, properties, alias);
3188
+ this.onSceneReadyHandled = false;
3189
+ }
3190
+ async initSceneReady(props) {
3191
+ if (this.onSceneReadyHandled)
3192
+ return;
3193
+ this.onSceneReadyHandled = true;
3194
+ setTimeout(async () => { if (this["onSceneReady"])
3195
+ await this["onSceneReady"](props); }, 1000);
3196
+ }
3197
+ }
3214
3198
  export var System;
3215
3199
  (function (System) {
3216
3200
  System[System["Deg2Rad"] = (Math.PI * 2 / 360)] = "Deg2Rad";
@@ -16071,7 +16055,7 @@ export class WindowManager {
16071
16055
  printer.style.left = "6px";
16072
16056
  printer.style.bottom = "3px";
16073
16057
  printer.style.fontSize = "12px";
16074
- printer.style.zIndex = "10000";
16058
+ printer.style.zIndex = "9001";
16075
16059
  printer.style.color = "#0c0";
16076
16060
  printer.style.pointerEvents = "none";
16077
16061
  document.body.appendChild(printer);
@@ -16846,9 +16830,6 @@ export class AnimationState extends ScriptComponent {
16846
16830
  if (this.onAnimationAwakeObservable && this.onAnimationAwakeObservable.hasObservers()) {
16847
16831
  this.onAnimationAwakeObservable.notifyObservers(this.transform);
16848
16832
  }
16849
- console.warn("Animation State Mahine: " + this.transform.name);
16850
- console.log(this);
16851
- SceneManager.SetWindowState(this.transform.name, this);
16852
16833
  }
16853
16834
  updateStateMachine(deltaTime = null) {
16854
16835
  if (this.delayUpdateUntilReady === false || (this.delayUpdateUntilReady === true && this.isReady())) {
@@ -19798,44 +19779,6 @@ export class btRaycastVehicle {
19798
19779
  this.isArcadeHandBrakeActive = false;
19799
19780
  this.isArcadeWheelSkidActive = false;
19800
19781
  this.isArcadeYawAssistActive = false;
19801
- this.arcadeYawAssistDebugLogEnabled = false;
19802
- this.arcadeYawAssistDebugLogIntervalFrames = 30;
19803
- this.arcadeYawAssistDebugLogEdgeEvents = true;
19804
- this.arcadeHandbrakeKickStrengthDegPerSec = 120.0;
19805
- this.arcadeHandbrakeKickFrames = 6;
19806
- this.arcadeHandbrakeYawAuthority = 1.8;
19807
- this.arcadeHandbrakeMaxYawRateDegPerSec = 180.0;
19808
- this.arcadeHandbrakeReferenceSpeedKmh = 90.0;
19809
- this.arcadeHandbrakeSpeedGateEnabled = true;
19810
- this.arcadeHandbrakeLowSpeedShape = 2.0;
19811
- this.arcadeHandbrakeDirectYawEnabled = true;
19812
- this.arcadeHandbrakeDirectYawDegPerSec = 60.0;
19813
- this.arcadeHandbrakeDirectYawDurationMs = 0;
19814
- this.arcadeHandbrakeDirectYawFadeMs = 200;
19815
- this.arcadeDonutDirectYawEnabled = true;
19816
- this.arcadeDonutDirectYawDegPerSec = 5.0;
19817
- this.arcadeDonutDirectYawDurationMs = 0;
19818
- this.arcadeDonutDirectYawFadeMs = 200;
19819
- this.arcadeHandbrakeMaxSlideAngleDeg = 220.0;
19820
- this.arcadeHandbrakeCounterSteerClampEnabled = true;
19821
- this.arcadeHandbrakeCounterSteerYawThresholdDegPerSec = 10.0;
19822
- this.arcadeHandbrakeClampReleaseFadeMs = 250;
19823
- this.arcadeHandbrakeSteerSlewLimitEnabled = false;
19824
- this.arcadeHandbrakeSteerSlewLimitDegPerSec = 360.0;
19825
- this._wasArcadeHandBrakeActive = false;
19826
- this._wasArcadeYawAssistApplyingForce = false;
19827
- this._handbrakeKickJzRemaining = 0;
19828
- this._handbrakeKickFramesRemaining = 0;
19829
- this._arcadeHandbrakeLatchedDriveSign = 0;
19830
- this._arcadeHandbrakeHoldElapsedSec = 0;
19831
- this._arcadeHandbrakeSlewedSteerRad = 0;
19832
- this._arcadeHandbrakeClampReleaseFadeSec = 999;
19833
- this._arcadeDonutHoldElapsedSec = 0;
19834
- this._arcadeYawAssistDebugFrameCounter = 0;
19835
- this._arcadeYawAssistLastKickRad = 0;
19836
- this._arcadeYawAssistLastIaddPerWheel = 0;
19837
- this._arcadeYawAssistLastClampScalar = 1.0;
19838
- this._arcadeYawAssistLastLeverSum = 0;
19839
19782
  this.burnoutFrictionFloor = 1.0;
19840
19783
  this.frictionRestoreSpeed = 8.0;
19841
19784
  this.arcadeBurnoutWheelSpinGain = 1.0;
@@ -19848,16 +19791,20 @@ export class btRaycastVehicle {
19848
19791
  this.arcadeWheelSpinMaxAngularVelocity = 160.0;
19849
19792
  this.arcadeStationaryBurnoutWheelSpinGain = 3.25;
19850
19793
  this.arcadeStationaryBurnoutMinAngularVelocity = 65.0;
19794
+ this.arcadeHandbrakeYawCapMultiplier = 1.85;
19795
+ this.arcadeBurnoutYawCapMultiplier = 1.25;
19796
+ this.arcadeDonutYawCapMultiplier = 1.15;
19851
19797
  this.arcadeSkidFadeInSpeed = 18.0;
19852
19798
  this.arcadeSkidFadeOutSpeed = 6.0;
19853
- this.arcadeYawCapMultiplier = 1.5;
19854
19799
  this.wheelAtRestSpeedThresholdKmh = 1.0;
19855
- this.wheelSpinDebugLogEnabled = false;
19856
- this.wheelSpinDebugLogIntervalFrames = 6;
19857
- this._wheelSpinDebugLogCounter = 0;
19858
- this._postHandbrakeLogFrames = 0;
19859
- this._postHandbrakeLogCounter = 0;
19860
- this._wasAnyArcadeModeActive = false;
19800
+ this.arcadeHandbrakeAssistEnabled = true;
19801
+ this.currentSteeringInput = 0;
19802
+ this.arcadeDonutDirectYawEnabled = true;
19803
+ this.arcadeDonutDirectYawDegPerSec = 60.0;
19804
+ this.arcadeDonutDirectYawDurationMs = 0;
19805
+ this.arcadeDonutDirectYawFadeMs = 120;
19806
+ this._arcadeDonutHoldElapsedSec = 0;
19807
+ this._arcadeDonutDirectionSign = 0;
19861
19808
  this._forwardWS = [];
19862
19809
  this._axle = [];
19863
19810
  this._forwardImpulse = [];
@@ -19865,6 +19812,11 @@ export class btRaycastVehicle {
19865
19812
  this._arcadeSkidInfo = [];
19866
19813
  this._arcadePreviousWheelSpin = [];
19867
19814
  this.sideFrictionStiffness = 1.0;
19815
+ this.arcadeSideSlipSaturationEnabled = true;
19816
+ this.arcadeSideSlipPeakDeg = 8.0;
19817
+ this.arcadeSideSlipFalloffDeg = 45.0;
19818
+ this.arcadeSideSlipFalloffFactor = 0.4;
19819
+ this.arcadeSideSlipMinSpeedMps = 1.5;
19868
19820
  this._chassisMass = 0;
19869
19821
  this._chassisInvMass = 0;
19870
19822
  this._chassisTransform = Matrix.Identity();
@@ -19989,6 +19941,9 @@ export class btRaycastVehicle {
19989
19941
  return this.isArcadeBurnoutModeActive;
19990
19942
  }
19991
19943
  setIsArcadeDonutActive(active) {
19944
+ if (active !== true) {
19945
+ this._arcadeDonutDirectionSign = 0;
19946
+ }
19992
19947
  this.isArcadeDonutModeActive = active;
19993
19948
  }
19994
19949
  getIsArcadeDonutActive() {
@@ -20609,29 +20564,6 @@ export class btRaycastVehicle {
20609
20564
  const chassisAtRest = (this.wheelAtRestSpeedThresholdKmh > 0
20610
20565
  && Math.abs(this._currentVehicleSpeedKmHour) < this.wheelAtRestSpeedThresholdKmh
20611
20566
  && (!arcadeModeActiveAny || !anyWheelEngineForceActive));
20612
- let wheelSpinLogThisTick = false;
20613
- if (this.wheelSpinDebugLogEnabled === true) {
20614
- this._wheelSpinDebugLogCounter++;
20615
- const intv = (this.wheelSpinDebugLogIntervalFrames > 0)
20616
- ? this.wheelSpinDebugLogIntervalFrames : 1;
20617
- if ((this._wheelSpinDebugLogCounter % intv) === 0) {
20618
- wheelSpinLogThisTick = true;
20619
- }
20620
- }
20621
- let chassisAngVelY = 0;
20622
- if (wheelSpinLogThisTick === true) {
20623
- this._chassisBody.getAngularVelocityToRef(this._sv8);
20624
- chassisAngVelY = this._sv8.y;
20625
- console.log("[HavokVehicle.wheelSpin] tick=" + this._wheelSpinDebugLogCounter
20626
- + " speedKmh=" + this._currentVehicleSpeedKmHour.toFixed(3)
20627
- + " yawRadPerSec=" + chassisAngVelY.toFixed(4)
20628
- + " atRest=" + chassisAtRest
20629
- + " arcadeAny=" + arcadeModeActiveAny
20630
- + " burn=" + this.isArcadeBurnoutModeActive
20631
- + " donut=" + this.isArcadeDonutModeActive
20632
- + " hand=" + this.isArcadeHandBrakeActive
20633
- + " skid=" + this.isArcadeWheelSkidActive);
20634
- }
20635
20567
  for (var i = 0; i < numWheels; i++) {
20636
20568
  var wheel = this._wheelInfo[i];
20637
20569
  var groundAngularVelocity = 0.0;
@@ -20647,29 +20579,12 @@ export class btRaycastVehicle {
20647
20579
  if (chassisAtRest === true) {
20648
20580
  wheel.rotationBoost = 0;
20649
20581
  wheel.deltaRotation = 0;
20650
- if (wheelSpinLogThisTick === true) {
20651
- console.log(" wheel[" + i + "] SUPPRESSED"
20652
- + " contact=" + wheel.raycastInfo.isInContact
20653
- + " groundAngVel=" + groundAngularVelocity.toFixed(4)
20654
- + " rotation=" + wheel.rotation.toFixed(4));
20655
- }
20656
20582
  continue;
20657
20583
  }
20658
20584
  var wheelAngularVelocity = this.getWheelAngularVelocity(i, groundAngularVelocity, step, wheel.raycastInfo.isInContact);
20659
20585
  wheel.deltaRotation = wheelAngularVelocity * step;
20660
20586
  wheel.rotation += wheel.deltaRotation;
20661
20587
  wheel.deltaRotation *= 0.99;
20662
- if (wheelSpinLogThisTick === true) {
20663
- console.log(" wheel[" + i + "]"
20664
- + " contact=" + wheel.raycastInfo.isInContact
20665
- + " groundAngVel=" + groundAngularVelocity.toFixed(4)
20666
- + " rotBoost=" + wheel.rotationBoost.toFixed(4)
20667
- + " wheelAngVel=" + wheelAngularVelocity.toFixed(4)
20668
- + " deltaRot=" + wheel.deltaRotation.toFixed(5)
20669
- + " rotation=" + wheel.rotation.toFixed(4)
20670
- + " engineForce=" + wheel.engineForce.toFixed(2)
20671
- + " brake=" + wheel.brake.toFixed(2));
20672
- }
20673
20588
  }
20674
20589
  this.clampChassisYawRate(step);
20675
20590
  }
@@ -20720,9 +20635,20 @@ export class btRaycastVehicle {
20720
20635
  }
20721
20636
  }
20722
20637
  }
20638
+ getSteeringAuthorityInput() {
20639
+ var steeringInput = Scalar.Clamp(this.currentSteeringInput, -1.0, 1.0);
20640
+ if (Math.abs(steeringInput) > 0.001)
20641
+ return steeringInput;
20642
+ var signedFrontSteer = this.getSignedFrontSteeringAngleRad();
20643
+ return Scalar.Clamp(signedFrontSteer / 0.6, -1.0, 1.0);
20644
+ }
20645
+ getSteeringMagnitude() {
20646
+ return Math.abs(this.getSteeringAuthorityInput());
20647
+ }
20723
20648
  applyEasyDonutYawAssist(timeStep, absSpeedKmh, signedSpeedKmh) {
20724
20649
  if (this.isArcadeDonutModeActive !== true) {
20725
20650
  this._arcadeDonutHoldElapsedSec = 0;
20651
+ this._arcadeDonutDirectionSign = 0;
20726
20652
  return;
20727
20653
  }
20728
20654
  if (this.arcadeDonutDirectYawEnabled !== true) {
@@ -20735,14 +20661,6 @@ export class btRaycastVehicle {
20735
20661
  this._arcadeDonutHoldElapsedSec += timeStep;
20736
20662
  return;
20737
20663
  }
20738
- var L = this.getApproxWheelbaseMeters();
20739
- if (L < 0.5)
20740
- L = 2.5;
20741
- var Iz = 0.22 * this._chassisMass * L * L;
20742
- if (Iz <= 0 || this._chassisMass <= 0) {
20743
- this._arcadeDonutHoldElapsedSec += timeStep;
20744
- return;
20745
- }
20746
20664
  var durSec = this.arcadeDonutDirectYawDurationMs > 0 ? this.arcadeDonutDirectYawDurationMs / 1000.0 : 0;
20747
20665
  var fadeSec = this.arcadeDonutDirectYawFadeMs > 0 ? this.arcadeDonutDirectYawFadeMs / 1000.0 : 0;
20748
20666
  var elapsed = this._arcadeDonutHoldElapsedSec;
@@ -20771,337 +20689,76 @@ export class btRaycastVehicle {
20771
20689
  chassisUp.set(cm[ui * 4], cm[ui * 4 + 1], cm[ui * 4 + 2]);
20772
20690
  this._chassisBody.getLinearVelocityToRef(this._sv8);
20773
20691
  var signedVxMps = Vector3.Dot(this._sv8, chassisForward);
20774
- var driveSign = Math.abs(signedVxMps) > 0.25 ? (signedVxMps >= 0 ? 1 : -1) : 1;
20775
20692
  var steerSign = signedFrontSteerRad >= 0 ? 1 : -1;
20776
- var extraRad = Tools.ToRadians(this.arcadeDonutDirectYawDegPerSec)
20777
- * driveSign * steerSign
20778
- * fade * this.arcadeSteeringAssist;
20779
- var donutYawJz = Iz * extraRad * timeStep;
20780
- if (Math.abs(donutYawJz) <= 1e-6) {
20781
- this._arcadeDonutHoldElapsedSec += timeStep;
20782
- return;
20693
+ if (this._arcadeDonutDirectionSign === 0) {
20694
+ this._arcadeDonutDirectionSign = Math.abs(signedVxMps) > 0.25 ? (signedVxMps >= 0 ? 1 : -1) : steerSign;
20783
20695
  }
20784
- this._chassisBody.getObjectCenterWorldToRef(this._sv1);
20785
- var leverSum = 0;
20786
- var rearIdxList = [];
20787
- var rearLeverList = [];
20788
- for (var w = 0; w < this._wheelInfo.length; w++) {
20789
- var wi = this._wheelInfo[w];
20790
- if (!wi.isFrontWheel && wi.raycastInfo.groundObject) {
20791
- wi.raycastInfo.contactPointWS.subtractToRef(this._sv1, this._sv2);
20792
- Vector3.CrossToRef(this._sv2, this._axle[w], this._sv3);
20793
- var lever_w = Vector3.Dot(this._sv3, chassisUp);
20794
- rearIdxList.push(w);
20795
- rearLeverList.push(lever_w);
20796
- leverSum += lever_w;
20797
- }
20798
- }
20799
- if (rearIdxList.length === 0 || Math.abs(leverSum) <= MIN_LEVER_EPS) {
20696
+ var targetYawRad = Tools.ToRadians(this.arcadeDonutDirectYawDegPerSec)
20697
+ * this._arcadeDonutDirectionSign * steerSign
20698
+ * fade * this.arcadeSteeringAssist;
20699
+ if (Math.abs(targetYawRad) <= 1e-5) {
20800
20700
  this._arcadeDonutHoldElapsedSec += timeStep;
20801
20701
  return;
20802
20702
  }
20803
- var IaddPerWheel = donutYawJz / leverSum;
20804
- for (var ii = 0; ii < rearIdxList.length; ii++) {
20805
- var w2 = rearIdxList[ii];
20806
- var wi2 = this._wheelInfo[w2];
20807
- this._axle[w2].scaleToRef(IaddPerWheel, this._sv2);
20808
- this._chassisBody.applyImpulse(this._sv2, wi2.raycastInfo.contactPointWS);
20809
- }
20703
+ this._chassisBody.getAngularVelocityToRef(this._sv9);
20704
+ var currentYawRad = Vector3.Dot(this._sv9, chassisUp);
20705
+ var lockRate = 14.0;
20706
+ var lockBlend = Scalar.Clamp(1.0 - Math.exp(-lockRate * timeStep), 0.0, 1.0);
20707
+ var nextYawRad = currentYawRad + (targetYawRad - currentYawRad) * lockBlend;
20708
+ var minHoldYawRad = Math.abs(targetYawRad) * 0.55;
20709
+ if (Math.sign(nextYawRad) !== Math.sign(targetYawRad) || Math.abs(nextYawRad) < minHoldYawRad) {
20710
+ nextYawRad = Math.sign(targetYawRad) * minHoldYawRad;
20711
+ }
20712
+ chassisUp.scaleToRef(currentYawRad, this._sv1);
20713
+ this._sv9.subtractToRef(this._sv1, this._sv2);
20714
+ chassisUp.scaleToRef(nextYawRad, this._sv3);
20715
+ this._sv2.addToRef(this._sv3, this._sv9);
20716
+ this._chassisBody.setAngularVelocity(this._sv9);
20810
20717
  this._arcadeDonutHoldElapsedSec += timeStep;
20811
20718
  }
20812
20719
  applyHandbrakeYawAssist(timeStep, absSpeedKmh, signedSpeedKmh) {
20813
20720
  this.isArcadeYawAssistActive = false;
20814
- if (this.isArcadeHandBrakeActive === false) {
20815
- this._wasArcadeHandBrakeActive = false;
20816
- this._wasArcadeYawAssistApplyingForce = false;
20817
- this._handbrakeKickJzRemaining = 0;
20818
- this._handbrakeKickFramesRemaining = 0;
20819
- this._arcadeHandbrakeLatchedDriveSign = 0;
20820
- this._arcadeHandbrakeHoldElapsedSec = 0;
20821
- this._arcadeHandbrakeSlewedSteerRad = 0;
20822
- this._arcadeHandbrakeClampReleaseFadeSec = 999;
20721
+ if (!this.arcadeHandbrakeAssistEnabled)
20823
20722
  return;
20824
- }
20825
- const TAU_RESPONSE = 0.18;
20826
- const V_ENGAGE_MIN_KMH = 7.0;
20827
- const V_ENGAGE_FULL_KMH = 65.0;
20828
- const V_KICK_FULL_KMH = 65.0;
20829
- const I_Z_FACTOR = 0.22;
20830
- const MIN_STEER_RAD = 0.02;
20831
- const MIN_LEVER_EPS = 0.001;
20832
- const ASSIST_MIN_NM = 25.0;
20833
- const SLIDE_TAPER_RANGE_RAD = Math.PI / 4;
20834
- const K_ASSIST = this.arcadeHandbrakeYawAuthority;
20835
- const R_MAX_DEG_PER_SEC = this.arcadeHandbrakeMaxYawRateDegPerSec;
20836
- const K_KICK_DEG_PER_SEC = this.arcadeHandbrakeKickStrengthDegPerSec;
20837
- const V_REF_MPS = this.arcadeHandbrakeReferenceSpeedKmh / 3.6;
20838
- const MAX_SLIDE_ANGLE_RAD = Tools.ToRadians(this.arcadeHandbrakeMaxSlideAngleDeg);
20839
- const KICK_FRAMES = Math.max(1, this.arcadeHandbrakeKickFrames | 0);
20840
- this._arcadeYawAssistDebugFrameCounter++;
20841
- var debugEnabled = this.arcadeYawAssistDebugLogEnabled === true;
20842
- var debugIntervalHit = debugEnabled && this.arcadeYawAssistDebugLogIntervalFrames > 0 && (this._arcadeYawAssistDebugFrameCounter % this.arcadeYawAssistDebugLogIntervalFrames) === 0;
20843
- var signedFrontSteerRad = this.getSignedFrontSteeringAngleRad();
20844
- var steeringMagnitude = Math.abs(signedFrontSteerRad);
20845
- var eligible = this.isArcadeHandBrakeActive === true && this.arcadeSteeringAssist > 0 && steeringMagnitude > MIN_STEER_RAD && absSpeedKmh > V_ENGAGE_MIN_KMH;
20846
- var risingEdge = this.isArcadeHandBrakeActive === true && this._wasArcadeHandBrakeActive === false;
20847
- if (this.arcadeHandbrakeSteerSlewLimitEnabled === true && !risingEdge) {
20848
- var slewMaxRad = Tools.ToRadians(this.arcadeHandbrakeSteerSlewLimitDegPerSec) * timeStep;
20849
- var steerDelta = signedFrontSteerRad - this._arcadeHandbrakeSlewedSteerRad;
20850
- if (steerDelta > slewMaxRad)
20851
- steerDelta = slewMaxRad;
20852
- else if (steerDelta < -slewMaxRad)
20853
- steerDelta = -slewMaxRad;
20854
- this._arcadeHandbrakeSlewedSteerRad += steerDelta;
20855
- }
20856
- else {
20857
- this._arcadeHandbrakeSlewedSteerRad = signedFrontSteerRad;
20858
- }
20859
- var effectiveSteerRad = this._arcadeHandbrakeSlewedSteerRad;
20860
- const cm = this._chassisTransform.m;
20723
+ var steeringMagnitude = this.getSteeringMagnitude();
20724
+ var steeringAuthorityInput = this.getSteeringAuthorityInput();
20725
+ if (!this.isArcadeHandBrakeActive || steeringMagnitude < 0.02)
20726
+ return;
20727
+ var speedMps = Math.max(0.0, absSpeedKmh / 3.6);
20728
+ var speedScale = Scalar.Clamp((speedMps - 0.5) / 3.0, 0.0, 1.0);
20729
+ if (speedScale <= 0.0)
20730
+ return;
20731
+ const m = this._chassisTransform.m;
20732
+ const ri = this._indexRightAxis;
20861
20733
  const ui = this._indexUpAxis;
20862
20734
  const fi = this._indexForwardAxis;
20863
- const ri = this._indexRightAxis;
20864
- const chassisUp = this._sv5;
20865
- const chassisForward = this._sv6;
20866
- const chassisRight = this._sv9;
20867
- chassisUp.set(cm[ui * 4], cm[ui * 4 + 1], cm[ui * 4 + 2]);
20868
- chassisForward.set(cm[fi * 4], cm[fi * 4 + 1], cm[fi * 4 + 2]);
20869
- chassisRight.set(cm[ri * 4], cm[ri * 4 + 1], cm[ri * 4 + 2]);
20870
- this._chassisBody.getLinearVelocityToRef(this._sv8);
20871
- var signedVxMps = Vector3.Dot(this._sv8, chassisForward);
20872
- var velRightMps = Vector3.Dot(this._sv8, chassisRight);
20873
- var speedMagMps = Math.sqrt(this._sv8.x * this._sv8.x + this._sv8.y * this._sv8.y + this._sv8.z * this._sv8.z);
20874
- var slipAngleRad = (speedMagMps > 0.1) ? Math.atan2(velRightMps, signedVxMps) : 0;
20875
- var driveSign = this._arcadeHandbrakeLatchedDriveSign !== 0
20876
- ? this._arcadeHandbrakeLatchedDriveSign
20877
- : (signedVxMps >= 0 ? 1 : -1);
20878
- var relSlipRad;
20879
- if (driveSign > 0) {
20880
- relSlipRad = slipAngleRad;
20881
- }
20882
- else {
20883
- relSlipRad = slipAngleRad >= 0 ? slipAngleRad - Math.PI : slipAngleRad + Math.PI;
20884
- }
20885
- var relSlipAbs = Math.abs(relSlipRad);
20886
- var relSlipSign = relSlipAbs > 1e-3 ? (relSlipRad > 0 ? 1 : -1) : 0;
20887
- var L = this.getApproxWheelbaseMeters();
20888
- if (L < 0.5)
20889
- L = 2.5;
20890
- var Iz = I_Z_FACTOR * this._chassisMass * L * L;
20891
- var rTarget = 0;
20892
- var currentYawRate = 0;
20893
- var gate = 0;
20894
- var slideTaper = 1.0;
20895
- var desiredMz = 0;
20896
- this._chassisBody.getAngularVelocityToRef(this._sv4);
20897
- currentYawRate = Vector3.Dot(this._sv4, chassisUp);
20898
- if (eligible) {
20899
- var gateRange = V_ENGAGE_FULL_KMH - V_ENGAGE_MIN_KMH;
20900
- var gateRaw = gateRange > 0 ? (absSpeedKmh - V_ENGAGE_MIN_KMH) / gateRange : 1.0;
20901
- gate = Scalar.Clamp(gateRaw, 0, 1);
20902
- gate = gate * gate * (3.0 - 2.0 * gate);
20903
- var vForTarget = driveSign * Math.min(speedMagMps, V_REF_MPS);
20904
- var rTargetRaw = K_ASSIST * vForTarget * effectiveSteerRad / L;
20905
- var rMaxLinear = Scalar.Clamp(speedMagMps / V_REF_MPS, 0, 1);
20906
- var lowSpeedShape = this.arcadeHandbrakeLowSpeedShape > 0 ? this.arcadeHandbrakeLowSpeedShape : 1.0;
20907
- var rMaxSpeedFactor = this.arcadeHandbrakeSpeedGateEnabled ? Math.pow(rMaxLinear, lowSpeedShape) : 1.0;
20908
- var rMax = Tools.ToRadians(R_MAX_DEG_PER_SEC) * rMaxSpeedFactor;
20909
- if (rTargetRaw > rMax)
20910
- rTargetRaw = rMax;
20911
- else if (rTargetRaw < -rMax)
20912
- rTargetRaw = -rMax;
20913
- rTarget = rTargetRaw * gate * this.arcadeSteeringAssist;
20914
- var counterSteerClampActive = false;
20915
- if (this.arcadeHandbrakeCounterSteerClampEnabled === true) {
20916
- var yawThresholdRadPerSec = Tools.ToRadians(this.arcadeHandbrakeCounterSteerYawThresholdDegPerSec);
20917
- if (Math.abs(currentYawRate) > yawThresholdRadPerSec && rTarget * currentYawRate < 0) {
20918
- rTarget = 0;
20919
- counterSteerClampActive = true;
20920
- }
20921
- }
20922
- var releaseFadeMs = this.arcadeHandbrakeClampReleaseFadeMs;
20923
- var clampFadeActive = false;
20924
- var clampFadeMul = 1.0;
20925
- if (counterSteerClampActive) {
20926
- this._arcadeHandbrakeClampReleaseFadeSec = 0;
20927
- }
20928
- else {
20929
- this._arcadeHandbrakeClampReleaseFadeSec += timeStep;
20930
- if (releaseFadeMs > 0) {
20931
- var fadeSec = releaseFadeMs / 1000.0;
20932
- if (this._arcadeHandbrakeClampReleaseFadeSec < fadeSec) {
20933
- var fadeT = this._arcadeHandbrakeClampReleaseFadeSec / fadeSec;
20934
- clampFadeMul = fadeT * fadeT * (3.0 - 2.0 * fadeT);
20935
- rTarget *= clampFadeMul;
20936
- clampFadeActive = true;
20937
- }
20938
- }
20939
- }
20940
- if (relSlipAbs > MAX_SLIDE_ANGLE_RAD) {
20941
- var pastMax = (relSlipAbs - MAX_SLIDE_ANGLE_RAD) / SLIDE_TAPER_RANGE_RAD;
20942
- if (pastMax > 1.0)
20943
- pastMax = 1.0;
20944
- slideTaper = 1.0 - pastMax;
20945
- rTarget *= slideTaper;
20946
- }
20947
- if (rTarget > rMax)
20948
- rTarget = rMax;
20949
- else if (rTarget < -rMax)
20950
- rTarget = -rMax;
20951
- desiredMz = Iz * (rTarget - currentYawRate) / TAU_RESPONSE;
20952
- }
20953
- var newMz;
20954
- if (eligible) {
20955
- newMz = desiredMz;
20735
+ this._stb1.set(m[ri * 4], m[ri * 4 + 1], m[ri * 4 + 2]);
20736
+ this._stb2.set(m[ui * 4], m[ui * 4 + 1], m[ui * 4 + 2]);
20737
+ this._stb3.set(m[fi * 4], m[fi * 4 + 1], m[fi * 4 + 2]);
20738
+ this._chassisBody.getAngularVelocityToRef(this._sv9);
20739
+ var localRoll = Vector3.Dot(this._sv9, this._stb1);
20740
+ var localYaw = Vector3.Dot(this._sv9, this._stb2);
20741
+ var localPitch = Vector3.Dot(this._sv9, this._stb3);
20742
+ var signedFrontSteerRad = this.getSignedFrontSteeringAngleRad();
20743
+ var wheelbaseMeters = this.getApproxWheelbaseMeters();
20744
+ var bicycleYawRate = 0.0;
20745
+ if (wheelbaseMeters > 0.5 && speedMps > 0.2 && Math.abs(signedFrontSteerRad) > 1e-4) {
20746
+ }
20747
+ var minimumYawRate = steeringAuthorityInput * this.arcadeSteeringAssist * (0.25 + steeringMagnitude * 1.0) * speedScale;
20748
+ var desiredYawBoost = Math.abs(bicycleYawRate) > Math.abs(minimumYawRate) ? bicycleYawRate : minimumYawRate;
20749
+ var sameDir = (desiredYawBoost * localYaw) >= 0.0;
20750
+ if (sameDir && Math.abs(localYaw) >= Math.abs(desiredYawBoost)) {
20751
+ this.isArcadeYawAssistActive = true;
20752
+ return;
20956
20753
  }
20957
- else {
20958
- newMz = 0;
20959
- }
20960
- var assistApplyingForce = Math.abs(newMz) > ASSIST_MIN_NM;
20961
- if (eligible && this._wasArcadeHandBrakeActive === false) {
20962
- this._arcadeHandbrakeLatchedDriveSign = signedVxMps >= 0 ? 1 : -1;
20963
- driveSign = this._arcadeHandbrakeLatchedDriveSign;
20964
- this._arcadeHandbrakeHoldElapsedSec = 0;
20965
- var kickRange = V_KICK_FULL_KMH - V_ENGAGE_MIN_KMH;
20966
- var kickRaw = kickRange > 0 ? (absSpeedKmh - V_ENGAGE_MIN_KMH) / kickRange : 1.0;
20967
- var kickGate = Scalar.Clamp(kickRaw, 0, 1);
20968
- kickGate = kickGate * kickGate * (3.0 - 2.0 * kickGate);
20969
- var steerSign = signedFrontSteerRad >= 0 ? 1 : -1;
20970
- var velSign = signedVxMps >= 0 ? 1 : -1;
20971
- var kickLinear = Scalar.Clamp(speedMagMps / V_REF_MPS, 0, 1);
20972
- var kickShape = this.arcadeHandbrakeLowSpeedShape > 0 ? this.arcadeHandbrakeLowSpeedShape : 1.0;
20973
- var kickSpeedFactor = this.arcadeHandbrakeSpeedGateEnabled ? Math.pow(kickLinear, kickShape) : 1.0;
20974
- var kickRadTotal = Tools.ToRadians(K_KICK_DEG_PER_SEC) * steerSign * velSign * kickGate * kickSpeedFactor * this.arcadeSteeringAssist;
20975
- var kickSuppressed = false;
20976
- if (this.arcadeHandbrakeCounterSteerClampEnabled === true) {
20977
- var kickYawThresholdRadPerSec = Tools.ToRadians(this.arcadeHandbrakeCounterSteerYawThresholdDegPerSec);
20978
- if (Math.abs(currentYawRate) > kickYawThresholdRadPerSec && kickRadTotal * currentYawRate < 0) {
20979
- kickRadTotal = 0;
20980
- kickSuppressed = true;
20981
- }
20982
- }
20983
- this._handbrakeKickJzRemaining = Iz * kickRadTotal;
20984
- this._handbrakeKickFramesRemaining = kickSuppressed ? 0 : KICK_FRAMES;
20985
- }
20986
- var kickAngularImpulseJz = 0;
20987
- var kickRad = 0;
20988
- if (eligible && this._handbrakeKickFramesRemaining > 0) {
20989
- var thisFrameKick = this._handbrakeKickJzRemaining / this._handbrakeKickFramesRemaining;
20990
- kickAngularImpulseJz += thisFrameKick;
20991
- this._handbrakeKickJzRemaining -= thisFrameKick;
20992
- this._handbrakeKickFramesRemaining--;
20993
- }
20994
- else if (!eligible) {
20995
- this._handbrakeKickJzRemaining = 0;
20996
- this._handbrakeKickFramesRemaining = 0;
20997
- }
20998
- if (Iz > 0)
20999
- kickRad = kickAngularImpulseJz / Iz;
21000
- var directYawJz = 0;
21001
- if (eligible && this.arcadeHandbrakeDirectYawEnabled === true && Iz > 0) {
21002
- var directDurSec = this.arcadeHandbrakeDirectYawDurationMs > 0 ? this.arcadeHandbrakeDirectYawDurationMs / 1000.0 : 0;
21003
- var directFadeSec = this.arcadeHandbrakeDirectYawFadeMs > 0 ? this.arcadeHandbrakeDirectYawFadeMs / 1000.0 : 0;
21004
- var elapsed = this._arcadeHandbrakeHoldElapsedSec;
21005
- var fadeIn = directFadeSec > 0 ? Scalar.Clamp(elapsed / directFadeSec, 0, 1) : 1.0;
21006
- var fadeOut = 1.0;
21007
- if (directDurSec > 0) {
21008
- var timeLeft = directDurSec - elapsed;
21009
- if (timeLeft <= 0) {
21010
- fadeOut = 0;
21011
- }
21012
- else if (directFadeSec > 0 && timeLeft < directFadeSec) {
21013
- fadeOut = timeLeft / directFadeSec;
21014
- }
21015
- }
21016
- var directFade = Math.min(fadeIn, fadeOut);
21017
- if (directFade > 0) {
21018
- var dyLinear = Scalar.Clamp(speedMagMps / V_REF_MPS, 0, 1);
21019
- var dyShape = this.arcadeHandbrakeLowSpeedShape > 0 ? this.arcadeHandbrakeLowSpeedShape : 1.0;
21020
- var dySpeedFactor = this.arcadeHandbrakeSpeedGateEnabled ? Math.pow(dyLinear, dyShape) : 1.0;
21021
- var dySteerSign = signedFrontSteerRad >= 0 ? 1 : -1;
21022
- var dyExtraRad = Tools.ToRadians(this.arcadeHandbrakeDirectYawDegPerSec)
21023
- * driveSign * dySteerSign
21024
- * gate * dySpeedFactor
21025
- * directFade * this.arcadeSteeringAssist;
21026
- directYawJz = Iz * dyExtraRad * timeStep;
21027
- }
21028
- }
21029
- if (eligible) {
21030
- this._arcadeHandbrakeHoldElapsedSec += timeStep;
21031
- }
21032
- var leverSum = 0;
21033
- var rearGroundedCount = 0;
21034
- var IaddCtrlDesired = 0;
21035
- var IaddCtrlAppliedSum = 0;
21036
- var IaddKickPerWheel = 0;
21037
- var IaddKickAppliedSum = 0;
21038
- var IaddDirectPerWheel = 0;
21039
- var IaddDirectAppliedSum = 0;
21040
- var Jz_through_tires = 0;
21041
- var minCtrlClamp = 1.0;
21042
- var perWheelLog = "";
21043
- var rearIdxList = [];
21044
- var rearLeverList = [];
21045
- var hasController = Math.abs(newMz) > 0;
21046
- var hasKick = Math.abs(kickAngularImpulseJz) > 0;
21047
- var hasDirect = Math.abs(directYawJz) > 0;
21048
- if ((hasController || hasKick || hasDirect) && this._chassisMass > 0) {
21049
- this._chassisBody.getObjectCenterWorldToRef(this._sv1);
21050
- for (var w = 0; w < this._wheelInfo.length; w++) {
21051
- var wi = this._wheelInfo[w];
21052
- if (!wi.isFrontWheel && wi.raycastInfo.groundObject) {
21053
- wi.raycastInfo.contactPointWS.subtractToRef(this._sv1, this._sv2);
21054
- Vector3.CrossToRef(this._sv2, this._axle[w], this._sv3);
21055
- var lever_w = Vector3.Dot(this._sv3, chassisUp);
21056
- rearIdxList.push(w);
21057
- rearLeverList.push(lever_w);
21058
- leverSum += lever_w;
21059
- rearGroundedCount++;
21060
- }
21061
- }
21062
- if (rearGroundedCount > 0 && Math.abs(leverSum) > MIN_LEVER_EPS) {
21063
- if (hasController)
21064
- IaddCtrlDesired = (newMz * timeStep) / leverSum;
21065
- if (hasKick)
21066
- IaddKickPerWheel = kickAngularImpulseJz / leverSum;
21067
- if (hasDirect)
21068
- IaddDirectPerWheel = directYawJz / leverSum;
21069
- for (var ii = 0; ii < rearIdxList.length; ii++) {
21070
- var w2 = rearIdxList[ii];
21071
- var lever_w2 = rearLeverList[ii];
21072
- var wi2 = this._wheelInfo[w2];
21073
- var IaddCtrlW = hasController ? IaddCtrlDesired : 0;
21074
- var IaddTotalW = IaddCtrlW + IaddKickPerWheel + IaddDirectPerWheel;
21075
- if (IaddTotalW !== 0) {
21076
- this._axle[w2].scaleToRef(IaddTotalW, this._sv2);
21077
- this._chassisBody.applyImpulse(this._sv2, wi2.raycastInfo.contactPointWS);
21078
- IaddCtrlAppliedSum += IaddCtrlW;
21079
- IaddKickAppliedSum += IaddKickPerWheel;
21080
- IaddDirectAppliedSum += IaddDirectPerWheel;
21081
- Jz_through_tires += lever_w2 * IaddTotalW;
21082
- }
21083
- if (debugEnabled) {
21084
- perWheelLog += " w" + w2
21085
- + "{maximp=" + (wi2.suspensionForce * timeStep * wi2.frictionSlip).toFixed(1)
21086
- + " side=" + this._sideImpulse[w2].toFixed(1)
21087
- + " fwd=" + (this._forwardImpulse[w2] * 0.5).toFixed(1)
21088
- + " ctrlDes=" + IaddCtrlDesired.toFixed(1)
21089
- + " ctrl=" + IaddCtrlW.toFixed(1)
21090
- + " kick=" + IaddKickPerWheel.toFixed(1)
21091
- + " direct=" + IaddDirectPerWheel.toFixed(1)
21092
- + " tot=" + IaddTotalW.toFixed(1) + "}";
21093
- }
21094
- }
21095
- }
21096
- }
21097
- this._arcadeYawAssistLastKickRad = kickRad;
21098
- this._arcadeYawAssistLastIaddPerWheel = IaddCtrlDesired + IaddKickPerWheel + IaddDirectPerWheel;
21099
- this._arcadeYawAssistLastClampScalar = minCtrlClamp;
21100
- this._arcadeYawAssistLastLeverSum = leverSum;
21101
- var assistActiveThisFrame = eligible || assistApplyingForce;
21102
- this.isArcadeYawAssistActive = assistActiveThisFrame;
21103
- this._wasArcadeHandBrakeActive = this.isArcadeHandBrakeActive;
21104
- this._wasArcadeYawAssistApplyingForce = assistApplyingForce;
20754
+ var yawDeltaMax = (0.15 + steeringMagnitude * 0.35) * speedScale;
20755
+ var yawDelta = Scalar.Clamp(desiredYawBoost * (2.0 + steeringMagnitude * 4.0) * timeStep, -yawDeltaMax, yawDeltaMax);
20756
+ if (Math.abs(yawDelta) < 1e-6)
20757
+ return;
20758
+ localYaw += yawDelta;
20759
+ this._sv9.set(this._stb1.x * localRoll + this._stb2.x * localYaw + this._stb3.x * localPitch, this._stb1.y * localRoll + this._stb2.y * localYaw + this._stb3.y * localPitch, this._stb1.z * localRoll + this._stb2.z * localYaw + this._stb3.z * localPitch);
20760
+ this._chassisBody.setAngularVelocity(this._sv9);
20761
+ this.isArcadeYawAssistActive = true;
21105
20762
  }
21106
20763
  resolveWheelSpinDirection(wheelIndex, requestedDriveImpulse, appliedDriveImpulse) {
21107
20764
  if (Math.abs(requestedDriveImpulse) > 0.0001) {
@@ -21299,6 +20956,24 @@ export class btRaycastVehicle {
21299
20956
  this._forwardWS[i].normalize();
21300
20957
  this._sideImpulse[i] = this.resolveSingleBilateral(this._chassisBody, wheel.raycastInfo.contactPointWS, this._axle[i]);
21301
20958
  this._sideImpulse[i] *= this.sideFrictionStiffness;
20959
+ if (this.arcadeSideSlipSaturationEnabled && this._sideImpulse[i] !== 0) {
20960
+ this.velocityAtWorldPoint(this._chassisBody, wheel.raycastInfo.contactPointWS, this._sv8);
20961
+ var vLat = Vector3.Dot(this._axle[i], this._sv8);
20962
+ var vFwd = Vector3.Dot(this._forwardWS[i], this._sv8);
20963
+ var wheelSpeedSqr = vLat * vLat + vFwd * vFwd;
20964
+ var minSpeed = this.arcadeSideSlipMinSpeedMps;
20965
+ if (wheelSpeedSqr > minSpeed * minSpeed) {
20966
+ var slipRad = Math.atan2(Math.abs(vLat), Math.max(Math.abs(vFwd), 1e-3));
20967
+ var peakRad = Tools.ToRadians(Math.max(this.arcadeSideSlipPeakDeg, 0.1));
20968
+ if (slipRad > peakRad) {
20969
+ var holdFactor = Math.sin(peakRad) / Math.max(Math.sin(slipRad), 1e-3);
20970
+ var falloffSpan = Math.max(this.arcadeSideSlipFalloffDeg - this.arcadeSideSlipPeakDeg, 0.1);
20971
+ var t = Math.min(Math.max((Tools.ToDegrees(slipRad) - this.arcadeSideSlipPeakDeg) / falloffSpan, 0.0), 1.0);
20972
+ var rolloff = Scalar.Lerp(1.0, this.arcadeSideSlipFalloffFactor, t);
20973
+ this._sideImpulse[i] *= holdFactor * rolloff;
20974
+ }
20975
+ }
20976
+ }
21302
20977
  }
21303
20978
  }
21304
20979
  var sideFactor = 1.0;
@@ -21424,12 +21099,6 @@ export class btRaycastVehicle {
21424
21099
  this._wheelInfo[wheel_i].skidInfo = Math.min(this._wheelInfo[wheel_i].skidInfo, arcadeSkidInfo);
21425
21100
  }
21426
21101
  }
21427
- var isAnyArcadeModeActiveNow = this.isArcadeHandBrakeActive || this.isArcadeWheelSkidActive || this.isArcadeBurnoutModeActive || this.isArcadeDonutModeActive;
21428
- if (this._wasAnyArcadeModeActive && !isAnyArcadeModeActiveNow) {
21429
- this._postHandbrakeLogFrames = 180;
21430
- this._postHandbrakeLogCounter = 0;
21431
- }
21432
- this._wasAnyArcadeModeActive = isAnyArcadeModeActiveNow;
21433
21102
  if (sliding) {
21434
21103
  for (var wheel_i = 0; wheel_i < numWheels; wheel_i++) {
21435
21104
  if (this._sideImpulse[wheel_i] !== 0) {
@@ -21453,7 +21122,8 @@ export class btRaycastVehicle {
21453
21122
  avgSideImpulse /= groundedSideCount;
21454
21123
  var sideBlendToCoM = 0;
21455
21124
  var absSpeedKmh = Math.abs(this._currentVehicleSpeedKmHour);
21456
- if (this.sideToSideStabilityEnabled && absSpeedKmh > this.sideToSideStabilityStartKmh) {
21125
+ var arcadeSlideActive = this.isArcadeHandBrakeActive || this.isArcadeWheelSkidActive || this.isArcadeBurnoutModeActive || this.isArcadeDonutModeActive;
21126
+ if (!arcadeSlideActive && this.sideToSideStabilityEnabled && absSpeedKmh > this.sideToSideStabilityStartKmh) {
21457
21127
  var sideBlendRange = this.sideToSideStabilityFullKmh - this.sideToSideStabilityStartKmh;
21458
21128
  if (sideBlendRange > 0) {
21459
21129
  sideBlendToCoM = 0.7 * Math.min((absSpeedKmh - this.sideToSideStabilityStartKmh) / sideBlendRange, 1.0);
@@ -21522,12 +21192,22 @@ export class btRaycastVehicle {
21522
21192
  clampChassisYawRate(deltaTime) {
21523
21193
  if (this.maximumYawRateLow <= 0 && this.maximumYawRateHigh <= 0)
21524
21194
  return;
21525
- const arcadeActive = (this.isArcadeHandBrakeActive === true || this.isArcadeBurnoutModeActive === true || this.isArcadeDonutModeActive === true || this.isArcadeWheelSkidActive === true);
21526
- if (arcadeActive === true && this.arcadeYawCapMultiplier <= 0)
21195
+ const arcadeActive = (this.isArcadeHandBrakeActive === true || this.isArcadeBurnoutModeActive === true || this.isArcadeDonutModeActive === true);
21196
+ if (arcadeActive === true && this.isArcadeHandBrakeActive === true && this.arcadeHandbrakeYawCapMultiplier <= 0)
21197
+ return;
21198
+ if (arcadeActive === true && this.isArcadeBurnoutModeActive === true && this.arcadeBurnoutYawCapMultiplier <= 0)
21199
+ return;
21200
+ if (arcadeActive === true && this.isArcadeDonutModeActive === true && this.arcadeDonutYawCapMultiplier <= 0)
21527
21201
  return;
21528
21202
  let capDeg = Scalar.Lerp(this.maximumYawRateLow, this.maximumYawRateHigh, this.smoothedGradientSpeed);
21529
- if (arcadeActive === true)
21530
- capDeg *= this.arcadeYawCapMultiplier;
21203
+ if (arcadeActive === true) {
21204
+ if (this.isArcadeHandBrakeActive === true)
21205
+ capDeg *= this.arcadeHandbrakeYawCapMultiplier;
21206
+ if (this.isArcadeBurnoutModeActive === true)
21207
+ capDeg *= this.arcadeBurnoutYawCapMultiplier;
21208
+ if (this.isArcadeDonutModeActive === true)
21209
+ capDeg *= this.arcadeDonutYawCapMultiplier;
21210
+ }
21531
21211
  if (capDeg <= 0)
21532
21212
  return;
21533
21213
  const capRad = Tools.ToRadians(capDeg);
@@ -23190,81 +22870,59 @@ export class RaycastVehicle {
23190
22870
  this.m_vehicle.arcadeSteeringAssist = value;
23191
22871
  }
23192
22872
  }
23193
- getArcadeDonutDirectYawDegPerSec() {
22873
+ getArcadeDonutDirectYawEnabled() {
23194
22874
  if (this.m_vehicle != null) {
23195
- return this.m_vehicle.arcadeDonutDirectYawDegPerSec;
22875
+ return this.m_vehicle.arcadeDonutDirectYawEnabled;
23196
22876
  }
23197
- return 1.0;
23198
- }
23199
- setArcadeDonutDirectYawDegPerSec(value) {
23200
- if (this.m_vehicle != null) {
23201
- this.m_vehicle.arcadeDonutDirectYawDegPerSec = value;
23202
- }
23203
- }
23204
- getArcadeHandbrakeDirectYawDegPerSec() {
23205
- if (this.m_vehicle != null) {
23206
- return this.m_vehicle.arcadeHandbrakeDirectYawDegPerSec;
23207
- }
23208
- return 1.0;
23209
- }
23210
- setArcadeHandbrakeDirectYawDegPerSec(value) {
23211
- if (this.m_vehicle != null) {
23212
- this.m_vehicle.arcadeHandbrakeDirectYawDegPerSec = value;
23213
- }
23214
- }
23215
- getArcadeHandbrakeMaxSlideAngleDeg() {
23216
- if (this.m_vehicle != null) {
23217
- return this.m_vehicle.arcadeHandbrakeMaxSlideAngleDeg;
23218
- }
23219
- return 1.0;
22877
+ return false;
23220
22878
  }
23221
- setArcadeHandbrakeMaxSlideAngleDeg(value) {
22879
+ setArcadeDonutDirectYawEnabled(value) {
23222
22880
  if (this.m_vehicle != null) {
23223
- this.m_vehicle.arcadeHandbrakeMaxSlideAngleDeg = value;
22881
+ this.m_vehicle.arcadeDonutDirectYawEnabled = value;
23224
22882
  }
23225
22883
  }
23226
- getArcadeHandbrakeBicycleYawAuthority() {
22884
+ getArcadeDonutDirectYawDegPerSec() {
23227
22885
  if (this.m_vehicle != null) {
23228
- return this.m_vehicle.arcadeHandbrakeYawAuthority;
22886
+ return this.m_vehicle.arcadeDonutDirectYawDegPerSec;
23229
22887
  }
23230
22888
  return 1.0;
23231
22889
  }
23232
- setArcadeHandbrakeBicycleYawAuthority(value) {
22890
+ setArcadeDonutDirectYawDegPerSec(value) {
23233
22891
  if (this.m_vehicle != null) {
23234
- this.m_vehicle.arcadeHandbrakeYawAuthority = value;
22892
+ this.m_vehicle.arcadeDonutDirectYawDegPerSec = value;
23235
22893
  }
23236
22894
  }
23237
- getArcadeHandbrakeMaxYawRateDegPerSec() {
22895
+ getArcadeHandbrakeYawCapMultiplier() {
23238
22896
  if (this.m_vehicle != null) {
23239
- return this.m_vehicle.arcadeHandbrakeMaxYawRateDegPerSec;
22897
+ return this.m_vehicle.arcadeHandbrakeYawCapMultiplier;
23240
22898
  }
23241
22899
  return 1.0;
23242
22900
  }
23243
- setArcadeHandbrakeMaxYawRateDegPerSec(value) {
22901
+ setArcadeHandbrakeYawCapMultiplier(value) {
23244
22902
  if (this.m_vehicle != null) {
23245
- this.m_vehicle.arcadeHandbrakeMaxYawRateDegPerSec = value;
22903
+ this.m_vehicle.arcadeHandbrakeYawCapMultiplier = value;
23246
22904
  }
23247
22905
  }
23248
- getArcadeHandbrakeReferenceSpeedKmh() {
22906
+ getArcadeBurnoutYawCapMultiplier() {
23249
22907
  if (this.m_vehicle != null) {
23250
- return this.m_vehicle.arcadeHandbrakeReferenceSpeedKmh;
22908
+ return this.m_vehicle.arcadeBurnoutYawCapMultiplier;
23251
22909
  }
23252
22910
  return 1.0;
23253
22911
  }
23254
- setArcadeHandbrakeReferenceSpeedKmh(value) {
22912
+ setArcadeBurnoutYawCapMultiplier(value) {
23255
22913
  if (this.m_vehicle != null) {
23256
- this.m_vehicle.arcadeHandbrakeReferenceSpeedKmh = value;
22914
+ this.m_vehicle.arcadeBurnoutYawCapMultiplier = value;
23257
22915
  }
23258
22916
  }
23259
- getArcadeHandbrakeKickStrengthDegPerSec() {
22917
+ getArcadeDonutYawCapMultiplier() {
23260
22918
  if (this.m_vehicle != null) {
23261
- return this.m_vehicle.arcadeHandbrakeKickStrengthDegPerSec;
22919
+ return this.m_vehicle.arcadeDonutYawCapMultiplier;
23262
22920
  }
23263
22921
  return 1.0;
23264
22922
  }
23265
- setArcadeHandbrakeKickStrengthDegPerSec(value) {
22923
+ setArcadeDonutYawCapMultiplier(value) {
23266
22924
  if (this.m_vehicle != null) {
23267
- this.m_vehicle.arcadeHandbrakeKickStrengthDegPerSec = value;
22925
+ this.m_vehicle.arcadeDonutYawCapMultiplier = value;
23268
22926
  }
23269
22927
  }
23270
22928
  getArcadeBurnoutActive() {
@@ -23526,22 +23184,6 @@ export class RaycastVehicle {
23526
23184
  this.m_vehicle.wheelAtRestSpeedThresholdKmh = value;
23527
23185
  }
23528
23186
  }
23529
- setWheelSpinDebugLogEnabled(enabled) {
23530
- if (this.m_vehicle != null) {
23531
- this.m_vehicle.wheelSpinDebugLogEnabled = enabled;
23532
- }
23533
- }
23534
- getWheelSpinDebugLogEnabled() {
23535
- if (this.m_vehicle != null) {
23536
- return this.m_vehicle.wheelSpinDebugLogEnabled;
23537
- }
23538
- return false;
23539
- }
23540
- setWheelSpinDebugLogIntervalFrames(frames) {
23541
- if (this.m_vehicle != null) {
23542
- this.m_vehicle.wheelSpinDebugLogIntervalFrames = frames;
23543
- }
23544
- }
23545
23187
  updateWheelInformation() {
23546
23188
  const wheels = this.getNumWheels();
23547
23189
  if (wheels > 0) {