Sprache Deutsch Language English

Script Dokumentation LS 2015 - WheelsUtil (Patch 1.3)

Script Dokumentation Übersicht

scripts/vehicles/WheelsUtil.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1--
2-- Wheels util
3-- Util class to manage wheels of a vehicle
4--
5-- @author Stefan Geiger
6-- @date 11/03/08
7--
8-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
9
10WheelsUtil = {};
11
12-- Note: these are in order of decreasing hardness so that default friction fallback is easier to implement
13WheelsUtil.GROUND_ROAD = 1;
14WheelsUtil.GROUND_HARD_TERRAIN = 2;
15WheelsUtil.GROUND_SOFT_TERRAIN = 3;
16WheelsUtil.GROUND_FIELD = 4;
17WheelsUtil.NUM_GROUNDS = 4;
18
19WheelsUtil.tireTypes = {};
20
21function WheelsUtil.registerTireType(name, frictionCoeffs, frictionCoeffsWet)
22 local tireType = WheelsUtil.getTireType(name);
23 if tireType ~= nil then
24 print("Warning: Adding duplicate tire type '"..name.."'");
25 return;
26 end
27
28 local function getNoNilCoeffs(frictionCoeffs)
29 local localCoeffs = {};
30 if frictionCoeffs[1] == nil then
31 localCoeffs[1] = 1.15;
32 for i=2,WheelsUtil.NUM_GROUNDS do
33 if frictionCoeffs[i] ~= nil then
34 localCoeffs[1] = frictionCoeffs[i];
35 break;
36 end
37 end
38 else
39 localCoeffs[1] = frictionCoeffs[1];
40 end
41 for i=2,WheelsUtil.NUM_GROUNDS do
42 localCoeffs[i] = frictionCoeffs[i] or frictionCoeffs[i-1];
43 end
44 return localCoeffs
45 end
46
47 local tireType = {};
48 tireType.name = name;
49 tireType.frictionCoeffs = getNoNilCoeffs(frictionCoeffs);
50 tireType.frictionCoeffsWet = getNoNilCoeffs(frictionCoeffsWet or frictionCoeffs);
51 table.insert(WheelsUtil.tireTypes, tireType);
52end
53
54function WheelsUtil.getTireType(name)
55 for i, t in pairs(WheelsUtil.tireTypes) do
56 if t.name == name then
57 return i;
58 end
59 end
60 return nil;
61end
62
63local mudTireCoeffs = {};
64mudTireCoeffs[WheelsUtil.GROUND_ROAD] = 1.15;
65mudTireCoeffs[WheelsUtil.GROUND_HARD_TERRAIN] = 1.15;
66mudTireCoeffs[WheelsUtil.GROUND_SOFT_TERRAIN] = 1.1;
67mudTireCoeffs[WheelsUtil.GROUND_FIELD] = 1.1;
68
69local mudTireCoeffsWet = {};
70mudTireCoeffsWet[WheelsUtil.GROUND_ROAD] = 1.05;
71mudTireCoeffsWet[WheelsUtil.GROUND_HARD_TERRAIN] = 1.05;
72mudTireCoeffsWet[WheelsUtil.GROUND_SOFT_TERRAIN] = 1.0;
73mudTireCoeffsWet[WheelsUtil.GROUND_FIELD] = 0.95;
74
75WheelsUtil.registerTireType("mud", mudTireCoeffs, mudTireCoeffsWet);
76
77local offRoadTireCoeffs = {};
78offRoadTireCoeffs[WheelsUtil.GROUND_ROAD] = 1.2;
79offRoadTireCoeffs[WheelsUtil.GROUND_HARD_TERRAIN] = 1.15;
80offRoadTireCoeffs[WheelsUtil.GROUND_SOFT_TERRAIN] = 1.05;
81offRoadTireCoeffs[WheelsUtil.GROUND_FIELD] = 1.0;
82
83local offRoadTireCoeffsWet = {};
84offRoadTireCoeffsWet[WheelsUtil.GROUND_ROAD] = 1.05;
85offRoadTireCoeffsWet[WheelsUtil.GROUND_HARD_TERRAIN] = 1.0;
86offRoadTireCoeffsWet[WheelsUtil.GROUND_SOFT_TERRAIN] = 0.95;
87offRoadTireCoeffsWet[WheelsUtil.GROUND_FIELD] = 0.85;
88
89WheelsUtil.registerTireType("offRoad", offRoadTireCoeffs, offRoadTireCoeffsWet);
90
91local streetTireCoeffs = {};
92streetTireCoeffs[WheelsUtil.GROUND_ROAD] = 1.25;
93streetTireCoeffs[WheelsUtil.GROUND_HARD_TERRAIN] = 1.15;
94streetTireCoeffs[WheelsUtil.GROUND_SOFT_TERRAIN] = 1.0;
95streetTireCoeffs[WheelsUtil.GROUND_FIELD] = 0.9;
96
97local streetTireCoeffsWet = {};
98streetTireCoeffsWet[WheelsUtil.GROUND_ROAD] = 1.15;
99streetTireCoeffsWet[WheelsUtil.GROUND_HARD_TERRAIN] = 1.0;
100streetTireCoeffsWet[WheelsUtil.GROUND_SOFT_TERRAIN] = 0.85;
101streetTireCoeffsWet[WheelsUtil.GROUND_FIELD] = 0.75;
102
103WheelsUtil.registerTireType("street", streetTireCoeffs, streetTireCoeffsWet);
104
105-- crawlers are similar to mud tires (but have slightly more traction in field, and loose less traction on fields when raining)
106local crawlerCoeffs = {};
107crawlerCoeffs[WheelsUtil.GROUND_ROAD] = 1.15;
108crawlerCoeffs[WheelsUtil.GROUND_HARD_TERRAIN] = 1.15;
109crawlerCoeffs[WheelsUtil.GROUND_SOFT_TERRAIN] = 1.15;
110crawlerCoeffs[WheelsUtil.GROUND_FIELD] = 1.15;
111
112local crawlerCoeffsWet = {};
113crawlerCoeffsWet[WheelsUtil.GROUND_ROAD] = 1.05;
114crawlerCoeffsWet[WheelsUtil.GROUND_HARD_TERRAIN] = 1.05;
115crawlerCoeffsWet[WheelsUtil.GROUND_SOFT_TERRAIN] = 1.05;
116crawlerCoeffsWet[WheelsUtil.GROUND_FIELD] = 1.05;
117
118WheelsUtil.registerTireType("crawler", crawlerCoeffs, crawlerCoeffsWet);
119
120function WheelsUtil.updateWheelsPhysics(self, dt, currentSpeed, acceleration, doHandbrake, requiredDriveMode)
121
122 local brakeAcc = false;
123 if (self.movingDirection*currentSpeed*Utils.sign(acceleration)) < -0.0003 then -- 0.0003 * 3600 = 1.08 km/h
124 -- do we want to accelerate in the opposite direction of the vehicle speed?
125 brakeAcc = true;
126 end;
127
128 local accelerationPedal;
129 local brakePedal = 0;
130 if math.abs(acceleration) < 0.001 then
131 accelerationPedal = 0;
132 --brakePedal = 1;
133
134 if currentSpeed < self.motor.lowBrakeForceSpeedLimit or doHandbrake then
135 --if self.rotatedTime == 0 or self.articulatedAxis == nil then -- TODO: Remove E3-Fix
136 if math.abs(self.rotatedTime) < 0.01 or self.articulatedAxis == nil then
137 brakePedal = 1;
138 end;
139 else
140 brakePedal = self.motor.lowBrakeForceScale;
141 end;
142 else
143 if not brakeAcc then
144 accelerationPedal = acceleration;
145 brakePedal = 0;
146 else
147 accelerationPedal = 0;
148 brakePedal = math.abs(acceleration);
149 end;
150 end;
151
152 self:setBrakeLightsVisibility(brakePedal > self.motor.lowBrakeForceScale and currentSpeed > 0.0004);
153 self:setReverseLightsVisibility(self.movingDirection < 0 and currentSpeed > 0.0004);
154
155 self.motor:updateMotorRpm(dt);
156 self.motor:updateGear(accelerationPedal);
157
158 local absAccelerationPedal = math.abs(accelerationPedal);
159
160 local wheelDriveTorque = 0;
161
162 --print(string.format("brakeAcc:%s acc.:%6.4f accPed.:%6.4f braPed.:%6.4f curSpeed:%6.4f", tostring(brakeAcc), acceleration, accelerationPedal, brakePedal, currentSpeed));
163
164 if next(self.differentials) ~= nil and self.motorizedNode ~= nil then
165 --print(string.format("set vehicle props: %.2f %.1f %.1f %.1f", self.motor:getTorque(accelerationPedal, false)*absAccelerationPedal, self.motor:getCurMaxRpm(), self.motor:getGearRatio(), 0.01));
166 local maxRotSpeed = self.motor:getCurMaxRpm() * math.pi / 30;
167 local torque = self.motor:getTorque(accelerationPedal, false);
168
169 setVehicleProps(self.motorizedNode, torque, maxRotSpeed, self.motor:getGearRatio(), self.motor.maxClutchTorque);
170 else
171 local numTouching = 0;
172 local numNotTouching = 0;
173 local numHandbrake = 0;
174
175 local axleSpeedSum = 0;
176 for _, wheel in pairs(self.wheels) do
177 if wheel.driveMode >= requiredDriveMode then
178 if doHandbrake and wheel.hasHandbrake then
179 numHandbrake = numHandbrake +1;
180 else
181 if wheel.hasGroundContact then
182 numTouching = numTouching+1;
183 else
184 numNotTouching = numNotTouching+1;
185 end;
186 end;
187 end;
188 end;
189
190 if numTouching > 0 and absAccelerationPedal > 0.01 then
191 local axisTorque, brakePedalMotor = WheelsUtil.getWheelTorque(self, accelerationPedal);
192 if axisTorque ~= 0 then
193 wheelDriveTorque = axisTorque / (numTouching+numNotTouching); --*0.7);
194 else
195 brakePedal = brakePedalMotor;
196 end;
197 end;
198 end
199
200 local doBrake = brakePedal > 0; --(brakePedal > 0 and self.lastSpeed > 0.0002) or doHandbrake;
201 for _, implement in pairs(self.attachedImplements) do
202 if implement.object ~= nil then
203 if doBrake then
204 implement.object:onBrake(brakePedal);
205 else
206 implement.object:onReleaseBrake();
207 end;
208 end
209 end;
210
211 for _, wheel in pairs(self.wheels) do
212 WheelsUtil.updateWheelPhysics(self, wheel, doHandbrake, wheelDriveTorque, brakePedal, requiredDriveMode, dt)
213 end;
214
215end;
216
217function WheelsUtil.getWheelTorque(self, accelerationPedal)
218 local torque, brakePedal = self.motor:getTorque(accelerationPedal, true);
219 local torque = torque * math.abs(accelerationPedal);
220
221 return torque * self.motor:getGearRatio(), brakePedal;
222end;
223
224function WheelsUtil.updateWheelPhysics(self, wheel, handbrake, motorTorque, brakePedal, requiredDriveMode, dt)
225
226 local brakeForce = brakePedal*self.motor.brakeForce;
227 if handbrake and wheel.hasHandbrake then
228 brakeForce = self.motor.brakeForce*10;
229 end;
230
231 if motorTorque ~= 0 then
232 if wheel.driveMode < requiredDriveMode then
233 motorTorque = 0;
234 elseif not wheel.hasGroundContact then
235 motorTorque = motorTorque*0.7;
236 end;
237 end
238
239 local steeringAngle = wheel.steeringAngle;
240
241 setWheelShapeProps(wheel.node, wheel.wheelShape, motorTorque, brakeForce, steeringAngle);
242end;
243
244function WheelsUtil.updateWheelHasGroundContact(wheel)
245
246 local x,_,_ = getWheelShapeContactPoint(wheel.node, wheel.wheelShape)
247 wheel.hasGroundContact = x~=nil;
248 --return wheel.hasGroundContact;
249end;
250
251function WheelsUtil.updateWheelSteeringAngle(self, wheel, dt)
252 local steeringAngle = 0;
253 local rotatedTime = self.rotatedTime;
254 if wheel.rotSpeed ~= 0 then
255 if rotatedTime > 0 or wheel.rotSpeedNeg == nil then
256 steeringAngle = rotatedTime * wheel.rotSpeed;
257 else
258 steeringAngle = rotatedTime * wheel.rotSpeedNeg;
259 end
260 if steeringAngle > wheel.rotMax then
261 steeringAngle = wheel.rotMax;
262 elseif steeringAngle < wheel.rotMin then
263 steeringAngle = wheel.rotMin;
264 end;
265 if self.updateSteeringAngle ~= nil then
266 steeringAngle = self:updateSteeringAngle(wheel, dt, steeringAngle);
267 end
268 elseif wheel.steeringAxleScale ~= 0 then
269 steeringAngle = Utils.clamp(self.steeringAxleAngle * wheel.steeringAxleScale, wheel.steeringAxleRotMin, wheel.steeringAxleRotMax);
270 elseif wheel.versatileYRot then
271 if self.isServer then
272 if wheel.forceVersatility or wheel.hasGroundContact then
273 steeringAngle = Utils.getVersatileRotation(wheel.repr, wheel.node, dt, wheel.positionX, wheel.positionY, wheel.positionZ, wheel.steeringAngle, wheel.rotMin, wheel.rotMax);
274 end;
275 end;
276 end;
277 wheel.steeringAngle = steeringAngle;
278end;
279
280function WheelsUtil.computeRpmFromWheels(self)
281 local wheelSpeed = 0;
282 local numWheels = 0;
283 for _, wheel in pairs(self.wheels) do
284 local axleSpeed = getWheelShapeAxleSpeed(wheel.node, wheel.wheelShape); -- rad/sec
285 if wheel.hasGroundContact then
286 wheelSpeed = wheelSpeed + axleSpeed * wheel.radius;
287 numWheels = numWheels+1;
288 end;
289 end;
290
291 if numWheels > 0 then
292 return wheelSpeed*30/(math.pi*numWheels);
293 end
294 return 0;
295end;
296
297function WheelsUtil.computeRpmFromSpeed(self)
298 -- v = w*r => w = v/r
299 -- w = 2pi*rpm / 60
300 -- rpm = 60 * v/r/(2pi)
301 return (self.lastSpeedReal*30000 / math.pi);
302end;
303
304function WheelsUtil.updateWheelsGraphics(self, dt)
305 if self.isServer then
306 self.hasWheelGroundContact = false;
307 end
308
309 for i, wheel in pairs(self.wheels) do
310 WheelsUtil.updateWheelSteeringAngle(self, wheel, dt);
311 if self.isServer then
312 WheelsUtil.updateWheelHasGroundContact(wheel);
313 if wheel.hasGroundContact then
314 self.hasWheelGroundContact = true;
315 end;
316
317 local x,y,z, xDrive = getWheelShapePosition(wheel.node, wheel.wheelShape);
318
319 WheelsUtil.updateWheelGraphics(self, wheel, x, y, z, xDrive);
320
321 --fill netinfo (on server)
322 wheel.netInfo.x = x;
323 wheel.netInfo.y = y;
324 wheel.netInfo.z = z;
325 wheel.netInfo.xDrive = xDrive;
326 else
327 -- client code
328 local x, y, z = wheel.netInfo.x, wheel.netInfo.y, wheel.netInfo.z;
329 local xDrive = wheel.netInfo.xDrive;
330 WheelsUtil.updateWheelGraphics(self, wheel, x, y, z, xDrive);
331 end;
332 end;
333end;
334
335function WheelsUtil.updateWheelGraphics(self, wheel, x, y, z, xDrive)
336 local steeringAngle = wheel.steeringAngle;
337 if not wheel.showSteeringAngle then
338 steeringAngle = 0;
339 end;
340 local x,y,z = worldToLocal(getParent(wheel.repr), localToWorld(wheel.node, x,y,z));
341 setTranslation(wheel.repr, x, y, z);
342
343 if wheel.repr == wheel.driveNode then
344 setRotation(wheel.repr, xDrive, steeringAngle, 0);
345 else
346 setRotation(wheel.repr, 0, steeringAngle, 0);
347 setRotation(wheel.driveNode, xDrive, 0, 0);
348 end;
349
350 if wheel.steeringNode ~= nil then
351 local refAngle = wheel.steeringNodeMaxRot;
352 local refTrans = wheel.steeringNodeMaxTransX
353 if steeringAngle < 0 then
354 refAngle = wheel.steeringNodeMinRot;
355 refTrans = wheel.steeringNodeMinTransX;
356 end;
357 local steering = 0;
358 if refAngle ~= 0 then
359 steering = steeringAngle / refAngle;
360 end;
361
362 local x,y,z = getTranslation(wheel.steeringNode);
363 local x = refTrans * steering;
364 setTranslation(wheel.steeringNode, x, y, z);
365 end;
366
367 if wheel.fenderNode ~= nil then
368 local angleDif = 0;
369 if steeringAngle > wheel.fenderRotMax then
370 angleDif = wheel.fenderRotMax - steeringAngle;
371 elseif steeringAngle < wheel.fenderRotMin then
372 angleDif = wheel.fenderRotMin - steeringAngle;
373 end;
374 setRotation(wheel.fenderNode, 0, angleDif, 0);
375 end;
376end;
377
378function WheelsUtil.getTireFriction(tireType, groundType, wetScale)
379 if wetScale == nil then
380 wetScale = 0;
381 end
382 local coeff = WheelsUtil.tireTypes[tireType].frictionCoeffs[groundType];
383 local coeffWet = WheelsUtil.tireTypes[tireType].frictionCoeffsWet[groundType];
384 return coeff + (coeffWet-coeff)*wetScale;
385end
386
387function WheelsUtil.getGroundType(isField, isRoad, attributes)
388 -- terrain softness:
389 -- [ 0, 0.1]: road
390 -- [0.1, 0.8]: hard terrain
391 -- [0.8, 1 ]: soft terrain
392 if isField then
393 return WheelsUtil.GROUND_FIELD
394 elseif isRoad or attributes[4] < 0.1 then
395 return WheelsUtil.GROUND_ROAD;
396 else
397 if attributes[4] > 0.8 then
398 return WheelsUtil.GROUND_SOFT_TERRAIN;
399 else
400 return WheelsUtil.GROUND_HARD_TERRAIN;
401 end
402 end
403end
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht