Vehicle.cpp 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. ASSERT(WHEEL_LEFT_FRONT==0 && WHEEL_RIGHT_FRONT==1 && WHEEL_LEFT_REAR==2 && WHEEL_RIGHT_REAR==3); // used by 'IsFront', 'IsRear', 'IsLeft', 'IsRight'
  6. /******************************************************************************/
  7. // VEHICLE
  8. /******************************************************************************/
  9. static Int CompareVehicle(Vehicle*C &a, Vehicle*C &b) {return Compare(Ptr(a), Ptr(b));}
  10. Vehicle::Vehicle() {zero();}
  11. void Vehicle::zero()
  12. {
  13. _accel=_brake=_angle=_max_accel=_max_back_accel=_max_brake=_brake_ratio=_max_angle=_fric_linear=_fric_scalar=_susp_spring=_susp_damping=_susp_compress=_scale=0;
  14. _wd=AWD;
  15. REPA(_wheel)
  16. {
  17. _Wheel &w=_wheel[i];
  18. w.pos.zero();
  19. w.contact.pos.zero();
  20. w.contact.normal.zero();
  21. w.radius=w.compress=w.angle=w.angle_vel=0;
  22. }
  23. }
  24. Vehicle& Vehicle::del()
  25. {
  26. if(is())
  27. {
  28. SafeWriteLock lock(Physics._rws);
  29. Physics._vehicles.binaryExclude(this, CompareVehicle);
  30. _actor.del();
  31. zero();
  32. }
  33. return T;
  34. }
  35. Vehicle& Vehicle::create(C PhysBody &body, C Params &params, Flt density, Flt scale)
  36. {
  37. if(!createTry(body, params, density, scale))Exit("Can't create Vehicle");
  38. return T;
  39. }
  40. Bool Vehicle::createTry(C PhysBody &body, C Params &params, Flt density, Flt scale)
  41. {
  42. WriteLock lock(Physics._rws);
  43. del();
  44. if(_actor.createTry(body, density, scale))
  45. {
  46. _max_accel=10; _max_back_accel=4.5f; _max_brake=12; _brake_ratio=0.43f; _max_angle=PI_3; _fric_linear=13; _fric_scalar=0.3f; _susp_spring=20; _susp_damping=0.7f; _susp_compress=0.75f; _scale=scale;
  47. _wd=AWD;
  48. Flt wheels_density =body.finalDensity()*density*0.5f, // assume that wheel density is half of the chassis density
  49. wheels_mass =0;
  50. Vec wheels_mass_center=0,
  51. wheels_center =0;
  52. REPA(_wheel)
  53. {
  54. _Wheel &dest= _wheel[i];
  55. C Wheel &src =params.wheel[i];
  56. dest.pos =src.pos *scale;
  57. dest.radius=src.radius*scale;
  58. dest.contact.normal.set(0, 1, 0);
  59. Flt wheel_volume=Tube(dest.radius, src.width*scale).volume(),
  60. wheel_mass =wheels_density*wheel_volume;
  61. wheels_center += dest.pos;
  62. wheels_mass_center+=wheel_mass*dest.pos;
  63. wheels_mass +=wheel_mass;
  64. }
  65. // adjust mass center by wheels
  66. if(Flt total_mass=mass()+wheels_mass)
  67. {
  68. massCenterL((massCenterL()*mass() + wheels_mass_center)/total_mass); // 'wheels_mass_center' is already multiplied by 'wheels_mass'
  69. mass(total_mass);
  70. }
  71. wheels_center/=WHEEL_NUM; _avg_wheel_dist=0; REPA(_wheel)_avg_wheel_dist+=Dist(_wheel[i].pos, wheels_center); _avg_wheel_dist/=WHEEL_NUM; _avg_wheel_dist*=SQRT2_2; // mul by SQRT2_2 because it's applied to both X and Z
  72. // once the vehicle is ready, add it to the global container
  73. Physics._vehicles.binaryInclude(this, CompareVehicle);
  74. return true;
  75. }
  76. return false;
  77. }
  78. Bool Vehicle::is()C {return _actor.is();}
  79. Int Vehicle::onGroundNum( )C {Int n=0; REPA(_wheel)if(_wheel[i].compress> 0)n++ ; return n ;}
  80. Bool Vehicle::onGroundAny( )C { REPA(_wheel)if(_wheel[i].compress> 0)return true ; return false;}
  81. Bool Vehicle::onGroundAll( )C { REPA(_wheel)if(_wheel[i].compress<=0)return false; return true ;}
  82. Bool Vehicle::onGround (WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? _wheel[wheel].compress>0 : false;}
  83. Flt Vehicle:: speed()C {return Dot(_actor.vel(), _actor.orn().z);}
  84. Flt Vehicle::sideSpeed()C {return Dot(_actor.vel(), _actor.orn().x);}
  85. Vec Vehicle::wheelAxis(WHEEL_TYPE wheel)C
  86. {
  87. Vec axis;
  88. if(IsFront(wheel))
  89. {
  90. Flt c, s; CosSin(c, s, _angle*_max_angle); axis.set(c, 0, -s)*=_actor.orn(); // setRotateY(angle).x
  91. }else axis=_actor.orn().x;
  92. // this should not change the direction for left wheels, 'wheelAxis' should always point to right direction
  93. return axis;
  94. }
  95. Vec Vehicle::wheelDir(WHEEL_TYPE wheel)C
  96. {
  97. Vec dir;
  98. if(IsFront(wheel))
  99. {
  100. Flt c, s; CosSin(c, s, _angle*_max_angle); dir.set(s, 0, c)*=_actor.orn(); // setRotateY(angle).z
  101. }else dir=_actor.orn().z;
  102. return dir;
  103. }
  104. Matrix Vehicle::wheelMatrix(WHEEL_TYPE wheel, Int flip_side)C
  105. {
  106. if(InRange(wheel, _wheel))
  107. {
  108. C _Wheel &w=_wheel[wheel];
  109. Matrix m;
  110. if(IsFront(wheel))m.orn().setRotateXY(w.angle, _angle*_max_angle);else m.orn().setRotateX(w.angle);
  111. m.pos=w.pos;
  112. m.pos.y+=w.compress*w.radius*_susp_compress;
  113. m*=_actor.matrix();
  114. if(flip_side && (flip_side>0)==IsRight(wheel))
  115. {
  116. m.x.chs();
  117. m.z.chs();
  118. }
  119. return m;
  120. }
  121. return MatrixIdentity;
  122. }
  123. Vec Vehicle::wheelVel (WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? _actor.pointVelL(_wheel[wheel].pos) : 0;}
  124. Vec Vehicle::wheelAngVel(WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? wheelAxis(wheel)*_wheel[wheel].angle_vel : 0;}
  125. Vec Vehicle::wheelContact (WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? _wheel[wheel].contact.pos : 0;}
  126. Vec Vehicle::wheelContactN(WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? _wheel[wheel].contact.normal : 0;}
  127. Flt Vehicle::wheelRadius (WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? _wheel[wheel].radius : 0;}
  128. Flt Vehicle::wheelCompress(WHEEL_TYPE wheel)C {return InRange(wheel, _wheel) ? _wheel[wheel].compress : 0;}
  129. Flt Vehicle::wheelLongSlip(WHEEL_TYPE wheel)C
  130. {
  131. if(onGround(wheel) && InRange(wheel, _wheel))
  132. {
  133. C _Wheel &w=_wheel[wheel];
  134. Vec point_vel=_actor.pointVelW(w.contact.pos); // vehicle velocity at ground contact point
  135. // TODO: should wheel angular velocity be applied to 'point_vel' ?
  136. Vec wheel_dir =wheelDir(wheel);
  137. Flt long_speed=Dot(point_vel, wheel_dir);
  138. // TODO: should w.angle_vel be negative for IsLeft ?
  139. if(long_speed==0 && w.angle_vel==0)return 0;
  140. if(Abs(long_speed)>Abs(w.angle_vel*w.radius))return (w.angle_vel*w.radius - long_speed)/(Abs(long_speed)+0.1f);
  141. else return (w.angle_vel*w.radius - long_speed)/(Abs(w.angle_vel*w.radius)+1.0f);
  142. }
  143. return 0;
  144. }
  145. Flt Vehicle::wheelLatSlip(WHEEL_TYPE wheel)C
  146. {
  147. if(onGround(wheel) && InRange(wheel, _wheel))
  148. {
  149. // TODO: should wheel angular velocity be applied to 'point_vel' ?
  150. Vec point_vel =_actor.pointVelW(_wheel[wheel].contact.pos); // vehicle velocity at ground contact point
  151. Vec wheel_dir =wheelDir(wheel);
  152. if(Flt long_speed=Dot(point_vel, wheel_dir))
  153. {
  154. Vec wheel_axis =wheelAxis(wheel);
  155. Flt lat_speed=Dot(point_vel, wheel_axis);
  156. return Atan(lat_speed/Abs(long_speed));
  157. }
  158. }
  159. return 0;
  160. }
  161. Flt Vehicle:: accel()C {return _accel ;} Vehicle& Vehicle:: accel(Flt accel ) {T._accel =Mid(accel ,-1.0f, 1.0f); return T;}
  162. Flt Vehicle:: brake()C {return _brake ;} Vehicle& Vehicle:: brake(Flt brake ) {T._brake =Sat(brake ); return T;}
  163. Flt Vehicle:: angle()C {return _angle ;} Vehicle& Vehicle:: angle(Flt angle ) {T._angle =Mid(angle ,-1.0f, 1.0f); return T;}
  164. Flt Vehicle:: maxAccel()C {return _max_accel ;} Vehicle& Vehicle:: maxAccel(Flt accel ) {T._max_accel =Max(accel , 0.0f ); return T;}
  165. Flt Vehicle:: maxBackAccel()C {return _max_back_accel;} Vehicle& Vehicle:: maxBackAccel(Flt accel ) {T._max_back_accel=Max(accel , 0.0f ); return T;}
  166. Flt Vehicle:: maxBrake()C {return _max_brake ;} Vehicle& Vehicle:: maxBrake(Flt brake ) {T._max_brake =Max(brake , 0.0f ); return T;}
  167. Flt Vehicle:: brakeRatio()C {return _brake_ratio ;} Vehicle& Vehicle:: brakeRatio(Flt ratio ) {T._brake_ratio =Sat(ratio ); return T;}
  168. Flt Vehicle:: maxAngle()C {return _max_angle ;} Vehicle& Vehicle:: maxAngle(Flt angle ) {T._max_angle =Mid(angle , 0.0f, PI_2); return T;}
  169. Flt Vehicle::frictionLinear()C {return _fric_linear ;} Vehicle& Vehicle::frictionLinear(Flt friction) {T._fric_linear =Max(friction, 0.0f ); return T;}
  170. Flt Vehicle::frictionScalar()C {return _fric_scalar ;} Vehicle& Vehicle::frictionScalar(Flt friction) {T._fric_scalar =Sat(friction ); return T;}
  171. Flt Vehicle:: suspSpring ()C {return _susp_spring ;} Vehicle& Vehicle:: suspSpring (Flt spring ) {T._susp_spring =Max(spring , 0.0f ); return T;}
  172. Flt Vehicle:: suspDamping ()C {return _susp_damping ;} Vehicle& Vehicle:: suspDamping (Flt damping ) {T._susp_damping =Max(damping , 0.0f ); return T;}
  173. Flt Vehicle:: suspCompress()C {return _susp_compress ;} Vehicle& Vehicle:: suspCompress(Flt compress) {T._susp_compress =Sat(compress ); return T;}
  174. Vehicle::WHEEL_DRIVE Vehicle:: wheelDrive ()C {return _wd ;} Vehicle& Vehicle:: wheelDrive (WHEEL_DRIVE wd) {T._wd =wd ; return T;}
  175. Flt Vehicle::energy ( )C {return _actor.energy ( );}
  176. Flt Vehicle::damping ( )C {return _actor.damping ( );} Vehicle& Vehicle:: damping ( Flt damping) {_actor. damping (damping); return T;}
  177. Flt Vehicle::adamping ( )C {return _actor.adamping ( );} Vehicle& Vehicle::adamping ( Flt damping) {_actor.adamping (damping); return T;}
  178. Flt Vehicle::mass ( )C {return _actor.mass ( );} Vehicle& Vehicle::mass ( Flt mass ) {_actor.mass (mass ); return T;}
  179. Vec Vehicle::massCenterL( )C {return _actor.massCenterL( );} Vehicle& Vehicle::massCenterL(C Vec &center ) {_actor.massCenterL(center ); return T;}
  180. Vec Vehicle::massCenterW( )C {return _actor.massCenterW( );} Vehicle& Vehicle::massCenterW(C Vec &center ) {_actor.massCenterW(center ); return T;}
  181. Vec Vehicle::inertia ( )C {return _actor.inertia ( );} Vehicle& Vehicle::inertia (C Vec &inertia) {_actor.inertia (inertia); return T;}
  182. Vec Vehicle::pos ( )C {return _actor.pos ( );} Vehicle& Vehicle::pos (C Vec &pos ) {_actor.pos (pos ); return T;}
  183. Matrix3 Vehicle::orn ( )C {return _actor.orn ( );} Vehicle& Vehicle::orn (C Matrix3 &orn ) {_actor.orn (orn ); return T;}
  184. Matrix Vehicle::matrix ( )C {return _actor.matrix ( );} Vehicle& Vehicle::matrix (C Matrix &matrix ) {_actor.matrix (matrix ); return T;}
  185. Vec Vehicle:: vel ( )C {return _actor. vel ( );} Vehicle& Vehicle:: vel (C Vec &vel ) {_actor. vel (vel ); return T;}
  186. Vec Vehicle:: angVel ( )C {return _actor. angVel ( );} Vehicle& Vehicle::angVel (C Vec &vel ) {_actor.angVel (vel ); return T;}
  187. Vec Vehicle::pointVelL (C Vec &pos)C {return _actor.pointVelL (pos);}
  188. Vec Vehicle::pointVelW (C Vec &pos)C {return _actor.pointVelW (pos);}
  189. Box Vehicle::box ( )C {return _actor.box ( );}
  190. Vehicle& Vehicle::addTorque (C Vec &torque ) {_actor.addTorque (torque ); return T;}
  191. Vehicle& Vehicle::addAngVel (C Vec &ang_vel ) {_actor.addAngVel (ang_vel ); return T;}
  192. Vehicle& Vehicle::addForce (C Vec &force ) {_actor.addForce (force ); return T;}
  193. Vehicle& Vehicle::addForce (C Vec &force , C Vec &pos) {_actor.addForce (force , pos); return T;}
  194. Vehicle& Vehicle::addImpulse(C Vec &impulse ) {_actor.addImpulse(impulse ); return T;}
  195. Vehicle& Vehicle::addImpulse(C Vec &impulse, C Vec &pos) {_actor.addImpulse(impulse, pos); return T;}
  196. Vehicle& Vehicle::addVel (C Vec &vel ) {_actor.addVel (vel ); return T;}
  197. Vehicle& Vehicle::addAccel (C Vec &accel ) {_actor.addAccel (accel ); return T;}
  198. Bool Vehicle::collision ()C {return _actor.collision ();} Vehicle& Vehicle::collision (Bool on ) {_actor.collision (on ); return T;}
  199. Bool Vehicle::gravity ()C {return _actor.gravity ();} Vehicle& Vehicle::gravity (Bool on ) {_actor.gravity (on ); return T;}
  200. Bool Vehicle::ray ()C {return _actor.ray ();} Vehicle& Vehicle::ray (Bool on ) {_actor.ray (on ); return T;}
  201. Bool Vehicle::sleep ()C {return _actor.sleep ();} Vehicle& Vehicle::sleep (Bool sleep ) {_actor.sleep (sleep ); return T;}
  202. Flt Vehicle::sleepEnergy()C {return _actor.sleepEnergy();} Vehicle& Vehicle::sleepEnergy(Flt energy ) {_actor.sleepEnergy(energy ); return T;}
  203. Bool Vehicle::ccd ()C {return _actor.ccd ();} Vehicle& Vehicle::ccd (Bool on ) {_actor.ccd (on ); return T;}
  204. Ptr Vehicle::user ()C {return _actor.user ();} Vehicle& Vehicle::user (Ptr user ) {_actor.user (user ); return T;}
  205. Ptr Vehicle::obj ()C {return _actor.obj ();} Vehicle& Vehicle::obj (Ptr obj ) {_actor.obj (obj ); return T;}
  206. Byte Vehicle::group ()C {return _actor.group ();} Vehicle& Vehicle::group (Byte group ) {_actor.group (group ); return T;}
  207. Byte Vehicle::dominance ()C {return _actor.dominance ();} Vehicle& Vehicle::dominance (Byte dominance) {_actor.dominance (dominance); return T;}
  208. PhysMtrl* Vehicle::material ()C {return _actor.material ();} Vehicle& Vehicle::material (PhysMtrl *material ) {_actor.material (material ); return T;}
  209. static inline Bool HasAccel(WHEEL_TYPE wheel, Vehicle::WHEEL_DRIVE wd)
  210. {
  211. switch(wd)
  212. {
  213. default : return true; // AWD
  214. case Vehicle::FWD: return IsFront(wheel);
  215. case Vehicle::RWD: return IsRear (wheel);
  216. }
  217. }
  218. struct VehicleCallback : PhysHitCallback
  219. {
  220. Actor &actor;
  221. Bool has;
  222. Flt dist;
  223. Plane plane;
  224. Vec up;
  225. VehicleCallback(Vehicle &vehicle, C Vec &up) : actor(vehicle._actor), up(up) {}
  226. virtual Bool hit(PhysHit &phys_hit)
  227. {
  228. if(phys_hit.collision)
  229. if(!has || phys_hit.dist<dist)
  230. if(Dot(phys_hit.plane.normal, up)>=0.1f) // ignore accidental obstacles that got under ray (for example if where the wheel is, there is no physical body on the vehicle, then due to lack of collisions the wheel position and the ray can get inside other actors)
  231. if(!actor.ignored(phys_hit)){has=true; dist=phys_hit.dist; plane=phys_hit.plane;}
  232. return true;
  233. }
  234. };
  235. inline Vec PointVel(C Vec &vel, C Vec &ang_vel, C Vec &com_offset ) {return vel+Cross(ang_vel, com_offset);} // 'com_offset' must be in world space
  236. inline Vec PointVel(C Vec &vel, C Vec &ang_vel, C Vec &mass_center, C Vec &point) {return PointVel(vel, ang_vel, point-mass_center);}
  237. void Vehicle::update()
  238. {
  239. Vec wheel_pos[WHEEL_NUM];
  240. Matrix3 wheel_orn[WHEEL_NUM];
  241. Matrix actor_matrix =_actor.matrix();
  242. Vec actor_com =_actor.massCenterW();
  243. Flt actor_mass =_actor.mass();
  244. Flt accel =_accel; if(accel)accel*=((_accel>0) ? T._max_accel : T._max_back_accel)*((T._wd==AWD) ? 0.25f : 0.5f)*actor_mass; // do not remove actor.mass and change 'addForce' to 'addAccel' because add accel at pos does not include mass for torque but inertia, it was tested that car doing fast turns on flat surfaced sticked to ground better when using 'addForce' instead of 'addAccel' (the simulation was more enjoyable to play), with 'addAccel' the car was losing ground contact and controls/friction were lost and it appeared jittery
  245. Flt brake =_brake; if(brake)brake*=_max_brake*Physics.time()*0.5f; // by half because of 2 wheels per front/rear
  246. VehicleCallback hit_callback(T, actor_matrix.y);
  247. REPA(_wheel)
  248. {
  249. _Wheel &wheel =_wheel[i];
  250. wheel_pos[i]= wheel.pos*actor_matrix;
  251. Flt start=wheel.radius*0.5f, compress;
  252. hit_callback.has=false; Physics.ray(wheel_pos[i] + actor_matrix.y*start, actor_matrix.y*-(start+wheel.radius), hit_callback, Physics.collisionGroups(_actor.group()));
  253. if(hit_callback.has) // hit something
  254. {
  255. Flt dist=hit_callback.dist-start-wheel.radius;
  256. if( dist<0) // we're touching it
  257. {
  258. // wheel contact
  259. wheel.contact=hit_callback.plane;
  260. Flt wheel_susp=wheel.radius*_susp_compress;
  261. compress=-dist/wheel_susp;
  262. MIN(compress, 1);
  263. // wheel dir
  264. wheel_orn[i]=actor_matrix; if(IsFront(WHEEL_TYPE(i)))wheel_orn[i].rotateYL(_angle*_max_angle);
  265. // accelerate
  266. if(accel && HasAccel(WHEEL_TYPE(i), _wd))
  267. {
  268. Vec dir=PointOnPlane(wheel_orn[i].z, wheel.contact.normal); dir.setLength(accel);
  269. #if DEBUG
  270. //if(Kb.win())addForce(dir, wheel_pos[i]);else // don't use local pos to avoid generating torque here, rotation is handled below in the friction section
  271. #endif
  272. addForce(dir);
  273. }
  274. }else compress=0;
  275. }else compress=0;
  276. // suspension force
  277. Flt spring_force= compress *_susp_spring , // how far to bounce
  278. damper_force=(compress-wheel.compress)*_susp_damping/Physics.time(), // how quickly to stabilize
  279. force=(spring_force + damper_force)*actor_mass; // do not remove 'actor.mass' and replace 'addForce' with 'addAccel' for the same reasons as above
  280. addForce(force*wheel.contact.normal, wheel_pos[i]);
  281. wheel.compress=compress;
  282. }
  283. Vec actor_vel =_actor.vel (),
  284. actor_ang_vel =_actor.angVel();
  285. Flt speed =Dot(actor_vel, actor_matrix.z);
  286. Flt fric_lin_rot =Mid(actor_vel.length()*-0.125f+1.0f, -1.0f, 0.0f), // should be "Sat((actor_vel.length()-8)/8)" but we negate it to optimize "addVel(-left_vel*fric_lin_rot)" into "addVel(left_vel*fric_lin_rot)" (now is in 0 .. -1 range)
  287. fric_lin_rot1 =(1+fric_lin_rot); // for velocity 0 this should be 1, for high velocity this should be 0 (should be "1+fric_lin_rot" but we've negated 'fric_lin_rot')
  288. fric_lin_rot *=0.25f; // mul by 0.25 by each 4 wheel
  289. fric_lin_rot1*=0.25f; // mul by 0.25 by each 4 wheel
  290. Flt scalar_mul =1-_fric_scalar; if(scalar_mul>0)scalar_mul=Pow(scalar_mul, Physics.time()); // watch out for Pow(<=0, ..) which causes NaN
  291. Flt linear_add = _fric_linear*Physics.time();
  292. // friction
  293. REP(WHEEL_NUM)
  294. {
  295. _Wheel &wheel=_wheel[i];
  296. if(onGround(WHEEL_TYPE(i)))
  297. {
  298. wheel.angle_vel=speed/wheel.radius;
  299. // scalar friction multiplies current velocity
  300. // linear friction subtracts current velocity (this friction can cause never ending actor rotation if it's moving fast, therefore rotation is applied only for low velocities)
  301. Vec wheel_uni(IsRight(WHEEL_TYPE(i)) ? _avg_wheel_dist : -_avg_wheel_dist, 0, IsFront(WHEEL_TYPE(i)) ? _avg_wheel_dist : -_avg_wheel_dist); (wheel_uni*=actor_matrix.orn())+=actor_com; // set as uniform point along center of mass (reduces jittering)
  302. Vec point_vel=PointVel(actor_vel, actor_ang_vel, actor_com, wheel_uni);
  303. Vec lateral_vel=wheel_orn[i].x*DistPointPlane(point_vel, wheel_orn[i].x);
  304. Vec add_vel=lateral_vel*(scalar_mul-1); // use -1 because we need to first decrease the existing velocity ('addVel' is used below)
  305. Vec left_vel=lateral_vel* scalar_mul ; // this velocity is still left after scalar friction (it is in direction of the velocity)
  306. left_vel.clipLength(linear_add); // limit to allowed linear friction
  307. // apply 'left_vel' divided in two parts, one at low velocities to 'add_vel' so it generates angular velocity, second to 'addVel' without angular velocites
  308. addVel( left_vel*fric_lin_rot); // apply without angular velocities (the higher vehicle velocity then this has 1.0 blend), normally should be "addVel(-left_vel)" but we've negated 'fric_lin_rot'
  309. add_vel-=left_vel*fric_lin_rot1; // apply with angular velocities (the lower vehicle velocity then this has 1.0 blend)
  310. addImpulse(add_vel*actor_mass, wheel_uni); // apply, do not remove 'actor.mass' and replace 'addImpulse' with 'addVel' because of torque (mass<->inertia), this would work incorrect if vehicle is very big, and angular velocities would be applied too big because of big distance between point of applied force and center of mass
  311. }else
  312. {
  313. wheel.angle_vel*=Pow(0.9f, Physics.time());
  314. }
  315. wheel.angle+=wheel.angle_vel*Physics.time();
  316. }
  317. // braking
  318. if(brake)REP(WHEEL_NUM)if(onGround(WHEEL_TYPE(i)))
  319. {
  320. _Wheel &wheel =_wheel[i];
  321. Vec point_vel=PointVel(actor_vel, actor_ang_vel, actor_com, wheel_pos[i]);
  322. Vec ground_vel=PointOnPlane(point_vel, wheel.contact.normal);
  323. ground_vel.clipLength(brake*(IsFront(WHEEL_TYPE(i)) ? _brake_ratio : 1-_brake_ratio));
  324. addImpulse(-ground_vel*actor_mass, wheel_pos[i]); // do not remove 'actor.mass' and replace 'addImpulse' with 'addVel' because of torque (mass<->inertia), this would work incorrect if vehicle is very big, and angular velocities would be applied too big because of big distance between point of applied force and center of mass
  325. }
  326. }
  327. /******************************************************************************/
  328. Bool Vehicle::saveState(File &f)C
  329. {
  330. f.cmpUIntV(0); // version
  331. if(_actor.saveState(f))
  332. {
  333. f<<_wd<<_accel<<_brake<<_angle<<_max_accel<<_max_back_accel<<_max_brake<<_brake_ratio<<_max_angle<<_fric_linear<<_fric_scalar<<_susp_spring<<_susp_damping<<_susp_compress; // scale is not saved
  334. FREPA(_wheel)
  335. {
  336. C _Wheel &w=_wheel[i];
  337. f<<w.compress<<w.angle<<w.angle_vel<<w.contact; // pos and radius are not saved
  338. }
  339. return f.ok();
  340. }
  341. return false;
  342. }
  343. Bool Vehicle::loadState(File &f) // don't delete on fail, as here we're loading only state
  344. {
  345. switch(f.decUIntV()) // version
  346. {
  347. case 0: if(_actor.loadState(f))
  348. {
  349. f>>_wd>>_accel>>_brake>>_angle>>_max_accel>>_max_back_accel>>_max_brake>>_brake_ratio>>_max_angle>>_fric_linear>>_fric_scalar>>_susp_spring>>_susp_damping>>_susp_compress;
  350. FREPA(_wheel)
  351. {
  352. _Wheel &w=_wheel[i];
  353. f>>w.compress>>w.angle>>w.angle_vel>>w.contact;
  354. }
  355. if(f.ok())return true;
  356. }break;
  357. }
  358. return false;
  359. }
  360. /******************************************************************************/
  361. // PHYSX VEHICLE
  362. /******************************************************************************/
  363. #if SUPPORT_PHYSX_VEHICLE
  364. /******************************************************************************/
  365. struct PhysXVehicle // Physical actor of vehicle type (this class is available only in PhysX)
  366. {
  367. enum DIFF_TYPE
  368. {
  369. DIFF_LS_4WD , // limited slip differential for car with four wheel drive
  370. DIFF_LS_FWD , // limited slip differential for car with front wheel drive
  371. DIFF_LS_RWD , // limited slip differential for car with rear wheel drive
  372. DIFF_OPEN_4WD, // open differential for car with four wheel drive
  373. DIFF_OPEN_FWD, // open differential for car with front wheel drive
  374. DIFF_OPEN_RWD, // open differential for car with rear wheel drive
  375. };
  376. struct Wheel
  377. {
  378. Flt radius, // wheel radius, default=0.35 m
  379. width ; // wheel width , default=0.25 m
  380. Vec pos ; // wheel position in vehicle
  381. void set(Flt radius, Flt width, C Vec &pos) {T.radius=radius; T.width=width; T.pos=pos;}
  382. Wheel() {set(0.35f, 0.25f, VecZero);}
  383. };
  384. struct Params // all of these parameters (except masses) will be scaled according to 'scale' during vehicle creation
  385. {
  386. Flt mass , // vehicle mass, default=1500 kg
  387. wheel_mass ; // wheel mass, default= 20 kg
  388. Vec mass_center_offset; // offset to center of mass in vehicle actor, default=(0, -0.1, 0) (slightly below)
  389. Wheel wheel[WHEEL_NUM] ; // parameters for each wheel
  390. Params() {mass=1500; wheel_mass=20; mass_center_offset.set(0, -0.1f, 0);}
  391. };
  392. // manage
  393. PhysXVehicle& del (); // manually delete
  394. Bool createTry(C PhysBody &body, C Params &params, Flt scale=1); // create from 'body' physical body, 'params' parameters, and 'scale' scaling, false on fail
  395. PhysXVehicle& create (C PhysBody &body, C Params &params, Flt scale=1); // create from 'body' physical body, 'params' parameters, and 'scale' scaling, Exit on fail
  396. // get / set
  397. Bool is()C {return _vehicle!=null;} // if created
  398. Bool onGround()C; // if vehicle is on ground (at least one wheel on ground)
  399. Bool onGround(WHEEL_TYPE wheel)C; // if wheel is on ground
  400. #if EE_PRIVATE
  401. Vec wheelPosL (WHEEL_TYPE wheel)C; // get wheel position in actor local space
  402. #endif
  403. Matrix wheelMatrix (WHEEL_TYPE wheel)C; // get wheel matrix in world space
  404. Vec wheelVel (WHEEL_TYPE wheel)C; // get wheel velocity in world space
  405. Vec wheelAngVel (WHEEL_TYPE wheel)C; // get wheel angular velocity in world space
  406. Vec wheelContact (WHEEL_TYPE wheel)C; // get wheel contact point with the ground, Vec(0,0,0) if not on ground
  407. Flt wheelRadius (WHEEL_TYPE wheel)C; // get wheel radius
  408. Flt wheelCompress(WHEEL_TYPE wheel)C; // get wheel compression, value <0 means wheel is loose in air, value 0 means wheel is at rest, value 1 means wheel is fully compressed
  409. Flt wheelLongSlip(WHEEL_TYPE wheel)C; // get wheel longitudinal slip (how much does the wheel slip on ground in "forward" direction)
  410. Flt wheelLatSlip (WHEEL_TYPE wheel)C; // get wheel lateral slip (how much does the wheel slip on ground in "side " direction)
  411. Flt speed()C; // get vehicle forward speed (this value is positive when moving forward and negative when moving backwards)
  412. Flt sideSpeed()C; // get vehicle side speed (this value is positive when moving right and negative when moving left )
  413. Flt engineSpeed()C; // get engine rotation speed (in radians per second)
  414. Flt engineFrac ()C {return engineSpeed()/engineMaxSpeed();} // get engine rotation speed fraction (0..1) this can be useful information when changing gears manually (for example: for fraction < 0.5 you can gear down, for fraction > 0.65 you can gear up)
  415. Int gears()C; // get number of gears
  416. Int gear()C; PhysXVehicle& gear(Int gear ); // get/set current gear (-1=reverse, 0=neutral, 1..=normal gear)
  417. #if EE_PRIVATE
  418. Int targetGear()C; PhysXVehicle& targetGear(Int gear ); // set target gear
  419. #endif
  420. Bool autoGear()C; PhysXVehicle& autoGear(Bool on ); // get/set automatic gear changing , true/false, default=true
  421. Flt accel()C; PhysXVehicle& accel(Flt accel ); // get/set acceleration , 0..1
  422. Flt brake()C; PhysXVehicle& brake(Flt brake ); // get/set current brake , 0..1
  423. Flt handBrake()C; PhysXVehicle& handBrake(Flt brake ); // get/set current hand brake , 0..1
  424. Flt angle()C; PhysXVehicle& angle(Flt angle ); // get/set current steer angle , -1..1
  425. Flt maxBrake()C; PhysXVehicle& maxBrake(Flt brake ); // get/set max brake torque, 0..Inf , default=1500
  426. Flt maxHandBrake()C; PhysXVehicle& maxHandBrake(Flt brake ); // get/set max hand brake torque, 0..Inf , default=4000
  427. Flt maxAngle()C; PhysXVehicle& maxAngle(Flt angle ); // get/set max steer angle , 0..PI_2 , default=PI_3
  428. Flt wheelDamping()C; PhysXVehicle& wheelDamping(Flt damping ); // get/set wheel damping , 0..Inf , default=0.05
  429. Flt suspSpring ()C; PhysXVehicle& suspSpring (Flt spring ); // get/set suspension spring strength, 0..Inf , default=35000
  430. Flt suspDamping ()C; PhysXVehicle& suspDamping (Flt damping ); // get/set suspension spring damping , 0..Inf , default= 4500
  431. Flt suspCompress()C; PhysXVehicle& suspCompress(Flt compress); // get/set suspension max compression, 0..1 , default=0.75 (1.0 means full wheel radius)
  432. Flt suspElongate()C; PhysXVehicle& suspElongate(Flt elongate); // get/set suspension max elongation , 0..1 , default=0.25 (1.0 means full wheel radius)
  433. Flt enginePeakTorque()C; PhysXVehicle& enginePeakTorque(Flt peak ); // get/set engine peak torque , 0..Inf , default= 500, maximum acceleration applied to engine rotation
  434. Flt engineMaxSpeed ()C; PhysXVehicle& engineMaxSpeed (Flt omega ); // get/set engine max rotation spead , 0..Inf , default= 600 (in radians per second)
  435. DIFF_TYPE diffType()C; PhysXVehicle& diffType(DIFF_TYPE diff); // get/set differential type , DIFF_TYPE, default=DIFF_LS_4WD
  436. #if EE_PRIVATE
  437. Int tireType()C; PhysXVehicle& tireType(Int type ); // get/set tire type , 0..Inf , default=0 (this is a custom value not used internally by the engine, you can set it to anything you want and use it for custom friction calculations when using 'Physics.wheelFriction')
  438. #endif
  439. Flt tireLongStiff ()C; PhysXVehicle& tireLongStiff (Flt f ); // get/set longitudinal stiffness per unit longitudinal slip per unit gravity, specified in N per radian per unit gravitational acceleration. Longitudinal stiffness of the tire per unit longitudinal slip is calculated as "gravity*tireLongStiff", 0..Inf, default=1000
  440. Flt tireLatStiffX ()C; PhysXVehicle& tireLatStiffX (Flt f ); // get/set the minimum normalised load (load/restLoad) that gives a flat lateral stiffness response (Tire lateral stiffness is typically a graph of tire load that has linear behaviour near zero load and flattens at large loads) , 0..Inf, default=2
  441. Flt tireLatStiffY ()C; PhysXVehicle& tireLatStiffY (Flt f ); // get/set the maximum possible lateral stiffness divided by the rest tire load, specified in "per radian" (Tire lateral stiffness is typically a graph of tire load that has linear behaviour near zero load and flattens at large loads) , 0..Inf, default=17.9
  442. Flt tireCamberStiff()C; PhysXVehicle& tireCamberStiff(Flt f ); // get/set Camber stiffness, specified in kilograms per radian , 0..Inf, default=5.73
  443. // function of friction vs longitudinal slip with 3 points, these values define a function "wheelFriction=Func(wheelLongSlip)", like "y=f(x)" and you define control points of the "x" (slip) and "y" (friction)
  444. //Flt tireFuncPoint0Slip()C; PhysXVehicle& tireFuncPoint0Slip(Flt f); // get/set slip value at point 0, this value is always zero
  445. Flt tireFuncPoint0Fric()C; PhysXVehicle& tireFuncPoint0Fric(Flt f); // get/set friction value at point 0, 0..Inf, default=1
  446. Flt tireFuncPoint1Slip()C; PhysXVehicle& tireFuncPoint1Slip(Flt f); // get/set slip value at point 1, 0..Inf, default=0.1
  447. Flt tireFuncPoint1Fric()C; PhysXVehicle& tireFuncPoint1Fric(Flt f); // get/set friction value at point 1, 0..Inf, default=1
  448. Flt tireFuncPoint2Slip()C; PhysXVehicle& tireFuncPoint2Slip(Flt f); // get/set slip value at point 2, 0..Inf, default=1
  449. Flt tireFuncPoint2Fric()C; PhysXVehicle& tireFuncPoint2Fric(Flt f); // get/set friction value at point 2, 0..Inf, default=1
  450. PhysXVehicle& precision(Flt thresholdLongitudinalSpeed, UInt lowForwardSpeedSubStepCount, UInt highForwardSpeedSubStepCount); // Set the number of vehicle sub-steps that will be performed when the vehicle's longitudinal speed is below and above a threshold longitudinal speed. More sub-steps provides better stability but with greater computational cost. Typically, vehicles require more sub-steps at very low forward speeds. The threshold longitudinal speed has a default value of 5 metres per second. The sub-step count below the threshold longitudinal speed has a default of 3. The sub-step count above the threshold longitudinal speed has a default of 1. Each sub-step has time advancement equal to the time-step passed to 'Physics.startSimulation' divided by the number of required sub-steps. The contact planes of the most recent suspension line raycast are reused across all sub-steps. Each sub-step computes tire and suspension forces and then advances a velocity, angular velocity and transform. At the end of all sub-steps the vehicle actor is given the velocity and angular velocity that would move the actor from its start transform prior to the first sub-step to the transform computed at the end of the last substep, assuming it doesn't collide with anything along the way in the next PhysX SDK update. The global pose of the actor is left unchanged throughout the sub-steps. 'thresholdLongitudinalSpeed'=threshold speed that is used to categorize vehicle speed as low speed or high speed. 'lowForwardSpeedSubStepCount'=number of sub-steps performed in PxVehicleUpates for vehicles that have longitudinal speed lower than thresholdLongitudinalSpeed. 'highForwardSpeedSubStepCount'=number of sub-steps performed in PxVehicleUpdates for vehicles that have longitudinal speed graeter than thresholdLongitudinalSpeed.
  451. Flt energy ( )C; // get kinetic energy , 0..Inf
  452. Flt damping ( )C; PhysXVehicle& damping( Flt damping); // get/set linear damping, 0..Inf, default=0.05
  453. Flt adamping ( )C; PhysXVehicle& adamping( Flt damping); // get/set angular damping, 0..Inf, default=0.05
  454. Flt mass ( )C; // get mass , 0..Inf
  455. Vec massCenterL( )C; // get mass center in actor local space
  456. Vec massCenterW( )C; // get mass center in world space
  457. Vec inertia ( )C; PhysXVehicle& inertia (C Vec &inertia); // get/set inertia tensor
  458. Vec pos ( )C; PhysXVehicle& pos (C Vec &pos ); // get/set position
  459. Matrix3 orn ( )C; PhysXVehicle& orn (C Matrix3 &orn ); // get/set orientation, 'orn' must be normalized
  460. Matrix matrix ( )C; PhysXVehicle& matrix (C Matrix &matrix ); // get/set matrix , 'matrix' must be normalized
  461. Vec vel ( )C; PhysXVehicle& vel (C Vec &vel ); // get/set velocity
  462. Vec angVel ( )C; PhysXVehicle& angVel (C Vec &vel ); // get/set angular velocity
  463. Vec pointVelL (C Vec &pos)C; // get point velocity ('pos' is in actor local space)
  464. Vec pointVelW (C Vec &pos)C; // get point velocity ('pos' is in world space)
  465. Box box ( )C; // get bounding box in world space
  466. Flt scale ( )C {return _scale;} // get scale that was used during vehicle creation
  467. PhysXVehicle& addTorque (C Vec &torque ); // add torque , unit = mass * rotation / time**2
  468. PhysXVehicle& addAngVel (C Vec &ang_vel ); // add angular velocity , unit = rotation / time
  469. PhysXVehicle& addForce (C Vec &force ); // add force , unit = mass * distance / time**2
  470. PhysXVehicle& addForce (C Vec &force , C Vec &pos); // add force at world 'pos' position, unit = mass * distance / time**2
  471. PhysXVehicle& addImpulse(C Vec &impulse ); // add impulse , unit = mass * distance / time
  472. PhysXVehicle& addImpulse(C Vec &impulse, C Vec &pos); // add impulse at world 'pos' position, unit = mass * distance / time
  473. PhysXVehicle& addVel (C Vec &vel ); // add velocity , unit = distance / time
  474. PhysXVehicle& addAccel (C Vec &accel ); // add acceleration , unit = distance / time**2
  475. Bool ray ()C; PhysXVehicle& ray (Bool on ); // get/set if this actor should be included when performing ray tests
  476. Bool collision ()C; PhysXVehicle& collision (Bool on ); // get/set if this actor should collide with other actors in the world
  477. Bool sleep ()C; PhysXVehicle& sleep (Bool sleep ); // get/set sleeping
  478. Flt sleepEnergy()C; PhysXVehicle& sleepEnergy(Flt energy ); // get/set the amount of energy below the actor is put to sleep, default=0.005
  479. Bool ccd ()C; PhysXVehicle& ccd (Bool on ); // get/set continuous collision detection
  480. Ptr user ()C; PhysXVehicle& user (Ptr user ); // get/set custom user data
  481. Ptr obj ()C; PhysXVehicle& obj (Ptr obj ); // get/set pointer to object containing the actor
  482. Byte group ()C; PhysXVehicle& group (Byte group ); // get/set collision group (0..31, default value is taken according to ACTOR_GROUP)
  483. Byte dominance ()C; PhysXVehicle& dominance (Byte dominance); // get/set dominance index (0..31, default=0), for more information about dominance please check comments on 'Physics.dominance' method
  484. PhysMtrl* bodyMaterial()C; PhysXVehicle& bodyMaterial(PhysMtrl *material); // get/set physics material for vehicle body (use 'null' for default material)
  485. PhysMtrl* wheelMaterial()C; PhysXVehicle& wheelMaterial(PhysMtrl *material); // get/set physics material for vehicle wheels (use 'null' for default material)
  486. // operations
  487. PhysXVehicle& reset(); // this method will reset the engine, wheel and control state (acceleration, torque, forces, gear, etc.)
  488. PhysXVehicle& gearUp () {Int g=gear(); return gear((g<=0) ? 1 : g+1);} // set gear up (avoiding neutral gear)
  489. PhysXVehicle& gearDown() {Int g=gear(); return gear((g<=1) ? -1 : g-1);} // set gear down (avoiding neutral gear)
  490. ~PhysXVehicle() {del();}
  491. PhysXVehicle();
  492. #if !EE_PRIVATE
  493. private:
  494. #endif
  495. #if EE_PRIVATE
  496. PHYS_API(PxVehicleDrive4W, void) *_vehicle;
  497. #else
  498. Ptr _vehicle;
  499. #endif
  500. UInt _vehicle_id;
  501. Flt _scale;
  502. Actor _actor;
  503. NO_COPY_CONSTRUCTOR(PhysXVehicle);
  504. };
  505. /******************************************************************************
  506. PhysXVehicle:
  507. Wheel shapes have disabled collision (eSIMULATION_SHAPE)
  508. /******************************************************************************/
  509. using 'PhysXVehicle' requires calling 'PxInitVehicleSDK' in 'PhysxClass::create'
  510. PhysXVehicle::PhysXVehicle() {_vehicle=null; _vehicle_id=0; _scale=0;}
  511. PhysXVehicle& PhysXVehicle::create(C PhysBody &body, C Params &params, Flt scale)
  512. {
  513. if(!createTry(body, params, scale))Exit("Can't create PhysXVehicle"
  514. #if !PHYSX
  515. "\nThis class is only supported on PhysX"
  516. #endif
  517. );
  518. return T;
  519. }
  520. Flt PhysXVehicle::energy ( )C {return _actor.energy ( );}
  521. Flt PhysXVehicle::damping ( )C {return _actor.damping ( );} PhysXVehicle& PhysXVehicle:: damping( Flt damping) {_actor. damping(damping); return T;}
  522. Flt PhysXVehicle::adamping ( )C {return _actor.adamping ( );} PhysXVehicle& PhysXVehicle::adamping( Flt damping) {_actor.adamping(damping); return T;}
  523. Flt PhysXVehicle::mass ( )C {return _actor.mass ( );}
  524. Vec PhysXVehicle::massCenterL( )C {return _actor.massCenterL( );}
  525. Vec PhysXVehicle::massCenterW( )C {return _actor.massCenterW( );}
  526. Vec PhysXVehicle::inertia ( )C {return _actor.inertia ( );} PhysXVehicle& PhysXVehicle::inertia (C Vec &inertia) {_actor.inertia (inertia); return T;}
  527. Vec PhysXVehicle::pos ( )C {return _actor.pos ( );} PhysXVehicle& PhysXVehicle::pos (C Vec &pos ) {_actor.pos (pos ); return T;}
  528. Matrix3 PhysXVehicle::orn ( )C {return _actor.orn ( );} PhysXVehicle& PhysXVehicle::orn (C Matrix3 &orn ) {_actor.orn (orn ); return T;}
  529. Matrix PhysXVehicle::matrix ( )C {return _actor.matrix ( );} PhysXVehicle& PhysXVehicle::matrix (C Matrix &matrix ) {_actor.matrix (matrix ); return T;}
  530. Vec PhysXVehicle:: vel ( )C {return _actor. vel ( );} PhysXVehicle& PhysXVehicle:: vel (C Vec &vel ) {_actor. vel (vel ); return T;}
  531. Vec PhysXVehicle:: angVel ( )C {return _actor. angVel ( );} PhysXVehicle& PhysXVehicle::angVel (C Vec &vel ) {_actor.angVel (vel ); return T;}
  532. Vec PhysXVehicle::pointVelL (C Vec &pos)C {return _actor.pointVelL (pos);}
  533. Vec PhysXVehicle::pointVelW (C Vec &pos)C {return _actor.pointVelW (pos);}
  534. Box PhysXVehicle::box ( )C {return _actor.box ( );}
  535. PhysXVehicle& PhysXVehicle::addTorque (C Vec &torque ) {_actor.addTorque (torque ); return T;}
  536. PhysXVehicle& PhysXVehicle::addAngVel (C Vec &ang_vel ) {_actor.addAngVel (ang_vel ); return T;}
  537. PhysXVehicle& PhysXVehicle::addForce (C Vec &force ) {_actor.addForce (force ); return T;}
  538. PhysXVehicle& PhysXVehicle::addForce (C Vec &force , C Vec &pos) {_actor.addForce (force , pos); return T;}
  539. PhysXVehicle& PhysXVehicle::addImpulse(C Vec &impulse ) {_actor.addImpulse(impulse ); return T;}
  540. PhysXVehicle& PhysXVehicle::addImpulse(C Vec &impulse, C Vec &pos) {_actor.addImpulse(impulse, pos); return T;}
  541. PhysXVehicle& PhysXVehicle::addVel (C Vec &vel ) {_actor.addVel (vel ); return T;}
  542. PhysXVehicle& PhysXVehicle::addAccel (C Vec &accel ) {_actor.addAccel (accel ); return T;}
  543. Bool PhysXVehicle::collision ()C {return _actor.collision ();}
  544. Bool PhysXVehicle::ray ()C {return _actor.ray ();} PhysXVehicle& PhysXVehicle::ray (Bool on ) {_actor.ray (on ); return T;}
  545. Bool PhysXVehicle::sleep ()C {return _actor.sleep ();} PhysXVehicle& PhysXVehicle::sleep (Bool sleep ) {_actor.sleep (sleep ); return T;}
  546. Flt PhysXVehicle::sleepEnergy()C {return _actor.sleepEnergy();} PhysXVehicle& PhysXVehicle::sleepEnergy(Flt energy ) {_actor.sleepEnergy(energy ); return T;}
  547. Bool PhysXVehicle::ccd ()C {return _actor.ccd ();} PhysXVehicle& PhysXVehicle::ccd (Bool on ) {_actor.ccd (on ); return group(group());} // need to re-apply group because of 'eCCD_LINEAR' in 'SimulationFilterData' (also 'Actor.ccd' calls 'Actor.group' and that clears 'vehicle_id')
  548. Ptr PhysXVehicle::user ()C {return _actor.user ();} PhysXVehicle& PhysXVehicle::user (Ptr user ) {_actor.user (user ); return T;}
  549. Ptr PhysXVehicle::obj ()C {return _actor.obj ();} PhysXVehicle& PhysXVehicle::obj (Ptr obj ) {_actor.obj (obj ); return T;}
  550. Byte PhysXVehicle::dominance ()C {return _actor.dominance ();} PhysXVehicle& PhysXVehicle::dominance (Byte dominance) {_actor.dominance (dominance); return T;}
  551. Byte PhysXVehicle::group ()C {return _actor.group ();}
  552. /******************************************************************************/
  553. #if PHYSX
  554. ASSERT(WHEEL_LEFT_FRONT ==(Int)PxVehicleDrive4WWheelOrder::eFRONT_LEFT );
  555. ASSERT(WHEEL_RIGHT_FRONT==(Int)PxVehicleDrive4WWheelOrder::eFRONT_RIGHT);
  556. ASSERT(WHEEL_LEFT_REAR ==(Int)PxVehicleDrive4WWheelOrder::eREAR_LEFT );
  557. ASSERT(WHEEL_RIGHT_REAR ==(Int)PxVehicleDrive4WWheelOrder::eREAR_RIGHT );
  558. /******************************************************************************/
  559. static Int CompareVehicle(PxVehicleDrive4W*C &a, PxVehicleDrive4W*C &b) {return Compare(Ptr(a), Ptr(b));}
  560. PhysXVehicle& PhysXVehicle::del()
  561. {
  562. if(_vehicle)
  563. {
  564. SafeWriteLock lock(Physics._rws);
  565. if(_vehicle)
  566. {
  567. if(Physx.physics)_vehicle->free();
  568. Physx.vehicles.binaryExclude(_vehicle, CompareVehicle);
  569. _vehicle=null;
  570. if(_vehicle_id){Physx.vehicle_id_gen.Return(_vehicle_id); _vehicle_id=0;}
  571. }
  572. }
  573. _actor.del();
  574. return T;
  575. }
  576. Bool PhysXVehicle::createTry(C PhysBody &body, C Params &params, Flt scale)
  577. {
  578. WriteLock lock(Physics._rws); del();
  579. if(Physx.physics)
  580. if(_actor.createTry(body, 1, scale))
  581. if(_actor.isDynamic())
  582. if(_vehicle=PxVehicleDrive4W::allocate(WHEEL_NUM))
  583. if(PxVehicleWheelsSimData *wheels_sim_data=PxVehicleWheelsSimData::allocate(WHEEL_NUM)) // this must be manually released
  584. {
  585. // create ID (before calling other methods which rely on id)
  586. _vehicle_id=Physx.vehicle_id_gen.New();
  587. // get dimensions
  588. T._scale=scale;
  589. if(!body.box.size().any())ConstCast(body).setBox(); // if someone forgot to set phys box then recalculate it (can result in invalid vehicle behavior with zero box)
  590. Box body_box=body.box*scale; Vec body_dims=body_box.size();
  591. // create wheel shapes
  592. PxVehicleDriveSimData4W drive_sim_data;
  593. PxFilterData susp_fd(0, _vehicle_id, 0, 0);
  594. PxVehicleWheelData wheels [WHEEL_NUM];
  595. PxVec3 wheel_pos[WHEEL_NUM];
  596. FREP(WHEEL_NUM)
  597. {
  598. C Wheel &wheel=params.wheel[i];
  599. PxConvexMeshGeometry geom(Physx.wheel_mesh._pm->_convex, PxMeshScale(Physx.vec(Vec(wheel.width, wheel.radius, wheel.radius)*scale), PxQuat(PxIdentity)));
  600. Int actor_shapes=_actor._actor->getNbShapes();
  601. if(PxShape *shape=_actor._actor->createShape(geom, *Physics.mtrl_default._m))
  602. {
  603. shape->setLocalPose(Physx.matrix(wheel.pos*scale));
  604. wheels_sim_data->setWheelShapeMapping (i, actor_shapes);
  605. wheels_sim_data->setSceneQueryFilterData(i, susp_fd );
  606. }
  607. wheels[i].mRadius=wheel.radius*scale;
  608. wheels[i].mWidth =wheel.width *scale;
  609. wheels[i].mMass =params.wheel_mass; // *scale.x*scale.y*scale.z; don't scale
  610. wheels[i].mMOI =0.5f*wheels[i].mMass*Sqr(wheels[i].mRadius); // moment of inertia around the axle's axis (http://en.wikipedia.org/wiki/List_of_moments_of_inertia)
  611. wheel_pos[i]=Physx.vec(wheel.pos*scale);
  612. }
  613. // mass
  614. Flt mass=params.mass; // *scale.x*scale.y*scale.z; don't scale
  615. _actor.mass(mass);
  616. // moment of inertia (use the moment of inertia of a cuboid as an approximate value)
  617. Vec chassis_moi((body_dims.y*body_dims.y + body_dims.z*body_dims.z)*mass/12.0f,
  618. (body_dims.x*body_dims.x + body_dims.z*body_dims.z)*mass/12.0f,
  619. (body_dims.x*body_dims.x + body_dims.y*body_dims.y)*mass/12.0f);
  620. inertia(chassis_moi);
  621. // center of mass
  622. Vec mass_center_offset=params.mass_center_offset*scale,
  623. mass_center =_actor.massCenterL()+mass_center_offset;
  624. if(_actor._dynamic)_actor._dynamic->setCMassLocalPose(PxTransform(Physx.vec(mass_center))); // _actor.massCenterL(mass_center); (reset mass orientation as well because otherwise there was a case when rear wheels were placed below ground)
  625. // front/rear mass ratio
  626. // Work out the front/rear mass split from the cm offset.
  627. // This is a very approximate calculation with lots of assumptions.
  628. // mass_rear*zRear + mass_front*zFront = mass*cm (1)
  629. // mass_rear + mass_front = mass (2)
  630. // Rearrange (2)
  631. // mass_front = mass - mass_rear (3)
  632. // Substitute (3) into (1)
  633. // mass_rear(zRear - zFront) + mass*zFront = mass*cm (4)
  634. // Solve (4) for mass_rear
  635. // mass_rear = mass(cm - zFront)/(zRear-zFront) (5)
  636. // Now we also have
  637. // zFront = (z-cm)/2 (6a)
  638. // zRear = (-z-cm)/2 (6b)
  639. // Substituting (6a-b) into (5) gives
  640. // mass_rear = mass*0.5*(z-3cm)/z (7)
  641. Flt mass_rear =mass*Mid(0.5f*(body_dims.z-3*mass_center_offset.z)/body_dims.z, 0.1f, 0.9f),
  642. mass_front=mass-mass_rear;
  643. wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT ].mMaxSteer=PI_3;
  644. wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxSteer=PI_3;
  645. wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].mMaxSteer=0;
  646. wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT ].mMaxSteer=0;
  647. wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT ].mMaxBrakeTorque=1500;
  648. wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxBrakeTorque=1500;
  649. wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].mMaxBrakeTorque=1500;
  650. wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT ].mMaxBrakeTorque=1500;
  651. wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT ].mMaxHandBrakeTorque=0;
  652. wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxHandBrakeTorque=0;
  653. wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].mMaxHandBrakeTorque=4000;
  654. wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT ].mMaxHandBrakeTorque=4000;
  655. wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT ].mDampingRate=Physics.mtrl_default.adamping();
  656. wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mDampingRate=Physics.mtrl_default.adamping();
  657. wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].mDampingRate=Physics.mtrl_default.adamping();
  658. wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT ].mDampingRate=Physics.mtrl_default.adamping();
  659. // Let's set up the tire data structures now.
  660. PxVehicleTireData tires[WHEEL_NUM];
  661. // Let's set up the suspension data structures now.
  662. PxVehicleSuspensionData susps[WHEEL_NUM];
  663. REPA(susps)
  664. {
  665. susps[i].mSpringStrength =35000;
  666. susps[i].mSpringDamperRate=4500;
  667. susps[i].mMaxCompression =wheels[i].mRadius*0.75f;
  668. susps[i].mMaxDroop =wheels[i].mRadius*0.25f;
  669. }
  670. susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT ].mSprungMass=mass_front*0.5f;
  671. susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mSprungMass=mass_front*0.5f;
  672. susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].mSprungMass=mass_rear *0.5f;
  673. susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT ].mSprungMass=mass_rear *0.5f;
  674. // We need to set up geometry data for the suspension, wheels, and tires.
  675. // We already know the wheel centers described as offsets from the rigid body centre of mass.
  676. // From here we can approximate application points for the tire and suspension forces.
  677. // Lets assume that the suspension travel directions are absolutely vertical.
  678. // Also assume that we apply the tire and suspension forces 30cm below the centre of mass.
  679. PxVec3 wheelCentreCMOffsets[WHEEL_NUM];
  680. PxVec3 suspForceAppCMOffsets[WHEEL_NUM];
  681. PxVec3 tireForceAppCMOffsets[WHEEL_NUM];
  682. FREP(WHEEL_NUM)
  683. {
  684. wheelCentreCMOffsets[i]=wheel_pos[i]-Physx.vec(mass_center);
  685. suspForceAppCMOffsets[i]=PxVec3(wheelCentreCMOffsets[i].x, -0.3f, wheelCentreCMOffsets[i].z);
  686. tireForceAppCMOffsets[i]=PxVec3(wheelCentreCMOffsets[i].x, -0.3f, wheelCentreCMOffsets[i].z);
  687. }
  688. // Now add the wheel, tire and suspension data.
  689. FREP(WHEEL_NUM)
  690. {
  691. wheels_sim_data->setWheelData (i, wheels[i]);
  692. wheels_sim_data->setTireData (i, tires [i]);
  693. wheels_sim_data->setSuspensionData(i, susps [i]);
  694. wheels_sim_data->setSuspTravelDirection(i, PxVec3(0, -1, 0));
  695. wheels_sim_data->setWheelCentreOffset (i, wheelCentreCMOffsets[i]);
  696. wheels_sim_data->setSuspForceAppPointOffset(i, suspForceAppCMOffsets[i]);
  697. wheels_sim_data->setTireForceAppPointOffset(i, tireForceAppCMOffsets[i]);
  698. }
  699. // differential
  700. PxVehicleDifferential4WData diff;
  701. diff.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD;
  702. drive_sim_data.setDiffData(diff);
  703. // engine
  704. PxVehicleEngineData engine;
  705. engine.mPeakTorque=500;
  706. engine.mMaxOmega =600;
  707. drive_sim_data.setEngineData(engine);
  708. // gears
  709. PxVehicleGearsData gears;
  710. gears.mSwitchTime=0.5f;
  711. drive_sim_data.setGearsData(gears);
  712. // clutch
  713. PxVehicleClutchData clutch;
  714. clutch.mStrength=10.0f;
  715. drive_sim_data.setClutchData(clutch);
  716. // ackermann steering
  717. PxVehicleAckermannGeometryData ackermann;
  718. ackermann.mAccuracy =1.0f;
  719. ackermann.mAxleSeparation=wheel_pos[PxVehicleDrive4WWheelOrder::eFRONT_LEFT ].z-wheel_pos[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].z;
  720. ackermann.mFrontWidth =wheel_pos[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].x-wheel_pos[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].x;
  721. ackermann.mRearWidth =wheel_pos[PxVehicleDrive4WWheelOrder::eREAR_RIGHT ].x-wheel_pos[PxVehicleDrive4WWheelOrder::eREAR_LEFT ].x;
  722. drive_sim_data.setAckermannGeometryData(ackermann);
  723. _vehicle->setup(Physx.physics, _actor._dynamic, *wheels_sim_data, drive_sim_data, 0);
  724. wheels_sim_data->free();
  725. group(0).collision(true)._actor.materialForce(&Physics.mtrl_default); // set params after having all shapes and vehicle being initialized
  726. reset().autoGear(true);
  727. // once the vehicle is ready, add it to the global container
  728. Physx.vehicles.binaryInclude(_vehicle, CompareVehicle);
  729. return true;
  730. }
  731. del(); return false;
  732. }
  733. /******************************************************************************/
  734. PhysXVehicle& PhysXVehicle::reset()
  735. {
  736. if(_vehicle)
  737. {
  738. _vehicle->setToRestState();
  739. gear(1);
  740. }
  741. return T;
  742. }
  743. /******************************************************************************/
  744. Bool PhysXVehicle::onGround(WHEEL_TYPE wheel)C {return (_vehicle && InRange(wheel, _vehicle->wheel_query_result)) ? !_vehicle->wheel_query_result[wheel].isInAir : false;}
  745. Bool PhysXVehicle::onGround( )C {if(_vehicle)REPA(_vehicle->wheel_query_result)if(!_vehicle->wheel_query_result[i].isInAir)return true; return false;} // if any is not in air then return true (on ground)
  746. Vec PhysXVehicle::wheelPosL(WHEEL_TYPE wheel)C
  747. {
  748. if(_vehicle && _actor._actor && InRange(wheel, WHEEL_NUM))
  749. {
  750. Int shape_index=_vehicle->mWheelsSimData.getWheelShapeMapping(wheel);
  751. if(InRange(shape_index, _actor._actor->getNbShapes()))
  752. {
  753. PxShape *shape; if(_actor._actor->getShapes(&shape, 1, shape_index))
  754. {
  755. return Physx.vec(shape->getLocalPose().p);
  756. }
  757. }
  758. }
  759. return _actor.pos();
  760. }
  761. Matrix PhysXVehicle::wheelMatrix(WHEEL_TYPE wheel)C
  762. {
  763. if(_vehicle && _actor._actor && InRange(wheel, WHEEL_NUM))
  764. {
  765. Int shape_index=_vehicle->mWheelsSimData.getWheelShapeMapping(wheel);
  766. if(InRange(shape_index, _actor._actor->getNbShapes()))
  767. {
  768. PxShape *shape; if(_actor._actor->getShapes(&shape, 1, shape_index))
  769. {
  770. Matrix m=Physx.matrix(_actor._actor->getGlobalPose()*shape->getLocalPose());
  771. if(IsLeft(wheel))
  772. {
  773. m.x.chs();
  774. m.z.chs();
  775. }
  776. return m;
  777. }
  778. }
  779. }
  780. return _actor.matrix();
  781. }
  782. Vec PhysXVehicle::wheelVel (WHEEL_TYPE wheel)C {return _actor.pointVelL(wheelPosL(wheel));}
  783. Vec PhysXVehicle::wheelAngVel(WHEEL_TYPE wheel)C
  784. {
  785. if(_vehicle && InRange(wheel, WHEEL_NUM))
  786. {
  787. Vec dir=wheelMatrix(wheel).x; if(IsLeft(wheel))dir.chs();
  788. return dir*_vehicle->mWheelsDynData.getWheelRotationSpeed(wheel);
  789. }
  790. return 0;
  791. }
  792. Vec PhysXVehicle:: wheelContact (WHEEL_TYPE wheel)C {return (_vehicle && InRange(wheel, _vehicle->wheel_query_result)) ? Physx.vec(_vehicle->wheel_query_result [wheel].tireContactPoint) : 0;}
  793. Flt PhysXVehicle:: wheelRadius (WHEEL_TYPE wheel)C {return (_vehicle && InRange(wheel, _vehicle->wheel_query_result)) ? _vehicle->mWheelsSimData.getWheelData(wheel).mRadius : 0;}
  794. Flt PhysXVehicle:: wheelCompress(WHEEL_TYPE wheel)C {return (_vehicle && InRange(wheel, _vehicle->wheel_query_result)) ? _vehicle->wheel_query_result [wheel].suspJounce*_vehicle->mWheelsSimData.getSuspensionData(wheel).getRecipMaxCompression() : 0;}
  795. Flt PhysXVehicle:: wheelLongSlip(WHEEL_TYPE wheel)C {return (_vehicle && InRange(wheel, _vehicle->wheel_query_result)) ? _vehicle->wheel_query_result [wheel].longitudinalSlip : 0;}
  796. Flt PhysXVehicle:: wheelLatSlip (WHEEL_TYPE wheel)C {return (_vehicle && InRange(wheel, _vehicle->wheel_query_result)) ? _vehicle->wheel_query_result [wheel].lateralSlip : 0;}
  797. Flt PhysXVehicle:: speed()C {return _vehicle ? _vehicle->computeForwardSpeed () : 0;}
  798. Flt PhysXVehicle:: sideSpeed()C {return _vehicle ? _vehicle->computeSidewaysSpeed() : 0;}
  799. Flt PhysXVehicle:: engineSpeed()C {return _vehicle ? _vehicle-> mDriveDynData.mEnginespeed : 0;}
  800. Int PhysXVehicle:: gear()C {return _vehicle ? _vehicle-> mDriveDynData.getCurrentGear () -PxVehicleGearsData::eNEUTRAL : 0;}
  801. Int PhysXVehicle:: targetGear()C {return _vehicle ? _vehicle-> mDriveDynData.getTargetGear () -PxVehicleGearsData::eNEUTRAL : 0;}
  802. Int PhysXVehicle:: gears()C {return _vehicle ? _vehicle-> mDriveSimData.getGearsData ().mNbRatios-PxVehicleGearsData::eFIRST : 0;}
  803. Bool PhysXVehicle:: autoGear()C {return _vehicle ? _vehicle-> mDriveDynData.getUseAutoGears () : false;}
  804. Flt PhysXVehicle:: angle()C {return _vehicle ? _vehicle-> mDriveDynData.getAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT) : 0;}
  805. Flt PhysXVehicle:: maxAngle()C {return _vehicle ? _vehicle->mWheelsSimData.getWheelData (WHEEL_LEFT_FRONT).mMaxSteer : 0;}
  806. Flt PhysXVehicle:: maxBrake()C {return _vehicle ? _vehicle->mWheelsSimData.getWheelData (WHEEL_LEFT_REAR ).mMaxBrakeTorque : 0;}
  807. Flt PhysXVehicle:: maxHandBrake()C {return _vehicle ? _vehicle->mWheelsSimData.getWheelData (WHEEL_LEFT_REAR ).mMaxHandBrakeTorque : 0;}
  808. Flt PhysXVehicle:: wheelDamping()C {return _vehicle ? _vehicle->mWheelsSimData.getWheelData (WHEEL_LEFT_FRONT).mDampingRate : 0;}
  809. Flt PhysXVehicle:: suspSpring ()C {return _vehicle ? _vehicle->mWheelsSimData.getSuspensionData(WHEEL_LEFT_FRONT).mSpringStrength : 0;}
  810. Flt PhysXVehicle:: suspDamping ()C {return _vehicle ? _vehicle->mWheelsSimData.getSuspensionData(WHEEL_LEFT_FRONT).mSpringDamperRate : 0;}
  811. Flt PhysXVehicle:: suspCompress()C {return _vehicle ? _vehicle->mWheelsSimData.getSuspensionData(WHEEL_LEFT_FRONT).mMaxCompression/_vehicle->mWheelsSimData.getWheelData(WHEEL_LEFT_FRONT).mRadius : 0;}
  812. Flt PhysXVehicle:: suspElongate()C {return _vehicle ? _vehicle->mWheelsSimData.getSuspensionData(WHEEL_LEFT_FRONT).mMaxDroop /_vehicle->mWheelsSimData.getWheelData(WHEEL_LEFT_FRONT).mRadius : 0;}
  813. Flt PhysXVehicle::enginePeakTorque()C {return _vehicle ? _vehicle-> mDriveSimData.getEngineData ().mPeakTorque : 0;}
  814. Flt PhysXVehicle::engineMaxSpeed ()C {return _vehicle ? _vehicle-> mDriveSimData.getEngineData ().mMaxOmega : 0;}
  815. Int PhysXVehicle:: tireType()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData (WHEEL_LEFT_FRONT).mType : 0;}
  816. Flt PhysXVehicle:: accel()C {return _vehicle ? _vehicle-> mDriveDynData.getAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL ) : 0;}
  817. Flt PhysXVehicle:: brake()C {return _vehicle ? _vehicle-> mDriveDynData.getAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE ) : 0;}
  818. Flt PhysXVehicle:: handBrake()C {return _vehicle ? _vehicle-> mDriveDynData.getAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE ) : 0;}
  819. Flt PhysXVehicle::tireLongStiff ()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mLongitudinalStiffnessPerUnitGravity : 0;}
  820. Flt PhysXVehicle::tireLatStiffX ()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mLatStiffX : 0;}
  821. Flt PhysXVehicle::tireLatStiffY ()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mLatStiffY : 0;}
  822. Flt PhysXVehicle::tireCamberStiff()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mCamberStiffnessPerUnitGravity : 0;}
  823. Flt PhysXVehicle::tireFuncPoint0Fric()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mFrictionVsSlipGraph[0][1] : 0;}
  824. Flt PhysXVehicle::tireFuncPoint1Slip()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mFrictionVsSlipGraph[1][0] : 0;}
  825. Flt PhysXVehicle::tireFuncPoint1Fric()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mFrictionVsSlipGraph[1][1] : 0;}
  826. Flt PhysXVehicle::tireFuncPoint2Slip()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mFrictionVsSlipGraph[2][0] : 0;}
  827. Flt PhysXVehicle::tireFuncPoint2Fric()C {return _vehicle ? _vehicle->mWheelsSimData.getTireData(WHEEL_LEFT_FRONT).mFrictionVsSlipGraph[2][1] : 0;}
  828. PhysXVehicle& PhysXVehicle:: gear(Int gear ) {if(_vehicle)_vehicle->mDriveDynData.forceGearChange(Mid(gear+PxVehicleGearsData::eNEUTRAL, 0, gears()+PxVehicleGearsData::eNEUTRAL)); return T;}
  829. PhysXVehicle& PhysXVehicle::targetGear(Int gear ) {if(_vehicle)_vehicle->mDriveDynData.startGearChange(Mid(gear+PxVehicleGearsData::eNEUTRAL, 0, gears()+PxVehicleGearsData::eNEUTRAL)); return T;}
  830. PhysXVehicle& PhysXVehicle:: autoGear(Bool on ) {if(_vehicle)_vehicle->mDriveDynData.setUseAutoGears(on); return T;}
  831. PhysXVehicle& PhysXVehicle:: angle(Flt angle) {if(_vehicle)_vehicle->mDriveDynData.setAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT, Mid(angle, -1.0f, 1.0f)); return T;}
  832. PhysXVehicle& PhysXVehicle:: accel(Flt accel) {if(_vehicle)_vehicle->mDriveDynData.setAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL , Sat(accel )); return T;}
  833. PhysXVehicle& PhysXVehicle:: brake(Flt brake) {if(_vehicle)_vehicle->mDriveDynData.setAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE , Sat(brake )); return T;}
  834. PhysXVehicle& PhysXVehicle:: handBrake(Flt brake) {if(_vehicle)_vehicle->mDriveDynData.setAnalogInput (PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE , Sat(brake )); return T;}
  835. PhysXVehicle& PhysXVehicle::maxAngle(Flt angle)
  836. {
  837. if(_vehicle)
  838. {
  839. Clamp(angle, 0, PI_2);
  840. PxVehicleWheelData data=_vehicle->mWheelsSimData.getWheelData(WHEEL_LEFT_FRONT ); data.mMaxSteer=angle; _vehicle->mWheelsSimData.setWheelData(WHEEL_LEFT_FRONT , data);
  841. data=_vehicle->mWheelsSimData.getWheelData(WHEEL_RIGHT_FRONT); data.mMaxSteer=angle; _vehicle->mWheelsSimData.setWheelData(WHEEL_RIGHT_FRONT, data);
  842. }
  843. return T;
  844. }
  845. PhysXVehicle& PhysXVehicle::maxBrake(Flt brake)
  846. {
  847. if(_vehicle)
  848. {
  849. MAX(brake, 0);
  850. PxVehicleWheelData data=_vehicle->mWheelsSimData.getWheelData(WHEEL_LEFT_FRONT ); data.mMaxBrakeTorque=brake; _vehicle->mWheelsSimData.setWheelData(WHEEL_LEFT_FRONT , data);
  851. data=_vehicle->mWheelsSimData.getWheelData(WHEEL_RIGHT_FRONT); data.mMaxBrakeTorque=brake; _vehicle->mWheelsSimData.setWheelData(WHEEL_RIGHT_FRONT, data);
  852. data=_vehicle->mWheelsSimData.getWheelData(WHEEL_LEFT_REAR ); data.mMaxBrakeTorque=brake; _vehicle->mWheelsSimData.setWheelData(WHEEL_LEFT_REAR , data);
  853. data=_vehicle->mWheelsSimData.getWheelData(WHEEL_RIGHT_REAR ); data.mMaxBrakeTorque=brake; _vehicle->mWheelsSimData.setWheelData(WHEEL_RIGHT_REAR , data);
  854. }
  855. return T;
  856. }
  857. PhysXVehicle& PhysXVehicle::maxHandBrake(Flt brake)
  858. {
  859. if(_vehicle)
  860. {
  861. MAX(brake, 0);
  862. PxVehicleWheelData data=_vehicle->mWheelsSimData.getWheelData(WHEEL_LEFT_REAR ); data.mMaxHandBrakeTorque=brake; _vehicle->mWheelsSimData.setWheelData(WHEEL_LEFT_REAR , data);
  863. data=_vehicle->mWheelsSimData.getWheelData(WHEEL_RIGHT_REAR); data.mMaxHandBrakeTorque=brake; _vehicle->mWheelsSimData.setWheelData(WHEEL_RIGHT_REAR, data);
  864. }
  865. return T;
  866. }
  867. PhysXVehicle& PhysXVehicle::wheelDamping(Flt damping ) {if(_vehicle){MAX(damping, 0); REP(WHEEL_NUM){PxVehicleWheelData data=_vehicle->mWheelsSimData.getWheelData (i); data.mDampingRate =damping ; _vehicle->mWheelsSimData.setWheelData (i, data);}} return T;}
  868. PhysXVehicle& PhysXVehicle::suspSpring (Flt spring ) {if(_vehicle){MAX(spring , 0); REP(WHEEL_NUM){PxVehicleSuspensionData data=_vehicle->mWheelsSimData.getSuspensionData(i); data.mSpringStrength =spring ; _vehicle->mWheelsSimData.setSuspensionData(i, data);}} return T;}
  869. PhysXVehicle& PhysXVehicle::suspDamping (Flt damping ) {if(_vehicle){MAX(damping, 0); REP(WHEEL_NUM){PxVehicleSuspensionData data=_vehicle->mWheelsSimData.getSuspensionData(i); data.mSpringDamperRate=damping ; _vehicle->mWheelsSimData.setSuspensionData(i, data);}} return T;}
  870. PhysXVehicle& PhysXVehicle::suspCompress(Flt compress) {if(_vehicle){SAT(compress ); REP(WHEEL_NUM){PxVehicleSuspensionData data=_vehicle->mWheelsSimData.getSuspensionData(i); data.mMaxCompression =compress*_vehicle->mWheelsSimData.getWheelData(i).mRadius; _vehicle->mWheelsSimData.setSuspensionData(i, data);}} return T;}
  871. PhysXVehicle& PhysXVehicle::suspElongate(Flt elongate) {if(_vehicle){SAT(elongate ); REP(WHEEL_NUM){PxVehicleSuspensionData data=_vehicle->mWheelsSimData.getSuspensionData(i); data.mMaxDroop =elongate*_vehicle->mWheelsSimData.getWheelData(i).mRadius; _vehicle->mWheelsSimData.setSuspensionData(i, data);}} return T;}
  872. PhysXVehicle& PhysXVehicle::enginePeakTorque(Flt peak ) {if(_vehicle){MAX(peak , 0); PxVehicleEngineData data=_vehicle->mDriveSimData.getEngineData(); data.mPeakTorque=peak ; _vehicle->mDriveSimData.setEngineData(data);} return T;}
  873. PhysXVehicle& PhysXVehicle::engineMaxSpeed (Flt omega) {if(_vehicle){MAX(omega, 0); PxVehicleEngineData data=_vehicle->mDriveSimData.getEngineData(); data.mMaxOmega =omega; _vehicle->mDriveSimData.setEngineData(data);} return T;}
  874. PhysXVehicle& PhysXVehicle::tireType (Int type) {if(_vehicle) REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mType =type; _vehicle->mWheelsSimData.setTireData(i, data);} return T;}
  875. PhysXVehicle& PhysXVehicle::tireLongStiff (Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mLongitudinalStiffnessPerUnitGravity=f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  876. PhysXVehicle& PhysXVehicle::tireLatStiffX (Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mLatStiffX =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  877. PhysXVehicle& PhysXVehicle::tireLatStiffY (Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mLatStiffY =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  878. PhysXVehicle& PhysXVehicle::tireCamberStiff (Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mCamberStiffnessPerUnitGravity =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  879. PhysXVehicle& PhysXVehicle::tireFuncPoint0Fric(Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mFrictionVsSlipGraph[0][1] =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  880. PhysXVehicle& PhysXVehicle::tireFuncPoint1Slip(Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mFrictionVsSlipGraph[1][0] =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  881. PhysXVehicle& PhysXVehicle::tireFuncPoint1Fric(Flt f ) {if(_vehicle){MAX(f, EPS); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mFrictionVsSlipGraph[1][1] =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;} // without EPS crash may occur
  882. PhysXVehicle& PhysXVehicle::tireFuncPoint2Slip(Flt f ) {if(_vehicle){MAX(f, 0 ); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mFrictionVsSlipGraph[2][0] =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;}
  883. PhysXVehicle& PhysXVehicle::tireFuncPoint2Fric(Flt f ) {if(_vehicle){MAX(f, EPS); REP(WHEEL_NUM){PxVehicleTireData data=_vehicle->mWheelsSimData.getTireData(i); data.mFrictionVsSlipGraph[2][1] =f ; _vehicle->mWheelsSimData.setTireData(i, data);}} return T;} // without EPS crash may occur
  884. PhysXVehicle& PhysXVehicle::precision(Flt thresholdLongitudinalSpeed, UInt lowForwardSpeedSubStepCount, UInt highForwardSpeedSubStepCount)
  885. {
  886. if(_vehicle)_vehicle->mWheelsSimData.setSubStepCount(thresholdLongitudinalSpeed, lowForwardSpeedSubStepCount, highForwardSpeedSubStepCount);
  887. return T;
  888. }
  889. /******************************************************************************/
  890. PhysXVehicle& PhysXVehicle::group(Byte group)
  891. {
  892. if(_actor._actor && InRange(group, AG_NUM)) // must always apply group even if applying the same one, because '_ignore_id' or '_vehicle_id' could be different (and 'qfd' needs to be set)
  893. {
  894. PxFilterData sfd(group, _actor._ignore_id, ccd() ? PxPairFlag::eDETECT_CCD_CONTACT : 0, 0), qfd(IndexToFlag(group), _vehicle_id, 0, 0);
  895. for(Int offset=0, shapes=_actor._actor->getNbShapes(); shapes>0; )
  896. {
  897. PxShape *shape[32]; Int s=Min(shapes, Elms(shape));
  898. REP(_actor._actor->getShapes(shape, s, offset))
  899. {
  900. shape[i]->setSimulationFilterData(sfd);
  901. shape[i]->setQueryFilterData (qfd);
  902. }
  903. shapes-=s;
  904. offset+=s;
  905. }
  906. }
  907. return T;
  908. }
  909. PhysXVehicle& PhysXVehicle::collision(Bool on)
  910. {
  911. if(_actor._actor)
  912. {
  913. VecI4 wheel; if(_vehicle)wheel.set(_vehicle->mWheelsSimData.getWheelShapeMapping(0), _vehicle->mWheelsSimData.getWheelShapeMapping(1), _vehicle->mWheelsSimData.getWheelShapeMapping(2), _vehicle->mWheelsSimData.getWheelShapeMapping(3));else wheel=-1;
  914. for(Int offset=0, shapes=_actor._actor->getNbShapes(); shapes>0; )
  915. {
  916. PxShape *shape[32]; Int s=Min(shapes, Elms(shape));
  917. REP(_actor._actor->getShapes(shape, s, offset))
  918. {
  919. Bool shape_on=on;
  920. Int io=i+offset; if(io==wheel.x || io==wheel.y || io==wheel.z || io==wheel.w)shape_on=false; // always disable for wheels
  921. if(shape_on)shape[i]->setFlag(PxShapeFlag::eTRIGGER_SHAPE , false ); // if enabling collision, we need to first disable trigger, because PhysX will ignore setting collision flag
  922. shape[i]->setFlag(PxShapeFlag::eSIMULATION_SHAPE, shape_on);
  923. }
  924. shapes-=s;
  925. offset+=s;
  926. }
  927. }
  928. return T;
  929. }
  930. PhysMtrl* PhysXVehicle::bodyMaterial()C
  931. {
  932. if(_actor._actor)
  933. {
  934. Int shapes=_actor._actor->getNbShapes();
  935. FREP(shapes)
  936. {
  937. if(_vehicle)
  938. if(_vehicle->mWheelsSimData.getWheelShapeMapping(0)==i
  939. || _vehicle->mWheelsSimData.getWheelShapeMapping(1)==i
  940. || _vehicle->mWheelsSimData.getWheelShapeMapping(2)==i
  941. || _vehicle->mWheelsSimData.getWheelShapeMapping(3)==i)continue; // skip wheels
  942. PxShape *shape; if(_actor._actor->getShapes(&shape, 1, i))
  943. {
  944. PxMaterial *mtrl; if(shape->getMaterials(&mtrl, 1))if(mtrl)if(PhysMtrl *phys_mtrl=(PhysMtrl*)mtrl->userData)return (phys_mtrl!=&Physics.mtrl_default) ? phys_mtrl : null; // return default material always as null (we can use 'userData' because PhysMtrl's are stored in non-ref-counted cache and kept forever)
  945. }
  946. }
  947. }
  948. return null;
  949. }
  950. PhysMtrl* PhysXVehicle::wheelMaterial()C
  951. {
  952. if(_vehicle && _actor._actor)
  953. {
  954. Int shape_index=_vehicle->mWheelsSimData.getWheelShapeMapping(0);
  955. if(InRange(shape_index, _actor._actor->getNbShapes()))
  956. {
  957. PxShape *shape; if(_actor._actor->getShapes(&shape, 1, shape_index))
  958. {
  959. PxMaterial *mtrl; if(shape->getMaterials(&mtrl, 1))if(mtrl)if(PhysMtrl *phys_mtrl=(PhysMtrl*)mtrl->userData)if(phys_mtrl!=&Physics.mtrl_default)return phys_mtrl; // return default material always as null (we can use 'userData' because PhysMtrl's are stored in non-ref-counted cache and kept forever)
  960. }
  961. }
  962. }
  963. return null;
  964. }
  965. PhysXVehicle& PhysXVehicle::bodyMaterial(PhysMtrl *material)
  966. {
  967. if(_actor._actor)
  968. {
  969. if(!material)material=&Physics.mtrl_default; // always set valid material
  970. if(PxMaterial *m=material->_m)
  971. {
  972. VecI4 wheel; if(_vehicle)wheel.set(_vehicle->mWheelsSimData.getWheelShapeMapping(0), _vehicle->mWheelsSimData.getWheelShapeMapping(1), _vehicle->mWheelsSimData.getWheelShapeMapping(2), _vehicle->mWheelsSimData.getWheelShapeMapping(3));else wheel=-1;
  973. for(Int offset=0, shapes=_actor._actor->getNbShapes(); shapes>0; )
  974. {
  975. PxShape *shape[32]; Int s=Min(shapes, Elms(shape));
  976. REP(_actor._actor->getShapes(shape, s, offset))
  977. {
  978. Int io=i+offset; if(io!=wheel.x && io!=wheel.y && io!=wheel.z && io!=wheel.w)shape[i]->setMaterials(&m, 1); // skip wheels
  979. }
  980. shapes-=s;
  981. offset+=s;
  982. }
  983. }
  984. damping(material->damping()).adamping(material->adamping()); // don't adjust mass
  985. }
  986. return T;
  987. }
  988. PhysXVehicle& PhysXVehicle::wheelMaterial(PhysMtrl *material)
  989. {
  990. if(_vehicle && _actor._actor)
  991. {
  992. if(!material)material=&Physics.mtrl_default; // always set valid material
  993. if(PxMaterial *m=material->_m)
  994. {
  995. Int shapes =_actor._actor->getNbShapes();
  996. Int wheel[4]={_vehicle->mWheelsSimData.getWheelShapeMapping(0), _vehicle->mWheelsSimData.getWheelShapeMapping(1), _vehicle->mWheelsSimData.getWheelShapeMapping(2), _vehicle->mWheelsSimData.getWheelShapeMapping(3)};
  997. REPA(wheel)if(InRange(wheel[i], shapes))
  998. {
  999. PxShape *shape; if(_actor._actor->getShapes(&shape, 1, wheel[i]))shape->setMaterials(&m, 1);
  1000. }
  1001. }
  1002. wheelDamping(material->adamping());
  1003. }
  1004. return T;
  1005. }
  1006. PhysXVehicle::DIFF_TYPE PhysXVehicle::diffType()C
  1007. {
  1008. if(_vehicle)switch(_vehicle->mDriveSimData.getDiffData().mType)
  1009. {
  1010. case PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD : return DIFF_LS_4WD;
  1011. case PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD : return DIFF_LS_FWD;
  1012. case PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD : return DIFF_LS_RWD;
  1013. case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD : return DIFF_OPEN_4WD;
  1014. case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD: return DIFF_OPEN_FWD;
  1015. case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD : return DIFF_OPEN_RWD;
  1016. }
  1017. return DIFF_LS_4WD;
  1018. }
  1019. PhysXVehicle& PhysXVehicle::diffType(DIFF_TYPE diff)
  1020. {
  1021. if(_vehicle)
  1022. {
  1023. PxVehicleDifferential4WData data=_vehicle->mDriveSimData.getDiffData(); switch(diff)
  1024. {
  1025. case DIFF_LS_4WD : data.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD ; break;
  1026. case DIFF_LS_FWD : data.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD ; break;
  1027. case DIFF_LS_RWD : data.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD ; break;
  1028. case DIFF_OPEN_4WD: data.mType=PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD ; break;
  1029. case DIFF_OPEN_FWD: data.mType=PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD; break;
  1030. case DIFF_OPEN_RWD: data.mType=PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD ; break;
  1031. }
  1032. _vehicle->mDriveSimData.setDiffData(data);
  1033. }
  1034. return T;
  1035. }
  1036. /******************************************************************************/
  1037. static PxVehicleDrivableSurfaceToTireFrictionPairs vdsttfp;
  1038. void PhysxClass::updateVehicles()
  1039. {
  1040. REPA(vehicles)
  1041. {
  1042. PxVehicleDrive4W *vehicle=vehicles[i];
  1043. PxVehicleWheels *vehicle_wheels[1]={vehicles[i]};
  1044. PxVehicleWheelQueryResult wqr; wqr.wheelQueryResults=vehicle->wheel_query_result; wqr.nbWheelQueryResults=Elms(vehicle->wheel_query_result);
  1045. PxVehicleSuspensionRaycasts(batch_query_4, Elms(vehicle_wheels), vehicle_wheels, Elms(raycast_query_result), raycast_query_result);
  1046. PxVehicleUpdates (Physics.time(), vec(Physics.gravity()), vdsttfp, Elms(vehicle_wheels), vehicle_wheels, &wqr);
  1047. }
  1048. }
  1049. /******************************************************************************/
  1050. #else
  1051. /******************************************************************************/
  1052. PhysXVehicle& PhysXVehicle::del() {return T;}
  1053. Bool PhysXVehicle::createTry(C PhysBody &body, C Params &params, Flt scale) {return false;}
  1054. PhysXVehicle& PhysXVehicle::reset() {return T;}
  1055. Bool PhysXVehicle::onGround( )C {return false;}
  1056. Bool PhysXVehicle::onGround(WHEEL_TYPE wheel)C {return false;}
  1057. Vec PhysXVehicle:: wheelPosL (WHEEL_TYPE wheel)C {return 0;}
  1058. Matrix PhysXVehicle:: wheelMatrix (WHEEL_TYPE wheel)C {return MatrixIdentity;}
  1059. Vec PhysXVehicle:: wheelVel (WHEEL_TYPE wheel)C {return 0;}
  1060. Vec PhysXVehicle:: wheelAngVel (WHEEL_TYPE wheel)C {return 0;}
  1061. Vec PhysXVehicle:: wheelContact (WHEEL_TYPE wheel)C {return 0;}
  1062. Flt PhysXVehicle:: wheelRadius (WHEEL_TYPE wheel)C {return 0;}
  1063. Flt PhysXVehicle:: wheelCompress(WHEEL_TYPE wheel)C {return 0;}
  1064. Flt PhysXVehicle:: wheelLatSlip (WHEEL_TYPE wheel)C {return 0;}
  1065. Flt PhysXVehicle:: wheelLongSlip(WHEEL_TYPE wheel)C {return 0;}
  1066. Flt PhysXVehicle:: speed()C {return 0;}
  1067. Flt PhysXVehicle:: sideSpeed()C {return 0;}
  1068. Flt PhysXVehicle:: engineSpeed()C {return 0;}
  1069. Int PhysXVehicle:: gear()C {return 0;}
  1070. Int PhysXVehicle:: targetGear()C {return 0;}
  1071. Int PhysXVehicle:: gears()C {return 0;}
  1072. Bool PhysXVehicle:: autoGear()C {return false;}
  1073. Flt PhysXVehicle:: angle()C {return 0;}
  1074. Flt PhysXVehicle:: maxAngle()C {return 0;}
  1075. Flt PhysXVehicle:: maxBrake()C {return 0;}
  1076. Flt PhysXVehicle:: maxHandBrake()C {return 0;}
  1077. Flt PhysXVehicle:: wheelDamping()C {return 0;}
  1078. Flt PhysXVehicle:: suspSpring ()C {return 0;}
  1079. Flt PhysXVehicle:: suspDamping ()C {return 0;}
  1080. Flt PhysXVehicle:: suspCompress()C {return 0;}
  1081. Flt PhysXVehicle:: suspElongate()C {return 0;}
  1082. Flt PhysXVehicle::enginePeakTorque()C {return 0;}
  1083. Flt PhysXVehicle::engineMaxSpeed ()C {return 0;}
  1084. Int PhysXVehicle:: tireType()C {return 0;}
  1085. Flt PhysXVehicle:: accel()C {return 0;}
  1086. Flt PhysXVehicle:: brake()C {return 0;}
  1087. Flt PhysXVehicle:: handBrake()C {return 0;}
  1088. PhysMtrl* PhysXVehicle:: bodyMaterial()C {return null;}
  1089. PhysMtrl* PhysXVehicle::wheelMaterial()C {return null;}
  1090. PhysXVehicle::DIFF_TYPE PhysXVehicle::diffType()C {return DIFF_LS_4WD;}
  1091. Flt PhysXVehicle::tireLatStiffX ()C {return 0;}
  1092. Flt PhysXVehicle::tireLatStiffY ()C {return 0;}
  1093. Flt PhysXVehicle::tireLongStiff ()C {return 0;}
  1094. Flt PhysXVehicle::tireCamberStiff()C {return 0;}
  1095. Flt PhysXVehicle::tireFuncPoint0Fric()C {return 0;}
  1096. Flt PhysXVehicle::tireFuncPoint1Slip()C {return 0;}
  1097. Flt PhysXVehicle::tireFuncPoint1Fric()C {return 0;}
  1098. Flt PhysXVehicle::tireFuncPoint2Slip()C {return 0;}
  1099. Flt PhysXVehicle::tireFuncPoint2Fric()C {return 0;}
  1100. PhysXVehicle& PhysXVehicle:: gear(Int gear ) {return T;}
  1101. PhysXVehicle& PhysXVehicle:: targetGear(Int gear ) {return T;}
  1102. PhysXVehicle& PhysXVehicle:: autoGear(Bool on ) {return T;}
  1103. PhysXVehicle& PhysXVehicle:: angle(Flt angle ) {return T;}
  1104. PhysXVehicle& PhysXVehicle:: accel(Flt accel ) {return T;}
  1105. PhysXVehicle& PhysXVehicle:: brake(Flt brake ) {return T;}
  1106. PhysXVehicle& PhysXVehicle:: handBrake(Flt brake ) {return T;}
  1107. PhysXVehicle& PhysXVehicle:: maxAngle(Flt angle ) {return T;}
  1108. PhysXVehicle& PhysXVehicle:: maxBrake(Flt brake ) {return T;}
  1109. PhysXVehicle& PhysXVehicle:: maxHandBrake(Flt brake ) {return T;}
  1110. PhysXVehicle& PhysXVehicle:: wheelDamping(Flt damping ) {return T;}
  1111. PhysXVehicle& PhysXVehicle:: suspSpring (Flt spring ) {return T;}
  1112. PhysXVehicle& PhysXVehicle:: suspDamping (Flt damping ) {return T;}
  1113. PhysXVehicle& PhysXVehicle:: suspCompress(Flt compress) {return T;}
  1114. PhysXVehicle& PhysXVehicle:: suspElongate(Flt elongate) {return T;}
  1115. PhysXVehicle& PhysXVehicle::enginePeakTorque(Flt peak ) {return T;}
  1116. PhysXVehicle& PhysXVehicle::engineMaxSpeed (Flt omega ) {return T;}
  1117. PhysXVehicle& PhysXVehicle:: tireType(Int type ) {return T;}
  1118. PhysXVehicle& PhysXVehicle:: diffType(DIFF_TYPE diff) {return T;}
  1119. PhysXVehicle& PhysXVehicle::group (Byte group) {return T;}
  1120. PhysXVehicle& PhysXVehicle::collision(Bool on ) {return T;}
  1121. PhysXVehicle& PhysXVehicle:: bodyMaterial(PhysMtrl *material) {return T;}
  1122. PhysXVehicle& PhysXVehicle::wheelMaterial(PhysMtrl *material) {return T;}
  1123. PhysXVehicle& PhysXVehicle::tireLatStiffX (Flt f) {return T;}
  1124. PhysXVehicle& PhysXVehicle::tireLatStiffY (Flt f) {return T;}
  1125. PhysXVehicle& PhysXVehicle::tireLongStiff (Flt f) {return T;}
  1126. PhysXVehicle& PhysXVehicle::tireCamberStiff(Flt f) {return T;}
  1127. PhysXVehicle& PhysXVehicle::tireFuncPoint0Fric(Flt f) {return T;}
  1128. PhysXVehicle& PhysXVehicle::tireFuncPoint1Slip(Flt f) {return T;}
  1129. PhysXVehicle& PhysXVehicle::tireFuncPoint1Fric(Flt f) {return T;}
  1130. PhysXVehicle& PhysXVehicle::tireFuncPoint2Slip(Flt f) {return T;}
  1131. PhysXVehicle& PhysXVehicle::tireFuncPoint2Fric(Flt f) {return T;}
  1132. PhysXVehicle& PhysXVehicle::precision(Flt thresholdLongitudinalSpeed, UInt lowForwardSpeedSubStepCount, UInt highForwardSpeedSubStepCount) {return T;}
  1133. /******************************************************************************/
  1134. #endif
  1135. /******************************************************************************/
  1136. // PHYSX VEHICLE TUTORIAL
  1137. /******************************************************************************/
  1138. const bool EasyReverse=true; // if use simplified reversing (will automatically switch between reverse<->forward gears)
  1139. Memc<Actor> actors;
  1140. PhysXVehicle vehicle;
  1141. /******************************************************************************/
  1142. flt WheelFriction(C PhysMtrl &ground_material, C PhysMtrl &wheel_material, C ActorInfo &vehicle, WHEEL_TYPE wheel)
  1143. {
  1144. return 1;
  1145. }
  1146. void InitPre()
  1147. {
  1148. EE_INIT();
  1149. App.flag=APP_RESIZABLE|APP_MINIMIZABLE|APP_MAXIMIZABLE|APP_WORK_IN_BACKGROUND|APP_FULL_TOGGLE;
  1150. #ifdef DEBUG
  1151. App.flag|=APP_MEM_LEAKS|APP_BREAKPOINT_ON_ERROR;
  1152. #endif
  1153. Cam.dist=10;
  1154. Cam.pitch=-0.4;
  1155. D.viewFov(DegToRad(60)).mode(App.desktopW()*0.8, App.desktopH()*0.8);
  1156. }
  1157. /******************************************************************************/
  1158. bool Init()
  1159. {
  1160. Physics.create(EE_PHYSX_DLL_PATH).wheelFriction(WheelFriction); // create physics and set custom friction calculation callback
  1161. actors.New().create(Plane(Vec(0, -1, 0), Vec(0, 1, 0))); // create ground
  1162. PhysXVehicle.Params params; // setup vehicle params
  1163. flt x=0.9, y=-0.5, z=1.8;
  1164. params.wheel[WHEEL_LEFT_FRONT ].pos.set(-x, y, z);
  1165. params.wheel[WHEEL_RIGHT_FRONT].pos.set( x, y, z);
  1166. params.wheel[WHEEL_LEFT_REAR ].pos.set(-x, y, -z);
  1167. params.wheel[WHEEL_RIGHT_REAR ].pos.set( x, y, -z);
  1168. PhysBody body; body.parts.New().create(Box(2, 1, 4)); body.setBox(); // create vehicle body
  1169. vehicle.create(body, params, 1); // create vehicle
  1170. return true;
  1171. }
  1172. /******************************************************************************/
  1173. void Shut()
  1174. {
  1175. }
  1176. /******************************************************************************/
  1177. bool Update()
  1178. {
  1179. if(Kb.bp(KB_ESC))return false;
  1180. Physics.startSimulation().stopSimulation(); // update physics
  1181. // set vehicle input
  1182. flt forward=Kb.b(KB_W),
  1183. back =Kb.b(KB_S),
  1184. angle =Kb.b(KB_D)-Kb.b(KB_A),
  1185. hand =Kb.b(KB_SPACE);
  1186. // adjust gears when reversing
  1187. if(EasyReverse)
  1188. {
  1189. if(back >forward+EPS && vehicle.speed()<=0.5)vehicle.gear(-1); // set reverse gear when 'back ' exceeds 'forward' and moving very slow
  1190. if(forward>back +EPS && vehicle.gear ()<=0 )vehicle.gear( 1); // set 1st gear when 'forward' exceeds 'back ' and gear is reverse or neutral
  1191. if(vehicle.gear()<0)Swap(forward, back);
  1192. }
  1193. vehicle.accel(forward).brake(back).angle(angle).handBrake(hand);
  1194. // manual gear change
  1195. if(Kb.bp(KB_R))vehicle.gearUp ();
  1196. if(Kb.bp(KB_F))vehicle.gearDown();
  1197. if(Kb.bp(KB_Z))vehicle.matrix(MatrixIdentity).vel(0).angVel(0);
  1198. /* sample code for changing gears depending on engine speed (for this code you should disable 'autoGear')
  1199. if(vehicle.gear()>0)
  1200. {
  1201. flt frac=vehicle.engineFrac();
  1202. if( frac>=0.70f )vehicle.gearUp ();else
  1203. if( frac< 0.50f && vehicle.gear()>1)vehicle.gearDown();
  1204. }*/
  1205. // setup camera
  1206. Cam.at =vehicle.pos();
  1207. Cam.yaw=Angle(vehicle.matrix().z.xz())-PI_2;
  1208. Cam.setSpherical().updateVelocities(CAM_ATTACH_ACTOR).set();
  1209. return true;
  1210. }
  1211. /******************************************************************************/
  1212. void Draw()
  1213. {
  1214. D.clear(TURQ);
  1215. Physics.draw();
  1216. }
  1217. /******************************************************************************/
  1218. #endif
  1219. /******************************************************************************/
  1220. }
  1221. /******************************************************************************/