LUADOC - Farming Simulator 22

WheelsUtil

Description
Wheels util Util class to manage wheels of a vehicle
Functions

computeDifferentialRotSpeedNonMotor

Description
Compute differential rot speed from properties of vehicle other than the motor, e.g. rot speed of wheels or linear speed of vehicle
Definition
computeDifferentialRotSpeedNonMotor()
Return Values
floatdiffRotSpeedrot speed [rad/sec]
Code
524function WheelsUtil.computeDifferentialRotSpeedNonMotor(self)
525 if self.isServer and self.spec_wheels ~= nil and #self.spec_wheels.wheels ~= 0 then
526 local wheelSpeed = 0
527 local numWheels = 0
528 for _, wheel in pairs(self.spec_wheels.wheels) do
529 local axleSpeed = getWheelShapeAxleSpeed(wheel.node, wheel.wheelShape) -- rad/sec
530 if wheel.hasGroundContact then
531 wheelSpeed = wheelSpeed + axleSpeed * wheel.radius
532 numWheels = numWheels+1
533 end
534 end
535
536 if numWheels > 0 then
537 return wheelSpeed/numWheels
538 end
539 return 0
540 else
541 -- v = w*r => w = v/r
542 -- differentials have embeded gear so that r can be considered 1
543 return self.lastSpeedReal*1000
544 end
545end

getGroundType

Description
Get ground type
Definition
getGroundType(boolean isField, boolean isRoad, float depth)
Arguments
booleanisFieldis on field
booleanisRoadis on road
floatdepthdepth of terrain
Return Values
IntegergroundTypeground type
Code
753function WheelsUtil.getGroundType(isField, isRoad, depth)
754 -- terrain softness:
755 -- [ 0, 0.1]: road
756 -- [0.1, 0.8]: hard terrain
757 -- [0.8, 1 ]: soft terrain
758 if isField then
759 return WheelsUtil.GROUND_FIELD
760 elseif isRoad or depth < 0.1 then
761 return WheelsUtil.GROUND_ROAD
762 else
763 if depth > 0.8 then
764 return WheelsUtil.GROUND_SOFT_TERRAIN
765 else
766 return WheelsUtil.GROUND_HARD_TERRAIN
767 end
768 end
769end

getSmoothedAcceleratorAndBrakePedals

Description
Definition
getSmoothedAcceleratorAndBrakePedals()
Code
228function WheelsUtil.getSmoothedAcceleratorAndBrakePedals(self, acceleratorPedal, brakePedal, dt)
229
230 if self.wheelsUtilSmoothedAcceleratorPedal == nil then
231 self.wheelsUtilSmoothedAcceleratorPedal = 0
232 end
233
234 local appliedAcc = 0
235 if acceleratorPedal > 0 then
236 if acceleratorPedal > self.wheelsUtilSmoothedAcceleratorPedal then
237 appliedAcc = math.min(math.max(self.wheelsUtilSmoothedAcceleratorPedal + SMOOTHING_SPEED_SCALE * dt, SMOOTHING_SPEED_SCALE), acceleratorPedal)
238 else
239 appliedAcc = acceleratorPedal
240 end
241 self.wheelsUtilSmoothedAcceleratorPedal = appliedAcc
242 elseif acceleratorPedal < 0 then
243 if acceleratorPedal < self.wheelsUtilSmoothedAcceleratorPedal then
244 appliedAcc = math.max(math.min(self.wheelsUtilSmoothedAcceleratorPedal - SMOOTHING_SPEED_SCALE * dt, -SMOOTHING_SPEED_SCALE), acceleratorPedal)
245 else
246 appliedAcc = acceleratorPedal
247 end
248 self.wheelsUtilSmoothedAcceleratorPedal = appliedAcc
249 else
250 -- Decrease smoothed acceleration towards 0 with different speeds based on if we are braking
251 local decSpeed = 0.0005 + 0.001 * brakePedal -- scale between 2sec and 0.66s (full brake)
252 if self.wheelsUtilSmoothedAcceleratorPedal > 0 then
253 self.wheelsUtilSmoothedAcceleratorPedal = math.max(self.wheelsUtilSmoothedAcceleratorPedal - decSpeed*dt, 0)
254 else
255 self.wheelsUtilSmoothedAcceleratorPedal = math.min(self.wheelsUtilSmoothedAcceleratorPedal + decSpeed*dt, 0)
256 end
257 end
258
259 if self.wheelsUtilSmoothedBrakePedal == nil then
260 self.wheelsUtilSmoothedBrakePedal = 0
261 end
262
263 local appliedBrake = 0
264 if brakePedal > 0 then
265 if brakePedal > self.wheelsUtilSmoothedBrakePedal then
266 appliedBrake = math.min(self.wheelsUtilSmoothedBrakePedal + 0.0025*dt, brakePedal) -- full brake in 0.4sec
267 else
268 appliedBrake = brakePedal
269 end
270 self.wheelsUtilSmoothedBrakePedal = appliedBrake
271 else
272 -- Decrease smoothed brake towards 0 with different speeds based on if we are accelerating
273 local decSpeed = 0.0005 + 0.001 * acceleratorPedal -- scale between 2sec and 0.66s (full acceleration)
274 self.wheelsUtilSmoothedBrakePedal = math.max(self.wheelsUtilSmoothedBrakePedal - decSpeed*dt, 0)
275 end
276
277 --print(string.format("input: %.2f %.2f applied: %.2f %.2f", acceleratorPedal, brakePedal, appliedAcc, appliedBrake))
278
279 return appliedAcc, appliedBrake
280end

getTireFriction

Description
Returns tire friction
Definition
getTireFriction(Integer tireType, Integer groundType, float wetScale)
Arguments
IntegertireTypetire type index
IntegergroundTypeground type index
floatwetScalewet scale
Return Values
floattireFrictiontire friction
Code
737function WheelsUtil.getTireFriction(tireType, groundType, wetScale, snowScale)
738 if wetScale == nil then
739 wetScale = 0
740 end
741 local coeff = WheelsUtil.tireTypes[tireType].frictionCoeffs[groundType]
742 local coeffWet = WheelsUtil.tireTypes[tireType].frictionCoeffsWet[groundType]
743 local coeffSnow = WheelsUtil.tireTypes[tireType].frictionCoeffsSnow[groundType]
744 return coeff + (coeffWet-coeff)*wetScale + (coeffSnow-coeff)*snowScale
745end

getTireType

Description
Returns tire type index
Definition
getTireType(string name)
Arguments
stringnamename of tire type
Return Values
Integeriindex of tire type
Code
79function WheelsUtil.getTireType(name)
80 name = name:upper()
81 for i, t in pairs(WheelsUtil.tireTypes) do
82 if t.name == name then
83 return i
84 end
85 end
86 return nil
87end

getTireTypeName

Description
Returns tire type name by index
Definition
getTireTypeName(integer i)
Arguments
integeriindex of tire type
Return Values
stringnamename of tire type
Code
93function WheelsUtil.getTireTypeName(index)
94 if WheelsUtil.tireTypes[index] ~= nil then
95 return WheelsUtil.tireTypes[index].name
96 end
97
98 return "unknown"
99end

registerTireType

Description
Register new tire type
Definition
registerTireType(string name, table frictionCoeffs, table frictionCoeffsWer)
Arguments
stringnamename of new tire type
tablefrictionCoeffsfriction coeffs
tablefrictionCoeffsWerfriction coeffs wet
Code
29function WheelsUtil.registerTireType(name, frictionCoeffs, frictionCoeffsWet, frictionCoeffsSnow)
30 name = name:upper()
31 if WheelsUtil.getTireType(name) ~= nil then
32 print("Warning: Tire type '"..name.."' already registered, ignoring this definition")
33 return
34 end
35
36 local function getNoNilCoeffs(frictionCoeffs)
37 local localCoeffs = {}
38 if frictionCoeffs[1] == nil then
39 localCoeffs[1] = 1.15
40 for i=2,WheelsUtil.NUM_GROUNDS do
41 if frictionCoeffs[i] ~= nil then
42 localCoeffs[1] = frictionCoeffs[i]
43 break
44 end
45 end
46 else
47 localCoeffs[1] = frictionCoeffs[1]
48 end
49 for i=2,WheelsUtil.NUM_GROUNDS do
50 localCoeffs[i] = frictionCoeffs[i] or frictionCoeffs[i-1]
51 end
52 return localCoeffs
53 end
54
55 local tireType = {}
56 tireType.name = name
57 tireType.frictionCoeffs = getNoNilCoeffs(frictionCoeffs)
58 tireType.frictionCoeffsWet = getNoNilCoeffs(frictionCoeffsWet or frictionCoeffs)
59 tireType.frictionCoeffsSnow = getNoNilCoeffs(frictionCoeffsSnow or tireType.frictionCoeffsWet)
60 table.insert(WheelsUtil.tireTypes, tireType)
61end

unregisterTireType

Description
Remove a tire type
Definition
unregisterTireType()
Code
65function WheelsUtil.unregisterTireType(name)
66 name = name:upper()
67 for i, tireType in ipairs(WheelsUtil.tireTypes) do
68 if tireType.name == name then
69 table.remove(WheelsUtil.tireTypes, i)
70 break
71 end
72 end
73end

updateVisualWheel

Description
Update wheel graphics
Definition
updateVisualWheel(table wheel, float x, float y, float z, float x, float suspensionLength)
Arguments
tablewheelwheel
floatxx position
floatyy position
floatzz position
floatxx drive rotation
floatsuspensionLengthlength of suspension
Code
610function WheelsUtil.updateVisualWheel(self, wheel, x, y, z, xDrive, suspensionLength)
611 local changed = false
612
613 local steeringAngle = wheel.steeringAngle
614 if not wheel.showSteeringAngle then
615 steeringAngle = 0
616 end
617
618 if math.abs(steeringAngle-wheel.lastSteeringAngle) > STEERING_ANGLE_THRESHOLD then
619 setRotation(wheel.repr, 0, steeringAngle, 0)
620 wheel.lastSteeringAngle = steeringAngle
621 changed = true
622 end
623
624 if math.abs(xDrive-wheel.lastXDrive) > STEERING_ANGLE_THRESHOLD then
625 setRotation(wheel.driveNode, xDrive, 0, 0)
626 wheel.lastXDrive = xDrive
627 changed = true
628 end
629
630 if wheel.wheelTire ~= nil then
631 if self.spec_wheels.wheelVisualPressureActive then
632 local deformation = MathUtil.clamp((wheel.deltaY + wheel.initialDeformation - suspensionLength), 0, wheel.maxDeformation)
633 local prevDeformation, curDeformation
634 if math.abs(deformation - wheel.deformation) > 0.003 then
635 prevDeformation = wheel.deformation
636 curDeformation = deformation
637
638 wheel.deformation = deformation
639 wheel.derformationPrevDirty = true
640
641 changed = true
642 end
643
644 -- one frame delayed we update prev deformation to match cur deformation (TAA)
645 if wheel.derformationPrevDirty then
646 prevDeformation = wheel.deformation
647 curDeformation = wheel.deformation
648
649 wheel.derformationPrevDirty = false
650 end
651
652 if curDeformation ~= nil then
653 local mx, my, mz, _ = I3DUtil.getShaderParameterRec(wheel.wheelTire, "morphPosition")
654 I3DUtil.setShaderParameterRec(wheel.wheelTire, "morphPosition", mx, my, mz, curDeformation, false)
655 I3DUtil.setShaderParameterRec(wheel.wheelTire, "prevMorphPosition", mx, my, mz, prevDeformation, false)
656
657 if wheel.additionalWheels ~= nil then
658 for _, additionalWheel in pairs(wheel.additionalWheels) do
659 mx, my, mz, _ = I3DUtil.getShaderParameterRec(additionalWheel.wheelTire, "morphPosition")
660 I3DUtil.setShaderParameterRec(additionalWheel.wheelTire, "morphPosition", mx, my, mz, curDeformation, false)
661 I3DUtil.setShaderParameterRec(additionalWheel.wheelTire, "prevMorphPosition", mx, my, mz, prevDeformation, false)
662 end
663 end
664 end
665
666 -- increase suspension length a bit to make sure the wheel sides are touching the ground and not only the center
667 -- temporary disabled until we find a final solution
668 local sideOffset = 0--math.min((1-wheel.sideDeformOffset) * (wheel.radius-deformation), wheel.maxDeformation)
669
670 suspensionLength = suspensionLength + deformation + sideOffset
671 end
672 end
673
674 suspensionLength = suspensionLength - wheel.deltaY
675
676 if math.abs(wheel.lastMovement-suspensionLength) > SUSPENSION_THRESHOLD then
677 local dirX, dirY, dirZ = localDirectionToLocal(wheel.repr, getParent(wheel.repr), 0, -1, 0)
678 local transRatio = wheel.transRatio
679 local movement = suspensionLength * transRatio
680 setTranslation(wheel.repr, wheel.startPositionX + dirX*movement, wheel.startPositionY + dirY*movement, wheel.startPositionZ + dirZ*movement)
681 changed = true
682 if transRatio < 1 then
683 movement = suspensionLength*(1-transRatio)
684 setTranslation(wheel.driveNode, wheel.driveNodeStartPosX + dirX*movement, wheel.driveNodeStartPosY + dirY*movement, wheel.driveNodeStartPosZ + dirZ*movement)
685 end
686
687 wheel.lastMovement = suspensionLength
688 end
689
690 if wheel.steeringNode ~= nil then
691 local refAngle = wheel.steeringNodeMaxRot
692 local refTrans = wheel.steeringNodeMaxTransX
693 local refRot = wheel.steeringNodeMaxRotY
694 if steeringAngle < 0 then
695 refAngle = wheel.steeringNodeMinRot
696 refTrans = wheel.steeringNodeMinTransX
697 refRot = wheel.steeringNodeMinRotY
698 end
699 local steering = 0
700 if refAngle ~= 0 then
701 steering = steeringAngle / refAngle
702 end
703
704 if wheel.steeringNodeMinTransX ~= nil then
705 local x,y,z = getTranslation(wheel.steeringNode)
706 x = refTrans * steering
707 setTranslation(wheel.steeringNode, x, y, z)
708 end
709 if wheel.steeringNodeMinRotY ~= nil then
710 local rotX,rotY,rotZ = getRotation(wheel.steeringRotNode or wheel.steeringNode)
711 rotY = refRot * steering
712 setRotation(wheel.steeringRotNode or wheel.steeringNode, rotX, rotY, rotZ)
713 end
714 end
715
716 for i=1, #wheel.fenders do
717 local fender = wheel.fenders[i]
718
719 local angleDif = 0
720 if steeringAngle > fender.rotMax then
721 angleDif = fender.rotMax - steeringAngle
722 elseif steeringAngle < fender.rotMin then
723 angleDif = fender.rotMin - steeringAngle
724 end
725 setRotation(fender.node, 0, angleDif, 0)
726 end
727
728 return changed
729end

updateWheelGraphics

Description
Definition
updateWheelGraphics()
Code
571function WheelsUtil.updateWheelGraphics(self, wheel, dt)
572 local x, y, z = wheel.netInfo.x, wheel.netInfo.y, wheel.netInfo.z
573 local xDrive = wheel.netInfo.xDrive
574 local suspensionLength = wheel.netInfo.suspensionLength
575
576 if x ~= nil then
577 -- calculate xDriveSpeed
578 if wheel.netInfo.xDriveBefore == nil then
579 wheel.netInfo.xDriveBefore = xDrive
580 end
581
582 local xDriveDiff = xDrive - wheel.netInfo.xDriveBefore
583 if xDriveDiff > math.pi then
584 wheel.netInfo.xDriveBefore = wheel.netInfo.xDriveBefore + (2*math.pi)
585 elseif xDriveDiff < -math.pi then
586 wheel.netInfo.xDriveBefore = wheel.netInfo.xDriveBefore - (2*math.pi)
587 end
588 wheel.netInfo.xDriveDiff = xDrive - wheel.netInfo.xDriveBefore
589 wheel.netInfo.xDriveSpeed = wheel.netInfo.xDriveDiff / (0.001 * dt)
590 wheel.netInfo.xDriveBefore = xDrive
591
592 -- update visual wheel node
593 return WheelsUtil.updateVisualWheel(self, wheel, x, y, z, xDrive, suspensionLength)
594 end
595
596 return false
597end

updateWheelNetInfo

Description
Definition
updateWheelNetInfo()
Code
549function WheelsUtil.updateWheelNetInfo(self, wheel)
550 if wheel.updateWheel then
551 local x, y, z, xDrive, suspensionLength = getWheelShapePosition(wheel.node, wheel.wheelShape)
552 xDrive = xDrive + wheel.xDriveOffset
553
554 if wheel.dirtyFlag ~= nil and (wheel.netInfo.x ~= x or wheel.netInfo.z ~= z) then
555 self:raiseDirtyFlags(wheel.dirtyFlag)
556 end
557
558 --fill netinfo (on server)
559 wheel.netInfo.x = x
560 wheel.netInfo.y = y
561 wheel.netInfo.z = z
562 wheel.netInfo.xDrive = xDrive
563 wheel.netInfo.suspensionLength = suspensionLength
564 else
565 wheel.updateWheel = true
566 end
567end

updateWheelPhysics

Description
Update wheel physics
Definition
updateWheelPhysics(table wheel, boolean doHandbrake, float brakePedal, float dt)
Arguments
tablewheelwheel
booleandoHandbrakedoHandbrake
floatbrakePedalbrake pedal
floatdtdt
Code
472function WheelsUtil.updateWheelPhysics(self, wheel, brakePedal, dt)
473 WheelsUtil.updateWheelSteeringAngle(self, wheel, dt)
474
475 if self.isServer and self.isAddedToPhysics then
476 local brakeForce = self:getBrakeForce() * brakePedal
477 setWheelShapeProps(wheel.node, wheel.wheelShape, wheel.torque, brakeForce*wheel.brakeFactor, wheel.steeringAngle, wheel.rotationDamping)
478 end
479end

updateWheelsPhysics

Description
Updates wheel physics
Definition
updateWheelsPhysics(float dt, float currentSpeed, float acceleration, boolean doHandbrake, boolean stopAndGoBraking)
Arguments
floatdttime since last call in ms
floatcurrentSpeedsigned current speed (m/ms)
floataccelerationtarget acceleration [-1,1]
booleandoHandbrakedo handbrake
booleanstopAndGoBrakingif false, the acceleration needs to be 0 before a change of direction is allowed
Code
289function WheelsUtil.updateWheelsPhysics(self, dt, currentSpeed, acceleration, doHandbrake, stopAndGoBraking)
290--print("function WheelsUtil.updateWheelsPhysics("..tostring(self)..", "..tostring(dt)..", "..tostring(currentSpeed)..", "..tostring(acceleration)..", "..tostring(doHandbrake)..", "..tostring(stopAndGoBraking))
291
292 local acceleratorPedal = 0
293 local brakePedal = 0
294
295 local reverserDirection = 1
296 if self.spec_drivable ~= nil then
297 reverserDirection = self.spec_drivable.reverserDirection
298 end
299
300 local motor = self.spec_motorized.motor
301 local isManualTransmission = motor.backwardGears ~= nil or motor.forwardGears ~= nil
302 local useManualDirectionChange = (isManualTransmission and motor.gearShiftMode ~= VehicleMotor.SHIFT_MODE_AUTOMATIC)
303 or motor.directionChangeMode == VehicleMotor.DIRECTION_CHANGE_MODE_MANUAL
304 useManualDirectionChange = useManualDirectionChange and self:getIsManualDirectionChangeAllowed()
305 if useManualDirectionChange then
306 acceleration = acceleration * motor.currentDirection
307 else
308 acceleration = acceleration * reverserDirection
309 end
310
311 local absCurrentSpeed = math.abs(currentSpeed)
312 local accSign = MathUtil.sign(acceleration)
313
314 self.nextMovingDirection = self.nextMovingDirection or 0
315 self.nextMovingDirectionTimer = self.nextMovingDirectionTimer or 0
316
317 local automaticBrake = false
318 if math.abs(acceleration) < 0.001 then
319 automaticBrake = true
320
321 -- Non-stop&go only allows change of direction if the vehicle speed is smaller than 1km/h or the direction has already changed (e.g. because the brakes are not hard enough)
322 if stopAndGoBraking or currentSpeed * self.nextMovingDirection < 0.0003 then
323 self.nextMovingDirection = 0
324 end
325 else
326 -- Disable the known moving direction if the vehicle is driving more than 5km/h (0.0014 * 3600 = 5.04km/h) in the opposite direction
327 if self.nextMovingDirection * currentSpeed < -0.0014 then
328 self.nextMovingDirection = 0
329 end
330
331 -- Continue accelerating if we want to go in the same direction
332 -- or if the vehicle is only moving slowly in the wrong direction (0.0003 * 3600 = 1.08 km/h) and we are allowed to change direction
333 if accSign == self.nextMovingDirection or (currentSpeed * accSign > -0.0003 and (stopAndGoBraking or self.nextMovingDirection == 0)) then
334 self.nextMovingDirectionTimer = math.max(self.nextMovingDirectionTimer - dt, 0)
335 if self.nextMovingDirectionTimer == 0 then
336 acceleratorPedal = acceleration
337 brakePedal = 0
338 self.nextMovingDirection = accSign
339 else
340 acceleratorPedal = 0
341 brakePedal = math.abs(acceleration)
342 end
343 else
344 acceleratorPedal = 0
345 brakePedal = math.abs(acceleration)
346 if stopAndGoBraking then
347 self.nextMovingDirectionTimer = 100
348 end
349 end
350 end
351
352 if useManualDirectionChange then
353 if acceleratorPedal ~= 0 and MathUtil.sign(acceleratorPedal) ~= motor.currentDirection then
354 brakePedal = math.abs(acceleratorPedal)
355 acceleratorPedal = 0
356 end
357 end
358
359 if automaticBrake then
360 acceleratorPedal = 0
361 end
362
363 acceleratorPedal, brakePedal = motor:updateGear(acceleratorPedal, brakePedal, dt)
364
365 if motor.gear == 0 and motor.targetGear ~= 0 then
366 -- brake automatically if the vehicle is rolling backwards while shifting
367 if currentSpeed * MathUtil.sign(motor.targetGear) < 0 then
368 automaticBrake = true
369 end
370 end
371
372 if motor.gearShiftMode == VehicleMotor.SHIFT_MODE_MANUAL_CLUTCH then
373 if isManualTransmission then
374 automaticBrake = false
375 end
376 end
377
378 if automaticBrake then
379 local isSlow = absCurrentSpeed < motor.lowBrakeForceSpeedLimit
380 local isArticulatedSteering = self.spec_articulatedAxis ~= nil and self.spec_articulatedAxis.componentJoint ~= nil and math.abs(self.rotatedTime) > 0.01
381
382 if (isSlow or doHandbrake) and not isArticulatedSteering then
383 brakePedal = 1
384 else
385 -- interpolate between lowBrakeForce and 1 if speed is below 3.6 km/h
386 local factor = math.min(absCurrentSpeed / 0.001, 1)
387 brakePedal = MathUtil.lerp(1, motor.lowBrakeForceScale, factor)
388 end
389 end
390
391 SpecializationUtil.raiseEvent(self, "onVehiclePhysicsUpdate", acceleratorPedal, brakePedal, automaticBrake, currentSpeed)
392
393 acceleratorPedal, brakePedal = WheelsUtil.getSmoothedAcceleratorAndBrakePedals(self, acceleratorPedal, brakePedal, dt)
394
395 local maxSpeed = motor:getMaximumForwardSpeed() * 3.6
396 if self.movingDirection < 0 then
397 maxSpeed = motor:getMaximumBackwardSpeed() * 3.6
398 end
399
400 --active braking if over the speed limit
401 local overSpeedLimit = self:getLastSpeed() - math.min(motor:getSpeedLimit(), maxSpeed)
402 if overSpeedLimit > 0 then
403 if overSpeedLimit > 0.3 then
404 motor.overSpeedTimer = math.min(motor.overSpeedTimer + dt, 2000)
405 else
406 motor.overSpeedTimer = math.max(motor.overSpeedTimer - dt, 0)
407 end
408
409 -- the longer we exceed the speed limit by min. 0.3km/h, the harder we brake
410 -- so we have a smooth braking when the speed limit changes and a harder brake when driving downhill with a full trailer
411 local factor = 0.5 + (motor.overSpeedTimer / 2000 * 1)
412
413 brakePedal = math.max(math.min(math.pow(overSpeedLimit * factor, 2), 1), brakePedal)
414 acceleratorPedal = 0.2 * math.max(1 - overSpeedLimit/0.2, 0) * acceleratorPedal -- fadeout the accelerator pedal over 0.2km/h, but immediately reduce to 20% (don't set to 0 directly so that the physics engine can still compensate if the brakes are too hard)
415 else
416 acceleratorPedal = acceleratorPedal * math.min(math.abs(overSpeedLimit) / 0.3 + 0.2, 1)
417 motor.overSpeedTimer = 0
418 end
419
420 if next(self.spec_motorized.differentials) ~= nil and self.spec_motorized.motorizedNode ~= nil then
421
422 local absAcceleratorPedal = math.abs(acceleratorPedal)
423 local minGearRatio, maxGearRatio = motor:getMinMaxGearRatio()
424
425 local maxSpeed
426 if maxGearRatio >= 0 then
427 maxSpeed = motor:getMaximumForwardSpeed()
428 else
429 maxSpeed = motor:getMaximumBackwardSpeed()
430 end
431
432 local acceleratorPedalControlsSpeed = false
433 if acceleratorPedalControlsSpeed then
434 maxSpeed = maxSpeed * absAcceleratorPedal
435 if absAcceleratorPedal > 0.001 then
436 absAcceleratorPedal = 1
437 end
438 end
439 maxSpeed = math.min(maxSpeed, motor:getSpeedLimit() / 3.6)
440 local maxAcceleration = motor:getAccelerationLimit()
441 local maxMotorRotAcceleration = motor:getMotorRotationAccelerationLimit()
442 local minMotorRpm, maxMotorRpm = motor:getRequiredMotorRpmRange()
443
444 local neededPtoTorque, ptoTorqueVirtualMultiplicator = PowerConsumer.getTotalConsumedPtoTorque(self)
445 neededPtoTorque = neededPtoTorque / motor:getPtoMotorRpmRatio()
446 local neutralActive = (minGearRatio == 0 and maxGearRatio == 0) or motor:getManualClutchPedal() > 0.90
447
448 motor:setExternalTorqueVirtualMultiplicator(ptoTorqueVirtualMultiplicator)
449
450 --print(string.format("set vehicle props: accPed=%.1f speed=%.1f gearRatio=[%.1f %.1f] rpm=[%.1f %.1f], ptoTorque=[%.1f]", absAcceleratorPedal, maxSpeed, minGearRatio, maxGearRatio, minMotorRpm, maxMotorRpm, neededPtoTorque))
451 if not neutralActive then
452 self:controlVehicle(absAcceleratorPedal, maxSpeed, maxAcceleration, minMotorRpm*math.pi/30, maxMotorRpm*math.pi/30, maxMotorRotAcceleration, minGearRatio, maxGearRatio, motor:getMaxClutchTorque(), neededPtoTorque)
453 else
454 self:controlVehicle(0.0, 0.0, 0.0, 0.0, math.huge, 0.0, 0.0, 0.0, 0.0, 0.0)
455
456 -- slightly break while using manual + clutch and in neutral position
457 -- to simulate a bit of rolling resistance
458 brakePedal = math.max(brakePedal, 0.03)
459 end
460 end
461
462 self:brake(brakePedal)
463end

updateWheelSteeringAngle

Description
Update wheel steering angle
Definition
updateWheelSteeringAngle(table wheel, float dt)
Arguments
tablewheelwheel
floatdttime since last call in ms
Code
485function WheelsUtil.updateWheelSteeringAngle(self, wheel, dt)
486
487 local steeringAngle = wheel.steeringAngle
488 local rotatedTime = self.rotatedTime
489
490 if wheel.steeringAxleScale ~= nil and wheel.steeringAxleScale ~= 0 then
491 local steeringAxleAngle = 0
492 if self.spec_attachable ~= nil then
493 steeringAxleAngle = self.spec_attachable.steeringAxleAngle
494 end
495 steeringAngle = MathUtil.clamp(steeringAxleAngle * wheel.steeringAxleScale, wheel.steeringAxleRotMin, wheel.steeringAxleRotMax)
496 elseif wheel.versatileYRot and self:getIsVersatileYRotActive(wheel) then
497 if self.isServer then
498 if wheel.forceVersatility or wheel.hasGroundContact then
499 steeringAngle = Utils.getVersatileRotation(wheel.repr, wheel.node, dt, wheel.positionX, wheel.positionY, wheel.positionZ, wheel.steeringAngle, wheel.rotMin, wheel.rotMax)
500 end
501 end
502 elseif (wheel.rotSpeed ~= 0 and wheel.rotMax ~= nil and wheel.rotMin ~= nil) or wheel.forceSteeringAngleUpdate then
503 if rotatedTime > 0 or wheel.rotSpeedNeg == nil then
504 steeringAngle = rotatedTime * wheel.rotSpeed
505 else
506 steeringAngle = rotatedTime * wheel.rotSpeedNeg
507 end
508 if steeringAngle > wheel.rotMax then
509 steeringAngle = wheel.rotMax
510 elseif steeringAngle < wheel.rotMin then
511 steeringAngle = wheel.rotMin
512 end
513 if self.customSteeringAngleFunction then
514 steeringAngle = self:updateSteeringAngle(wheel, dt, steeringAngle)
515 end
516 end
517
518 wheel.steeringAngle = steeringAngle
519end