1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22
23 #include "../Core/Context.h"
24 #include "../Physics/PhysicsUtils.h"
25 #include "../Physics/RigidBody.h"
26 #include "../Physics/PhysicsWorld.h"
27 #include "../Scene/Scene.h"
28 #include "../IO/Log.h"
29 #include "../Physics/RaycastVehicle.h"
30
31 #include <Bullet/BulletDynamics/Vehicle/btRaycastVehicle.h>
32 #include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
33
34 namespace Urho3D
35 {
36
37 struct RaycastVehicleData
38 {
RaycastVehicleDataUrho3D::RaycastVehicleData39 RaycastVehicleData()
40 {
41 vehicleRayCaster_ = 0;
42 vehicle_ = 0;
43 added_ = false;
44 }
45
~RaycastVehicleDataUrho3D::RaycastVehicleData46 ~RaycastVehicleData()
47 {
48 if (vehicleRayCaster_)
49 {
50 delete vehicleRayCaster_;
51 }
52 vehicleRayCaster_ = 0;
53 if (vehicle_)
54 {
55 if (physWorld_ && added_)
56 {
57 btDynamicsWorld* pbtDynWorld = physWorld_->GetWorld();
58 if (pbtDynWorld)
59 pbtDynWorld->removeAction(vehicle_);
60 added_ = false;
61 }
62 delete vehicle_;
63 }
64 vehicle_ = 0;
65 }
66
GetUrho3D::RaycastVehicleData67 btRaycastVehicle* Get()
68 {
69 return vehicle_;
70 }
71
InitUrho3D::RaycastVehicleData72 void Init(Scene* scene, RigidBody* body, bool enabled)
73 {
74 int rightIndex = 0;
75 int upIndex = 1;
76 int forwardIndex = 2;
77 PhysicsWorld* pPhysWorld = scene->GetComponent<PhysicsWorld>();
78 btDynamicsWorld* pbtDynWorld = pPhysWorld->GetWorld();
79 if (!pbtDynWorld)
80 return;
81
82 // Delete old vehicle & action first
83 if (vehicleRayCaster_)
84 delete vehicleRayCaster_;
85 if (vehicle_)
86 {
87 if (added_)
88 pbtDynWorld->removeAction(vehicle_);
89 delete vehicle_;
90 }
91
92 vehicleRayCaster_ = new btDefaultVehicleRaycaster(pbtDynWorld);
93 btRigidBody* bthullBody = body->GetBody();
94 vehicle_ = new btRaycastVehicle(tuning_, bthullBody, vehicleRayCaster_);
95 if (enabled)
96 {
97 pbtDynWorld->addAction(vehicle_);
98 added_ = true;
99 }
100
101 vehicle_->setCoordinateSystem(rightIndex, upIndex, forwardIndex);
102 physWorld_ = pPhysWorld;
103 }
104
SetEnabledUrho3D::RaycastVehicleData105 void SetEnabled(bool enabled)
106 {
107 if (!physWorld_ || !vehicle_)
108 return;
109 btDynamicsWorld* pbtDynWorld = physWorld_->GetWorld();
110 if (!pbtDynWorld)
111 return;
112
113 if (enabled && !added_)
114 {
115 pbtDynWorld->addAction(vehicle_);
116 added_ = true;
117 }
118 else if (!enabled && added_)
119 {
120 pbtDynWorld->removeAction(vehicle_);
121 added_ = false;
122 }
123 }
124
125 WeakPtr<PhysicsWorld> physWorld_;
126 btVehicleRaycaster* vehicleRayCaster_;
127 btRaycastVehicle* vehicle_;
128 btRaycastVehicle::btVehicleTuning tuning_;
129 bool added_;
130 };
131
RaycastVehicle(Context * context)132 RaycastVehicle::RaycastVehicle(Context* context) :
133 LogicComponent(context)
134 {
135 // fixed update() for inputs and post update() to sync wheels for rendering
136 SetUpdateEventMask(USE_FIXEDUPDATE | USE_FIXEDPOSTUPDATE | USE_POSTUPDATE);
137 vehicleData_ = new RaycastVehicleData();
138 wheelNodes_.Clear();
139 activate_ = false;
140 inAirRPM_ = 0.0f;
141 maxSideSlipSpeed_ = 4.0f;
142 }
143
~RaycastVehicle()144 RaycastVehicle::~RaycastVehicle()
145 {
146 delete vehicleData_;
147 wheelNodes_.Clear();
148 }
149
150 const char* wheelElementNames[] =
151 {
152 "Number of wheels",
153 " Wheel node id",
154 " Wheel direction",
155 " Wheel axle",
156 " Wheel rest length",
157 " Wheel radius",
158 " Wheel is front wheel",
159 " Steering",
160 " Connection point vector",
161 " Original rotation",
162 " Cumulative skid info",
163 " Side skip speed",
164 " Grounded",
165 " Contact position",
166 " Contact normal",
167 " Suspension stiffness",
168 " Damping relaxation",
169 " Damping compression",
170 " Friction slip",
171 " Roll influence",
172 " Engine force",
173 " Brake",
174 0
175 };
176
RegisterObject(Context * context)177 void RaycastVehicle::RegisterObject(Context* context)
178 {
179 context->RegisterFactory<RaycastVehicle>();
180 URHO3D_MIXED_ACCESSOR_VARIANT_VECTOR_STRUCTURE_ATTRIBUTE("Wheel data", GetWheelDataAttr, SetWheelDataAttr,
181 VariantVector, Variant::emptyVariantVector,
182 wheelElementNames, AM_DEFAULT);
183 URHO3D_ATTRIBUTE("Maximum side slip threshold", float, maxSideSlipSpeed_, 4.0f, AM_DEFAULT);
184 URHO3D_ATTRIBUTE("RPM for wheel motors in air (0=calculate)", float, inAirRPM_, 0.0f, AM_DEFAULT);
185 }
186
OnSetEnabled()187 void RaycastVehicle::OnSetEnabled()
188 {
189 if (vehicleData_)
190 vehicleData_->SetEnabled(IsEnabledEffective());
191 }
192
ApplyAttributes()193 void RaycastVehicle::ApplyAttributes()
194 {
195 int index = 0;
196 hullBody_ = node_->GetOrCreateComponent<RigidBody>();
197 Scene* scene = GetScene();
198 vehicleData_->Init(scene, hullBody_, IsEnabledEffective());
199 VariantVector& value = loadedWheelData_;
200 int numObjects = value[index++].GetInt();
201 int wheelIndex = 0;
202 origRotation_.Clear();
203 skidInfoCumulative_.Clear();
204 wheelSideSlipSpeed_.Clear();
205
206 for (int i = 0; i < numObjects; i++)
207 {
208 int node_id = value[index++].GetInt();
209 Vector3 direction = value[index++].GetVector3();
210 Vector3 axle = value[index++].GetVector3();
211 float restLength = value[index++].GetFloat();
212 float radius = value[index++].GetFloat();
213 bool isFrontWheel = value[index++].GetBool();
214 float steering = value[index++].GetFloat();
215 Vector3 connectionPoint = value[index++].GetVector3();
216 Quaternion origRotation = value[index++].GetQuaternion();
217 float skidInfoC = value[index++].GetFloat();
218 float sideSlipSpeed = value[index++].GetFloat();
219
220 bool isContact = value[index++].GetBool();
221 Vector3 contactPosition = value[index++].GetVector3();
222 Vector3 contactNormal = value[index++].GetVector3();
223 float suspensionStiffness = value[index++].GetFloat();
224 float dampingRelaxation = value[index++].GetFloat();
225 float dampingCompression = value[index++].GetFloat();
226 float frictionSlip = value[index++].GetFloat();
227 float rollInfluence = value[index++].GetFloat();
228 float engineForce = value[index++].GetFloat();
229 float brake = value[index++].GetFloat();
230 float skidInfo = value[index++].GetFloat();
231 Node* wheelNode = GetScene()->GetNode(node_id);
232 if (!wheelNode)
233 {
234 URHO3D_LOGERROR("RaycastVehicle: Incorrect node id = " + String(node_id) + " index: " + String(index));
235 continue;
236 }
237 btRaycastVehicle* vehicle = vehicleData_->Get();
238 int id = GetNumWheels();
239 btVector3 connectionPointCS0(connectionPoint.x_, connectionPoint.y_, connectionPoint.z_);
240 btVector3 wheelDirectionCS0(direction.x_, direction.y_, direction.z_);
241 btVector3 wheelAxleCS(axle.x_, axle.y_, axle.z_);
242 btWheelInfo& wheel = vehicle->addWheel(connectionPointCS0,
243 wheelDirectionCS0,
244 wheelAxleCS,
245 restLength,
246 radius,
247 vehicleData_->tuning_,
248 isFrontWheel);
249 wheelNodes_.Push(wheelNode);
250 origRotation_.Push(origRotation);
251 skidInfoCumulative_.Push(skidInfoC);
252 wheelSideSlipSpeed_.Push(sideSlipSpeed);
253 SetSteeringValue(wheelIndex, steering);
254 wheel.m_raycastInfo.m_isInContact = isContact;
255 wheel.m_raycastInfo.m_contactNormalWS = btVector3(contactNormal.x_, contactNormal.y_, contactNormal.z_);
256 wheel.m_raycastInfo.m_contactPointWS = btVector3(contactPosition.x_, contactPosition.y_, contactPosition.z_);
257 wheel.m_suspensionStiffness = suspensionStiffness;
258 wheel.m_wheelsDampingRelaxation = dampingRelaxation;
259 wheel.m_wheelsDampingCompression = dampingCompression;
260 wheel.m_frictionSlip = frictionSlip;
261 wheel.m_rollInfluence = rollInfluence;
262 wheel.m_engineForce = engineForce;
263 wheel.m_brake = brake;
264 wheel.m_skidInfo = skidInfo;
265 wheelIndex++;
266 }
267 URHO3D_LOGDEBUG("maxSideSlipSpeed_ value: " + String(maxSideSlipSpeed_));
268 URHO3D_LOGDEBUG("loaded items: " + String(index));
269 URHO3D_LOGDEBUG("loaded wheels: " + String(GetNumWheels()));
270 }
271
Init()272 void RaycastVehicle::Init()
273 {
274 hullBody_ = node_->GetOrCreateComponent<RigidBody>();
275 Scene* scene = GetScene();
276 vehicleData_->Init(scene, hullBody_, IsEnabledEffective());
277 }
278
FixedUpdate(float timeStep)279 void RaycastVehicle::FixedUpdate(float timeStep)
280 {
281 btRaycastVehicle* vehicle = vehicleData_->Get();
282 for (int i = 0; i < GetNumWheels(); i++)
283 {
284 btWheelInfo whInfo = vehicle->getWheelInfo(i);
285 if (whInfo.m_engineForce != 0.0f || whInfo.m_steering != 0.0f)
286 {
287 hullBody_->Activate();
288 break;
289 }
290 }
291 }
292
PostUpdate(float timeStep)293 void RaycastVehicle::PostUpdate(float timeStep)
294 {
295 btRaycastVehicle* vehicle = vehicleData_->Get();
296 for (int i = 0; i < GetNumWheels(); i++)
297 {
298 vehicle->updateWheelTransform(i, true);
299 btTransform transform = vehicle->getWheelTransformWS(i);
300 Vector3 origin = ToVector3(transform.getOrigin());
301 Quaternion qRot = ToQuaternion(transform.getRotation());
302 Node* pWheel = wheelNodes_[i];
303 pWheel->SetWorldPosition(origin);
304 pWheel->SetWorldRotation(qRot * origRotation_[i]);
305 }
306 }
307
FixedPostUpdate(float timeStep)308 void RaycastVehicle::FixedPostUpdate(float timeStep)
309 {
310 btRaycastVehicle* vehicle = vehicleData_->Get();
311 Vector3 velocity = hullBody_->GetLinearVelocity();
312 for (int i = 0; i < GetNumWheels(); i++)
313 {
314 btWheelInfo& whInfo = vehicle->getWheelInfo(i);
315 if (!WheelIsGrounded(i) && GetEngineForce(i) != 0.0f)
316 {
317 float delta;
318 if (inAirRPM_ != 0.0f)
319 {
320 delta = inAirRPM_ * timeStep / 60.0f;
321 }
322 else
323 {
324 delta = 8.0f * GetEngineForce(i) * timeStep / (hullBody_->GetMass() * GetWheelRadius(i));
325 }
326 if (Abs(whInfo.m_deltaRotation) < Abs(delta))
327 {
328 whInfo.m_rotation += delta - whInfo.m_deltaRotation;
329 whInfo.m_deltaRotation = delta;
330 }
331 if (skidInfoCumulative_[i] > 0.05f)
332 {
333 skidInfoCumulative_[i] -= 0.002;
334 }
335 }
336 else
337 {
338 skidInfoCumulative_[i] = GetWheelSkidInfo(i);
339 }
340 wheelSideSlipSpeed_[i] = Abs(ToVector3(whInfo.m_raycastInfo.m_wheelAxleWS).DotProduct(velocity));
341 if (wheelSideSlipSpeed_[i] > maxSideSlipSpeed_)
342 {
343 skidInfoCumulative_[i] = Clamp(skidInfoCumulative_[i], 0.0f, 0.89f);
344 }
345 }
346 }
347
SetMaxSideSlipSpeed(float speed)348 void RaycastVehicle::SetMaxSideSlipSpeed(float speed)
349 {
350 maxSideSlipSpeed_ = speed;
351 }
352
GetMaxSideSlipSpeed() const353 float RaycastVehicle::GetMaxSideSlipSpeed() const
354 {
355 return maxSideSlipSpeed_;
356 }
357
SetWheelSkidInfoCumulative(int wheel,float skid)358 void RaycastVehicle::SetWheelSkidInfoCumulative(int wheel, float skid)
359 {
360 skidInfoCumulative_[wheel] = skid;
361 }
362
GetWheelSkidInfoCumulative(int wheel) const363 float RaycastVehicle::GetWheelSkidInfoCumulative(int wheel) const
364 {
365 return skidInfoCumulative_[wheel];
366 }
367
AddWheel(Node * wheelNode,Vector3 wheelDirection,Vector3 wheelAxle,float restLength,float wheelRadius,bool frontWheel)368 void RaycastVehicle::AddWheel(Node* wheelNode,
369 Vector3 wheelDirection, Vector3 wheelAxle,
370 float restLength, float wheelRadius,
371 bool frontWheel)
372 {
373 btRaycastVehicle* vehicle = vehicleData_->Get();
374 int id = GetNumWheels();
375 Vector3 connectionPoint = wheelNode->GetWorldPosition() - node_->GetWorldPosition();
376 btVector3 connectionPointCS0(connectionPoint.x_, connectionPoint.y_, connectionPoint.z_);
377 btVector3 wheelDirectionCS0(wheelDirection.x_, wheelDirection.y_, wheelDirection.z_);
378 btVector3 wheelAxleCS(wheelAxle.x_, wheelAxle.y_, wheelAxle.z_);
379 btWheelInfo& wheel = vehicle->addWheel(connectionPointCS0,
380 wheelDirectionCS0,
381 wheelAxleCS,
382 restLength,
383 wheelRadius,
384 vehicleData_->tuning_,
385 frontWheel);
386
387 wheelNodes_.Push(wheelNode);
388 origRotation_.Push(wheelNode->GetWorldRotation());
389 skidInfoCumulative_.Push(1.0f);
390 wheelSideSlipSpeed_.Push(0.0f);
391 wheel.m_raycastInfo.m_isInContact = false;
392 }
393
ResetSuspension()394 void RaycastVehicle::ResetSuspension()
395 {
396 btRaycastVehicle* vehicle = vehicleData_->Get();
397 vehicle->resetSuspension();
398 }
399
UpdateWheelTransform(int wheel,bool interpolated)400 void RaycastVehicle::UpdateWheelTransform(int wheel, bool interpolated)
401 {
402 btRaycastVehicle* vehicle = vehicleData_->Get();
403 vehicle->updateWheelTransform(wheel, interpolated);
404 }
405
GetWheelPosition(int wheel)406 Vector3 RaycastVehicle::GetWheelPosition(int wheel)
407 {
408 btRaycastVehicle* vehicle = vehicleData_->Get();
409 btTransform transform = vehicle->getWheelTransformWS(wheel);
410 Vector3 origin = ToVector3(transform.getOrigin());
411 return origin;
412 }
413
GetWheelRotation(int wheel)414 Quaternion RaycastVehicle::GetWheelRotation(int wheel)
415 {
416 btRaycastVehicle* vehicle = vehicleData_->Get();
417 btTransform transform = vehicle->getWheelTransformWS(wheel);
418 Quaternion rotation = ToQuaternion(transform.getRotation());
419 return rotation;
420 }
421
GetWheelConnectionPoint(int wheel) const422 Vector3 RaycastVehicle::GetWheelConnectionPoint(int wheel) const
423 {
424 btRaycastVehicle* vehicle = vehicleData_->Get();
425 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
426 return ToVector3(whInfo.m_chassisConnectionPointCS);
427 }
428
SetSteeringValue(int wheel,float steeringValue)429 void RaycastVehicle::SetSteeringValue(int wheel, float steeringValue)
430 {
431 btRaycastVehicle* vehicle = vehicleData_->Get();
432 vehicle->setSteeringValue(steeringValue, wheel);
433 }
434
GetSteeringValue(int wheel) const435 float RaycastVehicle::GetSteeringValue(int wheel) const
436 {
437 btRaycastVehicle* vehicle = vehicleData_->Get();
438 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
439 return whInfo.m_steering;
440 }
441
SetWheelSuspensionStiffness(int wheel,float stiffness)442 void RaycastVehicle::SetWheelSuspensionStiffness(int wheel, float stiffness)
443 {
444 btRaycastVehicle* vehicle = vehicleData_->Get();
445 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
446 whInfo.m_suspensionStiffness = stiffness;
447 }
448
GetWheelSuspensionStiffness(int wheel) const449 float RaycastVehicle::GetWheelSuspensionStiffness(int wheel) const
450 {
451 btRaycastVehicle* vehicle = vehicleData_->Get();
452 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
453 return whInfo.m_suspensionStiffness;
454 }
455
SetWheelDampingRelaxation(int wheel,float damping)456 void RaycastVehicle::SetWheelDampingRelaxation(int wheel, float damping)
457 {
458 btRaycastVehicle* vehicle = vehicleData_->Get();
459 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
460 whInfo.m_wheelsDampingRelaxation = damping;
461 }
462
GetWheelDampingRelaxation(int wheel) const463 float RaycastVehicle::GetWheelDampingRelaxation(int wheel) const
464 {
465 btRaycastVehicle* vehicle = vehicleData_->Get();
466 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
467 return whInfo.m_wheelsDampingRelaxation;
468 }
469
SetWheelDampingCompression(int wheel,float compression)470 void RaycastVehicle::SetWheelDampingCompression(int wheel, float compression)
471 {
472 btRaycastVehicle* vehicle = vehicleData_->Get();
473 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
474 whInfo.m_wheelsDampingCompression = compression;
475 }
476
GetWheelDampingCompression(int wheel) const477 float RaycastVehicle::GetWheelDampingCompression(int wheel) const
478 {
479 btRaycastVehicle* vehicle = vehicleData_->Get();
480 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
481 return whInfo.m_wheelsDampingCompression;
482 }
483
SetWheelFrictionSlip(int wheel,float slip)484 void RaycastVehicle::SetWheelFrictionSlip(int wheel, float slip)
485 {
486 btRaycastVehicle* vehicle = vehicleData_->Get();
487 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
488 whInfo.m_frictionSlip = slip;
489 }
490
GetWheelFrictionSlip(int wheel) const491 float RaycastVehicle::GetWheelFrictionSlip(int wheel) const
492 {
493 btRaycastVehicle* vehicle = vehicleData_->Get();
494 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
495 return whInfo.m_frictionSlip;
496 }
497
SetWheelRollInfluence(int wheel,float rollInfluence)498 void RaycastVehicle::SetWheelRollInfluence(int wheel, float rollInfluence)
499 {
500 btRaycastVehicle* vehicle = vehicleData_->Get();
501 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
502 whInfo.m_rollInfluence = rollInfluence;
503 }
504
GetContactPosition(int wheel) const505 Vector3 RaycastVehicle::GetContactPosition(int wheel) const
506 {
507 btRaycastVehicle* vehicle = vehicleData_->Get();
508 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
509 return ToVector3(whInfo.m_raycastInfo.m_contactPointWS);
510 }
511
GetContactNormal(int wheel) const512 Vector3 RaycastVehicle::GetContactNormal(int wheel) const
513 {
514 btRaycastVehicle* vehicle = vehicleData_->Get();
515 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
516 return ToVector3(whInfo.m_raycastInfo.m_contactNormalWS);
517 }
518
GetWheelSideSlipSpeed(int wheel) const519 float RaycastVehicle::GetWheelSideSlipSpeed(int wheel) const
520 {
521 return wheelSideSlipSpeed_[wheel];
522 }
523
GetWheelRollInfluence(int wheel) const524 float RaycastVehicle::GetWheelRollInfluence(int wheel) const
525 {
526 btRaycastVehicle* vehicle = vehicleData_->Get();
527 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
528 return whInfo.m_rollInfluence;
529 }
530
SetWheelRadius(int wheel,float wheelRadius)531 void RaycastVehicle::SetWheelRadius(int wheel, float wheelRadius)
532 {
533 btRaycastVehicle* vehicle = vehicleData_->Get();
534 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
535 whInfo.m_wheelsRadius = wheelRadius;
536 }
537
GetWheelRadius(int wheel) const538 float RaycastVehicle::GetWheelRadius(int wheel) const
539 {
540 btRaycastVehicle* vehicle = vehicleData_->Get();
541 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
542 return whInfo.m_wheelsRadius;
543 }
544
SetEngineForce(int wheel,float force)545 void RaycastVehicle::SetEngineForce(int wheel, float force)
546 {
547 btRaycastVehicle* vehicle = vehicleData_->Get();
548 vehicle->applyEngineForce(force, wheel);
549 }
550
GetEngineForce(int wheel) const551 float RaycastVehicle::GetEngineForce(int wheel) const
552 {
553 btRaycastVehicle* vehicle = vehicleData_->Get();
554 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
555 return whInfo.m_engineForce;
556 }
557
SetBrake(int wheel,float force)558 void RaycastVehicle::SetBrake(int wheel, float force)
559 {
560 btRaycastVehicle* vehicle = vehicleData_->Get();
561 vehicle->setBrake(force, wheel);
562 }
563
GetBrake(int wheel) const564 float RaycastVehicle::GetBrake(int wheel) const
565 {
566 btRaycastVehicle* vehicle = vehicleData_->Get();
567 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
568 return whInfo.m_brake;
569 }
570
GetNumWheels() const571 int RaycastVehicle::GetNumWheels() const
572 {
573 btRaycastVehicle* vehicle = vehicleData_->Get();
574 return vehicle->getNumWheels();
575 }
576
GetWheelNode(int wheel) const577 Node* RaycastVehicle::GetWheelNode(int wheel) const
578 {
579 return wheelNodes_[wheel];
580 }
581
SetMaxSuspensionTravel(int wheel,float maxSuspensionTravel)582 void RaycastVehicle::SetMaxSuspensionTravel(int wheel, float maxSuspensionTravel)
583 {
584 btRaycastVehicle* vehicle = vehicleData_->Get();
585 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
586 whInfo.m_maxSuspensionTravelCm = maxSuspensionTravel;
587 }
588
GetMaxSuspensionTravel(int wheel)589 float RaycastVehicle::GetMaxSuspensionTravel(int wheel)
590 {
591 btRaycastVehicle* vehicle = vehicleData_->Get();
592 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
593 return whInfo.m_maxSuspensionTravelCm;
594 }
595
SetWheelDirection(int wheel,Vector3 direction)596 void RaycastVehicle::SetWheelDirection(int wheel, Vector3 direction)
597 {
598 btVector3 dir(direction.x_, direction.y_, direction.z_);
599 btRaycastVehicle* vehicle = vehicleData_->Get();
600 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
601 whInfo.m_wheelDirectionCS = dir;
602 }
603
GetWheelDirection(int wheel) const604 Vector3 RaycastVehicle::GetWheelDirection(int wheel) const
605 {
606 btRaycastVehicle* vehicle = vehicleData_->Get();
607 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
608 return ToVector3(whInfo.m_wheelDirectionCS);
609 }
610
SetWheelAxle(int wheel,Vector3 axle)611 void RaycastVehicle::SetWheelAxle(int wheel, Vector3 axle)
612 {
613 btVector3 ax(axle.x_, axle.y_, axle.z_);
614 btRaycastVehicle* vehicle = vehicleData_->Get();
615 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
616 whInfo.m_wheelAxleCS = ax;
617 }
618
GetWheelAxle(int wheel) const619 Vector3 RaycastVehicle::GetWheelAxle(int wheel) const
620 {
621 btRaycastVehicle* vehicle = vehicleData_->Get();
622 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
623 return ToVector3(whInfo.m_wheelAxleCS);
624 }
625
SetWheelRestLength(int wheel,float length)626 void RaycastVehicle::SetWheelRestLength(int wheel, float length)
627 {
628 btRaycastVehicle* vehicle = vehicleData_->Get();
629 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
630 whInfo.m_suspensionRestLength1 = length;
631 }
632
GetWheelRestLength(int wheel) const633 float RaycastVehicle::GetWheelRestLength(int wheel) const
634 {
635 btRaycastVehicle* vehicle = vehicleData_->Get();
636 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
637 return whInfo.m_suspensionRestLength1;
638 }
639
SetWheelSkidInfo(int wheel,float factor)640 void RaycastVehicle::SetWheelSkidInfo(int wheel, float factor)
641 {
642 btRaycastVehicle* vehicle = vehicleData_->Get();
643 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
644 whInfo.m_skidInfo = factor;
645 }
646
GetWheelSkidInfo(int wheel) const647 float RaycastVehicle::GetWheelSkidInfo(int wheel) const
648 {
649 btRaycastVehicle* vehicle = vehicleData_->Get();
650 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
651 return whInfo.m_skidInfo;
652 }
653
IsFrontWheel(int wheel) const654 bool RaycastVehicle::IsFrontWheel(int wheel) const
655 {
656 btRaycastVehicle* vehicle = vehicleData_->Get();
657 btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
658 return whInfo.m_bIsFrontWheel;
659 }
660
WheelIsGrounded(int wheel) const661 bool RaycastVehicle::WheelIsGrounded(int wheel) const
662 {
663 btRaycastVehicle* vehicle = vehicleData_->Get();
664 btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
665 return whInfo.m_raycastInfo.m_isInContact;
666 }
667
SetInAirRPM(float rpm)668 void RaycastVehicle::SetInAirRPM(float rpm)
669 {
670 inAirRPM_ = rpm;
671 }
672
GetInAirRPM() const673 float RaycastVehicle::GetInAirRPM() const
674 {
675 return inAirRPM_;
676 }
677
ResetWheels()678 void RaycastVehicle::ResetWheels()
679 {
680 ResetSuspension();
681 for (int i = 0; i < GetNumWheels(); i++)
682 {
683 UpdateWheelTransform(i, true);
684 Vector3 origin = GetWheelPosition(i);
685 Node* wheelNode = GetWheelNode(i);
686 wheelNode->SetWorldPosition(origin);
687 }
688 }
689
GetWheelDataAttr() const690 VariantVector RaycastVehicle::GetWheelDataAttr() const
691 {
692 VariantVector ret;
693 ret.Reserve(GetNumWheels() * 22 + 1);
694 ret.Push(GetNumWheels());
695 for (int i = 0; i < GetNumWheels(); i++)
696 {
697 Node* wNode = GetWheelNode(i);
698 int node_id = wNode->GetID();
699 URHO3D_LOGDEBUG("RaycastVehicle: Saving node id = " + String(node_id));
700 ret.Push(node_id);
701 ret.Push(GetWheelDirection(i));
702 ret.Push(GetWheelAxle(i));
703 ret.Push(GetWheelRestLength(i));
704 ret.Push(GetWheelRadius(i));
705 ret.Push(IsFrontWheel(i));
706 ret.Push(GetSteeringValue(i));
707 ret.Push(GetWheelConnectionPoint(i));
708 ret.Push(origRotation_[i]);
709 ret.Push(GetWheelSkidInfoCumulative(i));
710 ret.Push(GetWheelSideSlipSpeed(i));
711 ret.Push(WheelIsGrounded(i));
712 ret.Push(GetContactPosition(i));
713 ret.Push(GetContactNormal(i)); // 14
714 ret.Push(GetWheelSuspensionStiffness(i));
715 ret.Push(GetWheelDampingRelaxation(i));
716 ret.Push(GetWheelDampingCompression(i));
717 ret.Push(GetWheelFrictionSlip(i));
718 ret.Push(GetWheelRollInfluence(i));
719 ret.Push(GetEngineForce(i));
720 ret.Push(GetBrake(i));
721 ret.Push(GetWheelSkidInfo(i));
722 }
723 URHO3D_LOGDEBUG("RaycastVehicle: saved items: " + String(ret.Size()));
724 URHO3D_LOGDEBUG("maxSideSlipSpeed_ value save: " + String(maxSideSlipSpeed_));
725 return ret;
726 }
727
SetWheelDataAttr(const VariantVector & value)728 void RaycastVehicle::SetWheelDataAttr(const VariantVector& value)
729 {
730 if (!vehicleData_)
731 {
732 URHO3D_LOGERROR("RaycastVehicle: vehicleData doesn't exist");
733 return;
734 }
735 if (value.Size() < 2)
736 {
737 URHO3D_LOGERROR("RaycastVehicle: Incorrect vehicleData");
738 return;
739 }
740
741 loadedWheelData_ = value;
742 }
743
744 } // namespace Urho3D
745