car.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #define S3L_NEAR_CROSS_STRATEGY 2
  2. #define S3L_PERSPECTIVE_CORRECTION 2
  3. #include "helper.h"
  4. #include "carArenaModel.h"
  5. #include "carModel.h"
  6. #define ACCELERATION (TPE_F / 14)
  7. #define TURN_RATE (3 * TPE_F / 4)
  8. #define TURN_FRICTION (3 * TPE_F / 4) // wheel side friction
  9. #define FORW_FRICTION (TPE_F / 14) // wheel forward friction
  10. TPE_Unit rampPoits[6] = { 0,0, -2400,1400, -2400,0 };
  11. TPE_Vec3 environmentDistance(TPE_Vec3 p, TPE_Unit maxD)
  12. {
  13. TPE_ENV_START( TPE_envGround(p,0),p )
  14. TPE_ENV_NEXT( TPE_envSphereInside(p,TPE_vec3(0,10000,0),20000),p )
  15. TPE_ENV_NEXT( TPE_envAABox(p,TPE_vec3(-8700,100,-800),TPE_vec3(2200,1000,800)),p )
  16. TPE_ENV_NEXT( TPE_envAATriPrism(p,TPE_vec3(8700,0,0),rampPoits,5000,2),p )
  17. TPE_ENV_NEXT( TPE_envSphere(p,TPE_vec3(0,-200,0),1700),p )
  18. TPE_ENV_END
  19. }
  20. uint8_t steering = 0; // 0: none, 1: right, 2: left
  21. uint8_t jointCollisions; /* bit mask of colliding joints (i.e. wheels that are
  22. currently touching the ground). */
  23. uint8_t jointCollisionsPrev; // for averaging
  24. TPE_Body *carBody;
  25. TPE_Vec3 carForw, carSide, carUp, carPos, carRot;
  26. uint8_t collisionCallback(uint16_t b1, uint16_t j1, uint16_t b2, uint16_t j2,
  27. TPE_Vec3 p)
  28. {
  29. // here we record which wheels (joints) are currently touching the ground
  30. if (b1 == 1 && b1 == b2 && j1 < 4)
  31. jointCollisions |= 0x01 << j1;
  32. return 1;
  33. }
  34. int main(void)
  35. {
  36. arenaModelInit();
  37. carModelInit();
  38. helper_init();
  39. carPos = TPE_vec3(0,0,0);
  40. tpe_world.environmentFunction = environmentDistance;
  41. tpe_world.collisionCallback = collisionCallback;
  42. // add an interactive body:
  43. helper_addRect(6 * TPE_F / 5,6 * TPE_F / 5,6 * TPE_F / 5,TPE_F / 2);
  44. TPE_bodyMoveBy(&helper_lastBody,TPE_vec3(2000,1000,3000));
  45. helper_lastBody.friction = TPE_F / 5;
  46. // create the car body, start with a "center rect":
  47. helper_addCenterRectFull(1000,1800,400,2000);
  48. carBody = &helper_lastBody;
  49. // scale and shift the middle joint a bit
  50. carBody->joints[4].position.y += 600;
  51. carBody->joints[4].sizeDivided *= 3;
  52. carBody->joints[4].sizeDivided /= 2;
  53. // we need to reinit the body so that it recomputes its connection lengths
  54. TPE_bodyInit(carBody,carBody->joints,carBody->jointCount,carBody->connections,
  55. carBody->connectionCount,TPE_F / 2);
  56. TPE_bodyMoveBy(carBody,TPE_vec3(6 * TPE_F,2 * TPE_F,0));
  57. carBody->elasticity = TPE_F / 100;
  58. carBody->friction = FORW_FRICTION;
  59. carBody->flags |= TPE_BODY_FLAG_ALWAYS_ACTIVE;
  60. s3l_scene.camera.transform.rotation.x = -35;
  61. while (helper_running)
  62. {
  63. helper_frameStart();
  64. jointCollisions = 0;
  65. if (sdl_keyboard[SDL_SCANCODE_RIGHT])
  66. steering = 1;
  67. else if (sdl_keyboard[SDL_SCANCODE_LEFT])
  68. steering = 2;
  69. else
  70. steering = 0;
  71. TPE_worldStep(&tpe_world);
  72. // get and smooth the car position:
  73. carPos = TPE_vec3KeepWithinBox(carPos,carBody->joints[4].position,
  74. TPE_vec3(TPE_F / 50,TPE_F / 50,TPE_F / 50));
  75. // compute the car direction vectors from positions of its joints:
  76. carForw = TPE_vec3Normalized(TPE_vec3Plus(
  77. TPE_vec3Minus(carBody->joints[2].position,carBody->joints[0].position),
  78. TPE_vec3Minus(carBody->joints[3].position,carBody->joints[1].position)));
  79. carSide = TPE_vec3Normalized(TPE_vec3Plus(
  80. TPE_vec3Minus(carBody->joints[1].position,carBody->joints[0].position),
  81. TPE_vec3Minus(carBody->joints[3].position,carBody->joints[2].position)));
  82. carUp = TPE_vec3Cross(carForw,carSide);
  83. /* now we'll check each joint separately and if it is touching the ground,
  84. we apply directional friction (friction that's dependent on the direction
  85. of the wheel which e.g. allows turning); TPE has only non-directional
  86. friction programmed in so we do it ourselves */
  87. for (int i = 0; i < 4; ++i)
  88. if (jointCollisions & (0x01 << i)) // wheel touches the ground?
  89. {
  90. TPE_Vec3 jv = TPE_vec3( // joint velocity
  91. carBody->joints[i].velocity[0],
  92. carBody->joints[i].velocity[1],
  93. carBody->joints[i].velocity[2]);
  94. TPE_Vec3 ja = carSide; // wheel axis of rotation
  95. if (i >= 2 && steering)
  96. {
  97. // for front wheels with turning we tilt the wheel axis 45 degrees
  98. if (steering == 2)
  99. ja = TPE_vec3Plus(TPE_vec3Times(carForw,TURN_RATE),carSide);
  100. else
  101. ja = TPE_vec3Minus(TPE_vec3Times(carForw,TURN_RATE),carSide);
  102. ja = TPE_vec3Normalized(ja);
  103. }
  104. /* friction is in the direction if the axis and its magnitude is
  105. determined by the dot product (angle) of the axis and velocity */
  106. TPE_Vec3 fric = TPE_vec3Times(ja,(TPE_vec3Dot(ja,jv) * TURN_FRICTION)
  107. / TPE_F);
  108. jv = TPE_vec3Minus(jv,fric); // subtract the friction
  109. carBody->joints[i].velocity[0] = jv.x;
  110. carBody->joints[i].velocity[1] = jv.y;
  111. carBody->joints[i].velocity[2] = jv.z;
  112. }
  113. if (TPE_vec3Dot(carUp,TPE_vec3Minus(carBody->joints[4].position,
  114. carBody->joints[0].position)) < 0)
  115. {
  116. /* if the car falls on its roof the center joint may flip to the other
  117. side, here we fix it */
  118. puts("car geometry flipped over, fixing...");
  119. carBody->joints[4].position = TPE_vec3Plus(TPE_vec3Times(carUp,300),
  120. carBody->joints[0].position);
  121. }
  122. for (int i = 0; i < tpe_world.bodyCount; ++i)
  123. TPE_bodyApplyGravity(&tpe_world.bodies[i],5);
  124. if ((jointCollisions | jointCollisionsPrev) & 0x03) // back wheels on ground?
  125. {
  126. if (sdl_keyboard[SDL_SCANCODE_UP])
  127. {
  128. carBody->joints[0].velocity[0] += (carForw.x * ACCELERATION) / TPE_F;
  129. carBody->joints[0].velocity[1] += (carForw.y * ACCELERATION) / TPE_F;
  130. carBody->joints[0].velocity[2] += (carForw.z * ACCELERATION) / TPE_F;
  131. carBody->joints[1].velocity[0] += (carForw.x * ACCELERATION) / TPE_F;
  132. carBody->joints[1].velocity[1] += (carForw.y * ACCELERATION) / TPE_F;
  133. carBody->joints[1].velocity[2] += (carForw.z * ACCELERATION) / TPE_F;
  134. }
  135. else if (sdl_keyboard[SDL_SCANCODE_DOWN])
  136. {
  137. carBody->joints[0].velocity[0] -= (carForw.x * ACCELERATION) / TPE_F;
  138. carBody->joints[0].velocity[1] -= (carForw.y * ACCELERATION) / TPE_F;
  139. carBody->joints[0].velocity[2] -= (carForw.z * ACCELERATION) / TPE_F;
  140. carBody->joints[1].velocity[0] -= (carForw.x * ACCELERATION) / TPE_F;
  141. carBody->joints[1].velocity[1] -= (carForw.y * ACCELERATION) / TPE_F;
  142. carBody->joints[1].velocity[2] -= (carForw.z * ACCELERATION) / TPE_F;
  143. }
  144. }
  145. jointCollisionsPrev = jointCollisions;
  146. carRot = TPE_bodyGetRotation(carBody,0,2,1);
  147. // draw:
  148. helper_set3DColor(20,150,150);
  149. helper_drawModel(&arenaModel,TPE_vec3(0,0,0),TPE_vec3(512 * 32,512 * 32,512 * 32),
  150. TPE_vec3(0,0,0));
  151. helper_set3DColor(20,50,250);
  152. helper_draw3DBox(TPE_bodyGetCenterOfMass(&tpe_world.bodies[0]),
  153. TPE_vec3(1000,800,1000),TPE_bodyGetRotation(&tpe_world.bodies[0],0,2,1));
  154. S3L_zBufferClear();
  155. helper_set3DColor(200,200,200);
  156. helper_drawModel(&carModel,TPE_vec3Minus(carPos,TPE_vec3Times(carUp,400)),
  157. TPE_vec3(600,600,600),carRot);
  158. if (helper_debugDrawOn)
  159. helper_debugDraw(1);
  160. // handle camera:
  161. s3l_scene.camera.transform.translation.y = carPos.y + 800;
  162. TPE_Vec3 cPos = TPE_vec3KeepWithinDistanceBand(
  163. TPE_vec3(
  164. s3l_scene.camera.transform.translation.x,
  165. s3l_scene.camera.transform.translation.y,
  166. s3l_scene.camera.transform.translation.z
  167. ),carBody->joints[4].position,4 * TPE_F,6 * TPE_F);
  168. s3l_scene.camera.transform.translation.x = cPos.x;
  169. s3l_scene.camera.transform.translation.y = cPos.y;
  170. s3l_scene.camera.transform.translation.z = cPos.z;
  171. S3L_Vec4 toCar;
  172. toCar.x = carPos.x - s3l_scene.camera.transform.translation.x;
  173. toCar.y = carPos.y - s3l_scene.camera.transform.translation.y;
  174. toCar.z = carPos.z - s3l_scene.camera.transform.translation.z;
  175. toCar.w = 0;
  176. TPE_Unit angleDiff = s3l_scene.camera.transform.rotation.y -
  177. (TPE_vec2Angle(toCar.x,toCar.z) - 128);
  178. s3l_scene.camera.transform.rotation.y -=
  179. (angleDiff < 100 && angleDiff > -100) ? angleDiff / 2 : angleDiff;
  180. helper_frameEnd();
  181. }
  182. helper_end();
  183. return 0;
  184. }